source: trunk/GSASIIphsGUI.py @ 984

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

update Win2.7 g77 binaries
cov matrix now not modified by lam
no label plotting at all - fails
set MC/SA page after mc/sa run
fix 64 bit bug in switching to map peaks page

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 245.6 KB
Line 
1# -*- coding: utf-8 -*-
2#GSASII - phase data display routines
3########### SVN repository information ###################
4# $Date: 2013-07-08 12:30:27 +0000 (Mon, 08 Jul 2013) $
5# $Author: vondreele $
6# $Revision: 984 $
7# $URL: trunk/GSASIIphsGUI.py $
8# $Id: GSASIIphsGUI.py 984 2013-07-08 12:30:27Z 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: 984 $")
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           
3193        def ThermDataSizer(RBObj):
3194           
3195            def OnThermval(event):
3196                Obj = event.GetEventObject()
3197                item = Indx[Obj.GetId()]
3198                try:
3199                    val = float(Obj.GetValue())
3200                    RBObj['ThermalMotion'][1][item] = val
3201                except ValueError:
3202                    pass
3203                Obj.SetValue('%8.4f'%(RBObj['ThermalMotion'][1][item]))
3204                G2plt.PlotStructure(G2frame,data)
3205               
3206            def OnTLSRef(event):
3207                Obj = event.GetEventObject()
3208                item = Indx[Obj.GetId()]
3209                RBObj['ThermalMotion'][2][item] = Obj.GetValue()
3210           
3211            thermSizer = wx.FlexGridSizer(1,9,5,5)
3212            model = RBObj['ThermalMotion']
3213            if model[0] == 'Uiso':
3214                names = ['Uiso',]
3215            elif 'T' in model[0]:
3216                names = ['T11','T22','T33','T12','T13','T23']
3217            if 'L' in model[0]:
3218                names += ['L11','L22','L33','L12','L13','L23']
3219            if 'S' in model[0]:
3220                names += ['S12','S13','S21','S23','S31','S32','SAA','SBB']
3221            for i,name in enumerate(names):
3222                thermSizer.Add(wx.StaticText(RigidBodies,-1,name+': '),0,wx.ALIGN_CENTER_VERTICAL)
3223                thermVal = wx.TextCtrl(RigidBodies,-1,value='%8.4f'%(model[1][i]),
3224                    style=wx.TE_PROCESS_ENTER)
3225                thermVal.Bind(wx.EVT_TEXT_ENTER,OnThermval)
3226                thermVal.Bind(wx.EVT_KILL_FOCUS,OnThermval)
3227                Indx[thermVal.GetId()] = i
3228                thermSizer.Add(thermVal)
3229                Tcheck = wx.CheckBox(RigidBodies,-1,'Refine?')
3230                Tcheck.Bind(wx.EVT_CHECKBOX,OnTLSRef)
3231                Tcheck.SetValue(model[2][i])
3232                Indx[Tcheck.GetId()] = i
3233                thermSizer.Add(Tcheck,0,wx.ALIGN_CENTER_VERTICAL)
3234            return thermSizer
3235           
3236        def LocationSizer(RBObj,rbType):
3237           
3238            def OnOrigRef(event):
3239                RBObj['Orig'][1] = Ocheck.GetValue()
3240             
3241            def OnOrienRef(event):
3242                RBObj['Orient'][1] = Qcheck.GetValue()
3243               
3244            def OnOrigX(event):
3245                Obj = event.GetEventObject()
3246                item = Indx[Obj.GetId()]
3247                try:
3248                    val = float(Obj.GetValue())
3249                    RBObj['Orig'][0][item] = val
3250                    Obj.SetValue('%8.5f'%(val))
3251                    newXYZ = G2mth.UpdateRBXYZ(Bmat,RBObj,RBData,rbType)[0]
3252                    for i,id in enumerate(RBObj['Ids']):
3253                        data['Atoms'][AtLookUp[id]][cx:cx+3] = newXYZ[i]
3254                    data['Drawing']['Atoms'] = []
3255                    UpdateDrawAtoms(atomStyle)
3256                    G2plt.PlotStructure(G2frame,data)
3257                except ValueError:
3258                    pass
3259               
3260            def OnOrien(event):
3261                Obj = event.GetEventObject()
3262                item = Indx[Obj.GetId()]
3263                A,V = G2mth.Q2AVdeg(RBObj['Orient'][0])
3264                V = np.inner(Bmat,V)
3265                try:
3266                    val = float(Obj.GetValue())
3267                    if item:
3268                        V[item-1] = val
3269                    else:
3270                        A = val
3271                    Obj.SetValue('%8.5f'%(val))
3272                    V = np.inner(Amat,V)
3273                    Q = G2mth.AVdeg2Q(A,V)
3274                    if not any(Q):
3275                        raise ValueError
3276                    RBObj['Orient'][0] = Q
3277                    newXYZ = G2mth.UpdateRBXYZ(Bmat,RBObj,RBData,rbType)[0]
3278                    for i,id in enumerate(RBObj['Ids']):
3279                        data['Atoms'][AtLookUp[id]][cx:cx+3] = newXYZ[i]
3280                    data['Drawing']['Atoms'] = []
3281                    UpdateDrawAtoms(atomStyle)
3282                    G2plt.PlotStructure(G2frame,data)
3283                except ValueError:
3284                    pass
3285               
3286            topSizer = wx.FlexGridSizer(2,6,5,5)
3287            Orig = RBObj['Orig'][0]
3288            Orien,OrienV = G2mth.Q2AVdeg(RBObj['Orient'][0])
3289            Orien = [Orien,]
3290            Orien.extend(OrienV/nl.norm(OrienV))
3291            topSizer.Add(wx.StaticText(RigidBodies,-1,'Origin x,y,z:'),0,wx.ALIGN_CENTER_VERTICAL)
3292            for ix,x in enumerate(Orig):
3293                origX = wx.TextCtrl(RigidBodies,-1,value='%8.5f'%(x),style=wx.TE_PROCESS_ENTER)
3294                origX.Bind(wx.EVT_TEXT_ENTER,OnOrigX)
3295                origX.Bind(wx.EVT_KILL_FOCUS,OnOrigX)
3296                Indx[origX.GetId()] = ix
3297                topSizer.Add(origX,0,wx.ALIGN_CENTER_VERTICAL)
3298            topSizer.Add((5,0),)
3299            Ocheck = wx.CheckBox(RigidBodies,-1,'Refine?')
3300            Ocheck.Bind(wx.EVT_CHECKBOX,OnOrigRef)
3301            Ocheck.SetValue(RBObj['Orig'][1])
3302            topSizer.Add(Ocheck,0,wx.ALIGN_CENTER_VERTICAL)
3303            topSizer.Add(wx.StaticText(RigidBodies,-1,'Rotation angle, vector:'),0,wx.ALIGN_CENTER_VERTICAL)
3304            for ix,x in enumerate(Orien):
3305                orien = wx.TextCtrl(RigidBodies,-1,value='%8.4f'%(x),style=wx.TE_PROCESS_ENTER)
3306                orien.Bind(wx.EVT_TEXT_ENTER,OnOrien)
3307                orien.Bind(wx.EVT_KILL_FOCUS,OnOrien)
3308                Indx[orien.GetId()] = ix
3309                topSizer.Add(orien,0,wx.ALIGN_CENTER_VERTICAL)
3310            Qcheck = wx.ComboBox(RigidBodies,-1,value='',choices=[' ','A','AV'],
3311                style=wx.CB_READONLY|wx.CB_DROPDOWN)
3312            Qcheck.Bind(wx.EVT_COMBOBOX,OnOrienRef)
3313            Qcheck.SetValue(RBObj['Orient'][1])
3314            topSizer.Add(Qcheck)
3315            return topSizer
3316                         
3317        def ResrbSizer(RBObj):
3318            G2frame.dataFrame.SetStatusText('NB: Rotation vector is in crystallographic space')
3319             
3320            def OnTorsionRef(event):
3321                Obj = event.GetEventObject()
3322                item = Indx[Obj.GetId()]
3323                RBObj['Torsions'][item][1] = Obj.GetValue()               
3324               
3325            def OnTorsion(event):
3326                Obj = event.GetEventObject()
3327                item = Indx[Obj.GetId()]
3328                try:
3329                    val = float(Obj.GetValue())
3330                    RBObj['Torsions'][item][0] = val
3331                    newXYZ = G2mth.UpdateRBXYZ(Bmat,RBObj,RBData,'Residue')[0]
3332                    for i,id in enumerate(RBObj['Ids']):
3333                        data['Atoms'][AtLookUp[id]][cx:cx+3] = newXYZ[i]
3334                except ValueError:
3335                    pass
3336                Obj.SetValue("%10.3f"%(RBObj['Torsions'][item][0]))               
3337                data['Drawing']['Atoms'] = []
3338                UpdateDrawAtoms(atomStyle)
3339                drawAtoms.ClearSelection()
3340                G2plt.PlotStructure(G2frame,data)
3341               
3342            def OnDelResRB(event):
3343                Obj = event.GetEventObject()
3344                RBId = Indx[Obj.GetId()]
3345                RBData['Residue'][RBId]['useCount'] -= 1
3346                RBObjs = data['RBModels']['Residue']
3347                for rbObj in RBObjs:
3348                    if RBId == rbObj['RBId']:
3349                       data['RBModels']['Residue'].remove(rbObj)                 
3350                G2plt.PlotStructure(G2frame,data)
3351                wx.CallAfter(FillRigidBodyGrid,True)
3352               
3353            resrbSizer = wx.BoxSizer(wx.VERTICAL)
3354            resrbSizer.Add(wx.StaticText(RigidBodies,-1,120*'-'))
3355            topLine = wx.BoxSizer(wx.HORIZONTAL)
3356            topLine.Add(wx.StaticText(RigidBodies,-1,
3357                'Name: '+RBObj['RBname']+RBObj['numChain']+'   '),0,wx.ALIGN_CENTER_VERTICAL)
3358            rbId = RBObj['RBId']
3359            delRB = wx.CheckBox(RigidBodies,-1,'Delete?')
3360            delRB.Bind(wx.EVT_CHECKBOX,OnDelResRB)
3361            Indx[delRB.GetId()] = rbId
3362            topLine.Add(delRB,0,wx.ALIGN_CENTER_VERTICAL)
3363            resrbSizer.Add(topLine)
3364            resrbSizer.Add(LocationSizer(RBObj,'Residue'))
3365            resrbSizer.Add(wx.StaticText(RigidBodies,-1,'Torsions:'),0,wx.ALIGN_CENTER_VERTICAL)
3366            torSizer = wx.FlexGridSizer(1,6,5,5)
3367            for itors,tors in enumerate(RBObj['Torsions']):
3368                torSizer.Add(wx.StaticText(RigidBodies,-1,'Torsion '+'%d'%(itors)),0,wx.ALIGN_CENTER_VERTICAL)
3369                torsTxt = wx.TextCtrl(RigidBodies,-1,value='%.3f'%(tors[0]),style=wx.TE_PROCESS_ENTER)
3370                torsTxt.Bind(wx.EVT_TEXT_ENTER,OnTorsion)
3371                torsTxt.Bind(wx.EVT_KILL_FOCUS,OnTorsion)
3372                Indx[torsTxt.GetId()] = itors
3373                torSizer.Add(torsTxt)
3374                torCheck = wx.CheckBox(RigidBodies,-1,'Refine?')
3375                torCheck.Bind(wx.EVT_CHECKBOX,OnTorsionRef)
3376                torCheck.SetValue(tors[1])
3377                Indx[torCheck.GetId()] = itors
3378                torSizer.Add(torCheck,0,wx.ALIGN_CENTER_VERTICAL)
3379            resrbSizer.Add(torSizer)
3380            tchoice = ['None','Uiso','T','TL','TLS']
3381            thermSizer = wx.BoxSizer(wx.HORIZONTAL)
3382            thermSizer.Add(wx.StaticText(RigidBodies,-1,'Rigid body thermal motion model: '),0,wx.ALIGN_CENTER_VERTICAL)
3383            thermSel = wx.ComboBox(RigidBodies,-1,value=RBObj['ThermalMotion'][0],choices=tchoice,
3384                style=wx.CB_READONLY|wx.CB_DROPDOWN)
3385            Indx[thermSel.GetId()] = RBObj
3386            thermSel.Bind(wx.EVT_COMBOBOX,OnThermSel)
3387            thermSizer.Add(thermSel,0,wx.ALIGN_CENTER_VERTICAL)
3388            thermSizer.Add(wx.StaticText(RigidBodies,-1,' Units: T A^2, L deg^2, S deg-A'),0,wx.ALIGN_CENTER_VERTICAL)
3389            resrbSizer.Add(thermSizer)
3390            if RBObj['ThermalMotion'][0] != 'None':
3391                resrbSizer.Add(ThermDataSizer(RBObj))
3392            return resrbSizer
3393           
3394        def VecrbSizer(RBObj):
3395            G2frame.dataFrame.SetStatusText('NB: Rotation vector is in crystallographic space')
3396                   
3397            def OnDelVecRB(event):
3398                Obj = event.GetEventObject()
3399                RBId = Indx[Obj.GetId()]
3400                RBData['Vector'][RBId]['useCount'] -= 1               
3401                RBObjs = data['RBModels']['Vector']
3402                for rbObj in RBObjs:
3403                    if RBId == rbObj['RBId']:
3404                       data['RBModels']['Vector'].remove(rbObj)                 
3405                G2plt.PlotStructure(G2frame,data)
3406                wx.CallAfter(FillRigidBodyGrid,True)
3407             
3408            vecrbSizer = wx.BoxSizer(wx.VERTICAL)
3409            vecrbSizer.Add(wx.StaticText(RigidBodies,-1,120*'-'))
3410            topLine = wx.BoxSizer(wx.HORIZONTAL)
3411            topLine.Add(wx.StaticText(RigidBodies,-1,
3412                'Name: '+RBObj['RBname']+'   '),0,wx.ALIGN_CENTER_VERTICAL)
3413            rbId = RBObj['RBId']
3414            delRB = wx.CheckBox(RigidBodies,-1,'Delete?')
3415            delRB.Bind(wx.EVT_CHECKBOX,OnDelVecRB)
3416            Indx[delRB.GetId()] = rbId
3417            topLine.Add(delRB,0,wx.ALIGN_CENTER_VERTICAL)
3418            vecrbSizer.Add(topLine)
3419            vecrbSizer.Add(LocationSizer(RBObj,'Vector'))
3420            tchoice = ['None','Uiso','T','TL','TLS']
3421            thermSizer = wx.BoxSizer(wx.HORIZONTAL)
3422            thermSizer.Add(wx.StaticText(RigidBodies,-1,'Rigid body thermal motion model: '),0,wx.ALIGN_CENTER_VERTICAL)
3423            thermSel = wx.ComboBox(RigidBodies,-1,value=RBObj['ThermalMotion'][0],choices=tchoice,
3424                style=wx.CB_READONLY|wx.CB_DROPDOWN)
3425            Indx[thermSel.GetId()] = RBObj
3426            thermSel.Bind(wx.EVT_COMBOBOX,OnThermSel)
3427            thermSizer.Add(thermSel,0,wx.ALIGN_CENTER_VERTICAL)
3428            thermSizer.Add(wx.StaticText(RigidBodies,-1,' Units: T A^2, L deg^2, S deg-A'),0,wx.ALIGN_CENTER_VERTICAL)
3429            vecrbSizer.Add(thermSizer)
3430            if RBObj['ThermalMotion'][0] != 'None':
3431                vecrbSizer.Add(ThermDataSizer(RBObj))
3432            return vecrbSizer               
3433       
3434        # FillRigidBodyGrid executable code starts here
3435        if refresh:
3436            RigidBodies.DestroyChildren()
3437        AtLookUp = G2mth.FillAtomLookUp(data['Atoms'])
3438        general = data['General']
3439        cx = general['AtomPtrs'][0]
3440        Amat,Bmat = G2lat.cell2AB(general['Cell'][1:7])
3441        RBData = G2frame.PatternTree.GetItemPyData(   
3442            G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Rigid bodies'))
3443        Indx = {}
3444        atomStyle = 'balls & sticks'
3445        if 'macro' in general['Type']:
3446            atomStyle = 'sticks'
3447        G2frame.dataFrame.SetStatusText('')
3448        mainSizer = wx.BoxSizer(wx.VERTICAL)
3449        if not data['RBModels']:
3450            mainSizer.Add((5,5),0)
3451            mainSizer.Add(wx.StaticText(RigidBodies,-1,'No rigid body models:'),0,wx.ALIGN_CENTER_VERTICAL)
3452            mainSizer.Add((5,5),0)
3453        if 'Residue' in data['RBModels']:
3454            mainSizer.Add((5,5),0)
3455            mainSizer.Add(wx.StaticText(RigidBodies,-1,'Residue rigid bodies:'),0,wx.ALIGN_CENTER_VERTICAL)
3456            mainSizer.Add((5,5),0)
3457            for RBObj in data['RBModels']['Residue']:
3458                mainSizer.Add(ResrbSizer(RBObj))
3459        if 'Vector' in data['RBModels']:
3460            mainSizer.Add((5,5),0)
3461            mainSizer.Add(wx.StaticText(RigidBodies,-1,'Vector rigid bodies:'),0,wx.ALIGN_CENTER_VERTICAL)
3462            mainSizer.Add((5,5),0)
3463            for RBObj in data['RBModels']['Vector']:
3464                mainSizer.Add(VecrbSizer(RBObj))
3465
3466        RigidBodies.SetSizer(mainSizer)
3467        if G2frame.dataFrame.PhaseUserSize is None:
3468            mainSizer.FitInside(G2frame.dataFrame)
3469            Size = mainSizer.Fit()
3470            Size[0] += 40
3471            Size[1] = max(Size[1],290) + 35
3472            RigidBodies.SetSize(Size)
3473            RigidBodies.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
3474            Size[1] = min(Size[1],450)
3475            G2frame.dataFrame.setSizePosLeft(Size)
3476        else:
3477            Size = G2frame.dataFrame.PhaseUserSize
3478            RigidBodies.SetSize(Size)
3479            RigidBodies.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
3480            G2frame.dataFrame.Update()
3481
3482    def OnRBCopyParms(event):
3483        RBObjs = []
3484        for rbType in ['Vector','Residue']:           
3485            RBObjs += data['RBModels'].get(rbType,[])
3486        if not len(RBObjs):
3487            print '**** ERROR - no rigid bodies defined ****'
3488            return
3489        if len(RBObjs) == 1:
3490            print '**** INFO - only one rigid body defined; nothing to copy to ****'
3491            return
3492        Source = []
3493        sourceRB = {}
3494        for RBObj in RBObjs:
3495            Source.append(RBObj['RBname'])
3496        dlg = wx.SingleChoiceDialog(G2frame,'Select source','Copy rigid body parameters',Source)
3497        if dlg.ShowModal() == wx.ID_OK:
3498            sel = dlg.GetSelection()
3499            name = Source[sel]
3500            for item in ['Orig','Orient','ThermalMotion']: 
3501                sourceRB.update({item:RBObjs[sel][item],})
3502        dlg.Destroy()
3503        if not sourceRB:
3504            return
3505        dlg = wx.MultiChoiceDialog(G2frame,'Select targets','Copy rigid body parameters',Source)
3506        if dlg.ShowModal() == wx.ID_OK:
3507            sel = dlg.GetSelections()
3508            for x in sel:
3509                RBObjs[x].update(copy.copy(sourceRB))
3510        G2plt.PlotStructure(G2frame,data)
3511        wx.CallAfter(FillRigidBodyGrid(True))
3512               
3513    def OnRBAssign(event):
3514       
3515        G2frame.dataFrame.SetStatusText('')
3516        RBData = G2frame.PatternTree.GetItemPyData(   
3517            G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Rigid bodies'))
3518        rbNames = {}
3519        for rbVec in RBData['Vector']:
3520            if rbVec != 'AtInfo':
3521                rbNames[RBData['Vector'][rbVec]['RBname']] =['Vector',rbVec]
3522        for rbRes in RBData['Residue']:
3523            if rbRes != 'AtInfo':
3524                rbNames[RBData['Residue'][rbRes]['RBname']] = ['Residue',rbRes]
3525        if not rbNames:
3526            print '**** ERROR - no rigid bodies defined ****'
3527            return
3528        general = data['General']
3529        Amat,Bmat = G2lat.cell2AB(general['Cell'][1:7])
3530        cx,ct = general['AtomPtrs'][:2]
3531        atomData = data['Atoms']
3532        Indx = {}
3533        atInd = [-1,-1,-1]
3534        data['testRBObj'] = {}
3535           
3536        def Draw():
3537           
3538            def OnOk(event):
3539                rbType = data['testRBObj']['rbType']
3540                RBObjs = data['RBModels'].get(rbType,[])
3541                rbObj = data['testRBObj']['rbObj']
3542                rbId = rbObj['RBId']
3543                newXYZ = G2mth.UpdateRBXYZ(Bmat,rbObj,RBData,rbType)[0]
3544                Ids = []
3545                dmax = 0.0
3546                oldXYZ = G2mth.getAtomXYZ(atomData,cx)
3547                for xyz in newXYZ:
3548                    dist = G2mth.GetXYZDist(xyz,oldXYZ,Amat)
3549                    dmax = max(dmax,np.min(dist))
3550                    id = np.argmin(dist)
3551                    Ids.append(atomData[id][-1])
3552                    atomData[id][cx:cx+3] = xyz
3553                if dmax > 0.5:
3554                    print '**** WARNING - some atoms not found or misidentified ****'
3555                    print '****           check torsion angles & try again      ****'
3556                    OkBtn.SetLabel('Not Ready')
3557                    OkBtn.Enable(False)
3558                    return
3559                rbObj['Ids'] = Ids
3560                rbObj['ThermalMotion'] = ['None',[0. for i in range(21)],[False for i in range(21)]] #type,values,flags
3561                rbObj['RBname'] += ':'+str(RBData[rbType][rbId]['useCount'])
3562                RBObjs.append(rbObj)
3563                data['RBModels'][rbType] = RBObjs
3564                RBData[rbType][rbId]['useCount'] += 1
3565                del data['testRBObj']
3566                G2plt.PlotStructure(G2frame,data)
3567                FillRigidBodyGrid(True)
3568               
3569            def OnCancel(event):
3570                del data['testRBObj']
3571                FillRigidBodyGrid(True)
3572               
3573            def OnRBSel(event):
3574                selection = rbSel.GetValue()
3575                rbType,rbId = rbNames[selection]
3576                data['testRBObj']['rbAtTypes'] = RBData[rbType][rbId]['rbTypes']
3577                data['testRBObj']['AtInfo'] = RBData[rbType]['AtInfo']
3578                data['testRBObj']['rbType'] = rbType
3579                data['testRBObj']['rbData'] = RBData
3580                data['testRBObj']['Sizers'] = {}
3581                rbRef = RBData[rbType][rbId]['rbRef']
3582                data['testRBObj']['rbRef'] = rbRef
3583                refType = []
3584                refName = []
3585                for ref in rbRef[:3]:
3586                    reftype = data['testRBObj']['rbAtTypes'][ref]
3587                    refType.append(reftype)
3588                    refName.append(reftype+' '+str(rbRef[0]))
3589                atNames,AtNames = fillAtNames(refType,atomData,ct)
3590                data['testRBObj']['atNames'] = atNames
3591                data['testRBObj']['AtNames'] = AtNames
3592                data['testRBObj']['rbObj'] = {'Orig':[[0,0,0],False],
3593                    'Orient':[[0.,0.,0.,1.],' '],'Ids':[],'RBId':rbId,'Torsions':[],
3594                    'numChain':'','RBname':RBData[rbType][rbId]['RBname']}
3595                data['testRBObj']['torAtms'] = []               
3596                for item in RBData[rbType][rbId].get('rbSeq',[]):
3597                    data['testRBObj']['rbObj']['Torsions'].append([item[2],False])
3598                    data['testRBObj']['torAtms'].append([-1,-1,-1])
3599                Draw()
3600               
3601            def fillAtNames(refType,atomData,ct):
3602                atNames = [{},{},{}]
3603                AtNames = {}
3604                for iatm,atom in enumerate(atomData):
3605                    AtNames[atom[ct-1]] = iatm
3606                    for i,reftype in enumerate(refType):
3607                        if atom[ct] == reftype:
3608                            atNames[i][atom[ct-1]] = iatm
3609                return atNames,AtNames
3610               
3611            def OnAtOrigPick(event):
3612                Obj = event.GetEventObject()
3613                item = Indx[Obj.GetId()]
3614                atName = Obj.GetValue()
3615                rbType = data['testRBObj']['rbType']
3616                atInd[0] = atNames[item][atName]
3617                if 'Vector' in rbType:
3618                    rbObj = data['testRBObj']['rbObj']
3619                    rbId = rbObj['RBId']
3620                    rbRef = data['testRBObj']['rbRef']
3621                    rbXYZ = -RBData[rbType][rbId]['rbXYZ']
3622                    nref = atNames[item][atName]
3623                    Oxyz = np.inner(Bmat,np.array(rbXYZ[rbRef[0]]))
3624                    Nxyz = np.array(atomData[nref][cx:cx+3])
3625                    Orig = Nxyz-Oxyz
3626                    data['testRBObj']['rbObj']['Orig'][0] = Orig   
3627                else:
3628                    Orig = atomData[atNames[item][atName]][cx:cx+3]
3629                    data['testRBObj']['rbObj']['Orig'][0] = Orig
3630                for x,item in zip(Orig,Xsizers):
3631                    item.SetLabel('%10.5f'%(x))
3632                G2plt.PlotStructure(G2frame,data)
3633               
3634            def OnAtQPick(event):
3635                Obj = event.GetEventObject()
3636                item = Indx[Obj.GetId()]
3637                atName = Obj.GetValue()
3638                atInd[item] = atNames[item][atName]
3639                if any([x<0 for x in atInd]):
3640                    return
3641                OkBtn.SetLabel('OK')
3642                OkBtn.Enable(True)
3643                rbType = data['testRBObj']['rbType']
3644                rbObj = data['testRBObj']['rbObj']
3645                rbId = rbObj['RBId']
3646                rbRef = data['testRBObj']['rbRef']
3647                rbXYZ = RBData[rbType][rbId]['rbXYZ']
3648                rbOrig = rbXYZ[rbRef[0]]
3649                VAR = rbXYZ[rbRef[1]]-rbOrig
3650                VBR = rbXYZ[rbRef[2]]-rbOrig
3651                if rbType == 'Vector':
3652                    Orig = np.array(atomData[atInd[0]][cx:cx+3])
3653                else:
3654                    Orig = np.array(data['testRBObj']['rbObj']['Orig'][0])               
3655                VAC = np.inner(Amat,np.array(atomData[atInd[1]][cx:cx+3])-Orig)
3656                VBC = np.inner(Amat,np.array(atomData[atInd[2]][cx:cx+3])-Orig)
3657                VCC = np.cross(VAR,VAC)
3658                QuatA = G2mth.makeQuat(VAR,VAC,VCC)[0]
3659                VAR = G2mth.prodQVQ(QuatA,VAR)
3660                VBR = G2mth.prodQVQ(QuatA,VBR)
3661                QuatB = G2mth.makeQuat(VBR,VBC,VAR)[0]
3662                QuatC = G2mth.prodQQ(QuatB,QuatA)
3663                data['testRBObj']['rbObj']['Orient'] = [QuatC,' ']
3664                for x,item in zip(QuatC,Osizers):
3665                    item.SetLabel('%10.4f'%(x))               
3666                if rbType == 'Vector':
3667                    Oxyz = np.inner(Bmat,G2mth.prodQVQ(QuatC,rbOrig))
3668                    Nxyz = np.array(atomData[atInd[0]][cx:cx+3])
3669                    Orig = Nxyz-Oxyz
3670                    data['testRBObj']['rbObj']['Orig'][0] = Orig
3671                    for x,item in zip(Orig,Xsizers):
3672                        item.SetLabel('%10.5f'%(x))
3673                G2plt.PlotStructure(G2frame,data)
3674               
3675            def OnTorAngle(event):
3676                OkBtn.SetLabel('OK')
3677                OkBtn.Enable(True)
3678                Obj = event.GetEventObject()
3679                [tor,torSlide] = Indx[Obj.GetId()]
3680                Tors = data['testRBObj']['rbObj']['Torsions'][tor]
3681                try:
3682                    value = float(Obj.GetValue())
3683                except ValueError:
3684                    value = Tors[0]
3685                Tors[0] = value
3686                Obj.SetValue('%8.3f'%(value))
3687                torSlide.SetValue(int(value*10))
3688                G2plt.PlotStructure(G2frame,data)
3689               
3690            def OnTorSlide(event):
3691                OkBtn.SetLabel('OK')
3692                OkBtn.Enable(True)
3693                Obj = event.GetEventObject()
3694                tor,ang = Indx[Obj.GetId()]
3695                Tors = data['testRBObj']['rbObj']['Torsions'][tor]
3696                val = float(Obj.GetValue())/10.
3697                Tors[0] = val
3698                ang.SetValue('%8.3f'%(val))
3699                G2plt.PlotStructure(G2frame,data)
3700
3701            if len(data['testRBObj']):
3702                G2plt.PlotStructure(G2frame,data)
3703                   
3704            RigidBodies.DestroyChildren()
3705            mainSizer = wx.BoxSizer(wx.VERTICAL)
3706            mainSizer.Add((5,5),0)
3707            if data['testRBObj']:
3708                Xsizers = []
3709                Osizers = []
3710                rbObj = data['testRBObj']['rbObj']
3711                rbName = rbObj['RBname']
3712                rbId = rbObj['RBId']
3713                Orig = rbObj['Orig'][0]
3714                Orien = rbObj['Orient'][0]
3715                rbRef = data['testRBObj']['rbRef']
3716                Torsions = rbObj['Torsions']
3717                refName = []
3718                for ref in rbRef:
3719                    refName.append(data['testRBObj']['rbAtTypes'][ref]+str(ref))
3720                atNames = data['testRBObj']['atNames']
3721                mainSizer.Add(wx.StaticText(RigidBodies,-1,'Locate rigid body : '+rbName),
3722                    0,wx.ALIGN_CENTER_VERTICAL)
3723                mainSizer.Add((5,5),0)
3724                OriSizer = wx.FlexGridSizer(1,5,5,5)
3725                OriSizer.Add(wx.StaticText(RigidBodies,-1,'Origin x,y,z: '),0,wx.ALIGN_CENTER_VERTICAL)
3726                for ix,x in enumerate(Orig):
3727                    origX = wx.StaticText(RigidBodies,-1,'%10.5f'%(x))
3728                    OriSizer.Add(origX,0,wx.ALIGN_CENTER_VERTICAL)
3729                    Xsizers.append(origX)
3730                OriSizer.Add((5,0),)
3731                if len(atomData):
3732                    choice = atNames[0].keys()
3733                    choice.sort()
3734                    data['testRBObj']['Sizers']['Xsizers'] = Xsizers
3735                OriSizer.Add(wx.StaticText(RigidBodies,-1,'Orientation quaternion: '),0,wx.ALIGN_CENTER_VERTICAL)
3736                for ix,x in enumerate(Orien):
3737                    orien = wx.StaticText(RigidBodies,-1,'%10.4f'%(x))
3738                    OriSizer.Add(orien,0,wx.ALIGN_CENTER_VERTICAL)
3739                    Osizers.append(orien)
3740                data['testRBObj']['Sizers']['Osizers'] = Osizers
3741                mainSizer.Add(OriSizer)
3742                mainSizer.Add((5,5),0)
3743                RefSizer = wx.FlexGridSizer(1,7,5,5)
3744                if len(atomData):
3745                    RefSizer.Add(wx.StaticText(RigidBodies,-1,'Location setting: Select match to'),0,wx.ALIGN_CENTER_VERTICAL)
3746                    for i in [0,1,2]:
3747                        choice = ['',]+atNames[i].keys()
3748                        choice.sort()
3749                        RefSizer.Add(wx.StaticText(RigidBodies,-1,' '+refName[i]+': '),0,wx.ALIGN_CENTER_VERTICAL)
3750                        atPick = wx.ComboBox(RigidBodies,-1,value='',
3751                            choices=choice[1:],style=wx.CB_READONLY|wx.CB_DROPDOWN)
3752                        if i:
3753                            atPick.Bind(wx.EVT_COMBOBOX, OnAtQPick)
3754                        else:
3755                            atPick.Bind(wx.EVT_COMBOBOX, OnAtOrigPick)                           
3756                        Indx[atPick.GetId()] = i
3757                        RefSizer.Add(atPick,0,wx.ALIGN_CENTER_VERTICAL)
3758                mainSizer.Add(RefSizer)
3759                mainSizer.Add((5,5),0)
3760                if Torsions:                   
3761                    AtNames = data['testRBObj']['AtNames']
3762                    rbAtTypes = data['testRBObj']['rbAtTypes']
3763                    rbSeq = RBData['Residue'][rbId]['rbSeq']
3764                    TorSizer = wx.FlexGridSizer(1,4)
3765                    TorSizer.AddGrowableCol(1,1)
3766                    for t,[torsion,seq] in enumerate(zip(Torsions,rbSeq)):
3767                        torName = ''
3768                        for item in [seq[0],seq[1],seq[3][0]]:
3769                            torName += data['testRBObj']['rbAtTypes'][item]+str(item)+' '
3770                        TorSizer.Add(wx.StaticText(RigidBodies,-1,'Side chain torsion for rb seq: '+torName),0,wx.ALIGN_CENTER_VERTICAL)
3771                        torSlide = wx.Slider(RigidBodies,style=wx.SL_HORIZONTAL)
3772                        torSlide.SetRange(0,3600)
3773                        torSlide.SetValue(int(torsion[0]*10.))
3774                        torSlide.Bind(wx.EVT_SLIDER, OnTorSlide)
3775                        TorSizer.Add(torSlide,1,wx.EXPAND|wx.RIGHT)
3776                        TorSizer.Add(wx.StaticText(RigidBodies,-1,' Angle: '),0,wx.ALIGN_CENTER_VERTICAL)
3777                        ang = wx.TextCtrl(RigidBodies,-1,value='%8.3f'%(torsion[0]),style=wx.TE_PROCESS_ENTER)
3778                        ang.Bind(wx.EVT_TEXT_ENTER,OnTorAngle)
3779                        ang.Bind(wx.EVT_KILL_FOCUS,OnTorAngle)
3780                        Indx[torSlide.GetId()] = [t,ang]
3781                        Indx[ang.GetId()] = [t,torSlide]
3782                        TorSizer.Add(ang,0,wx.ALIGN_CENTER_VERTICAL)                           
3783                    mainSizer.Add(TorSizer,1,wx.EXPAND|wx.RIGHT)
3784                else:
3785                    mainSizer.Add(wx.StaticText(RigidBodies,-1,'No side chain torsions'),0,wx.ALIGN_CENTER_VERTICAL)
3786            else:
3787                mainSizer.Add(wx.StaticText(RigidBodies,-1,'Assign rigid body:'),0,wx.ALIGN_CENTER_VERTICAL)
3788                mainSizer.Add((5,5),0)
3789                topSizer = wx.BoxSizer(wx.HORIZONTAL)
3790                topSizer.Add(wx.StaticText(RigidBodies,-1,'Select rigid body model'),0,wx.ALIGN_CENTER_VERTICAL)
3791                rbSel = wx.ComboBox(RigidBodies,-1,value='',choices=rbNames.keys(),
3792                    style=wx.CB_READONLY|wx.CB_DROPDOWN)
3793                rbSel.Bind(wx.EVT_COMBOBOX, OnRBSel)
3794                topSizer.Add((5,5),0)
3795                topSizer.Add(rbSel,0,wx.ALIGN_CENTER_VERTICAL)
3796                mainSizer.Add(topSizer)               
3797               
3798            OkBtn = wx.Button(RigidBodies,-1,"Not ready")
3799            OkBtn.Bind(wx.EVT_BUTTON, OnOk)
3800            OkBtn.Enable(False)
3801            CancelBtn = wx.Button(RigidBodies,-1,'Cancel')
3802            CancelBtn.Bind(wx.EVT_BUTTON, OnCancel)
3803            btnSizer = wx.BoxSizer(wx.HORIZONTAL)
3804            btnSizer.Add((20,20),1)
3805            btnSizer.Add(OkBtn)
3806            btnSizer.Add(CancelBtn)
3807            btnSizer.Add((20,20),1)
3808            mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
3809            RigidBodies.SetSizer(mainSizer)
3810            Size = mainSizer.Fit(RigidBodies)
3811            Size[0] += 40
3812            Size[1] = min(max(Size[1],290) + 35,560)
3813            RigidBodies.SetSize(Size)
3814            RigidBodies.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
3815            G2frame.dataFrame.setSizePosLeft(Size)
3816        Draw()
3817       
3818    def OnAutoFindResRB(event):
3819        RBData = G2frame.PatternTree.GetItemPyData(   
3820            G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Rigid bodies'))
3821        rbKeys = RBData['Residue'].keys()
3822        rbKeys.remove('AtInfo')
3823        if not len(rbKeys):
3824            print '**** ERROR - no residue rigid bodies are defined ****'
3825            return
3826        RBNames = [RBData['Residue'][k]['RBname'] for k in rbKeys]
3827        RBIds = dict(zip(RBNames,rbKeys))
3828        general = data['General']
3829        Amat,Bmat = G2lat.cell2AB(general['Cell'][1:7])
3830        Atoms = data['Atoms']
3831        AtLookUp = G2mth.FillAtomLookUp(Atoms)
3832        if 'macro' not in general['Type']:
3833            print '**** ERROR - this phase is not a macromolecule ****'
3834            return
3835        if not len(Atoms):
3836            print '**** ERROR - this phase has no atoms ****'
3837            return
3838        RBObjs = []
3839        cx,ct = general['AtomPtrs'][:2]
3840        iatm = 0
3841        wx.BeginBusyCursor()
3842        try:
3843            while iatm < len(Atoms):
3844                atom = Atoms[iatm]
3845                res = atom[1].strip()
3846                numChain = ' %s %s'%(atom[0],atom[2])
3847                if res not in RBIds or atom[ct-1] == 'OXT':
3848                    iatm += 1
3849                    continue        #skip for OXT, water molecules, etc.
3850                rbRes = RBData['Residue'][RBIds[res]]
3851                rbRef = rbRes['rbRef']
3852                VAR = rbRes['rbXYZ'][rbRef[1]]-rbRes['rbXYZ'][rbRef[0]]
3853                VBR = rbRes['rbXYZ'][rbRef[2]]-rbRes['rbXYZ'][rbRef[0]]
3854                rbObj = {'RBname':rbRes['RBname']+':'+str(rbRes['useCount']),'numChain':numChain}
3855                rbAtoms = []
3856                rbIds = []
3857                for iratm in range(len(rbRes['atNames'])):
3858                    rbAtoms.append(np.array(Atoms[iatm][cx:cx+3]))
3859                    rbIds.append(Atoms[iatm][20])
3860                    iatm += 1    #puts this at beginning of next residue?
3861                Orig = rbAtoms[rbRef[0]]
3862                rbObj['RBId'] = RBIds[res]
3863                rbObj['Ids'] = rbIds
3864                rbObj['Orig'] = [Orig,False]
3865#                print ' residue '+rbRes['RBname']+str(atom[0]).strip()+ \
3866#                    ' origin at: ','%.5f %.5f %.5f'%(Orig[0],Orig[1],Orig[2])
3867                VAC = np.inner(Amat,rbAtoms[rbRef[1]]-Orig)
3868                VBC = np.inner(Amat,rbAtoms[rbRef[2]]-Orig)
3869                VCC = np.cross(VAR,VAC)
3870                QuatA = G2mth.makeQuat(VAR,VAC,VCC)[0]
3871                VAR = G2mth.prodQVQ(QuatA,VAR)
3872                VBR = G2mth.prodQVQ(QuatA,VBR)
3873                QuatB = G2mth.makeQuat(VBR,VBC,VAR)[0]
3874                QuatC = G2mth.prodQQ(QuatB,QuatA)
3875                rbObj['Orient'] = [QuatC,' ']
3876                rbObj['ThermalMotion'] = ['None',[0. for i in range(21)],[False for i in range(21)]] #type,values,flags
3877                SXYZ = []
3878                TXYZ = []
3879                rbObj['Torsions'] = []
3880                for i,xyz in enumerate(rbRes['rbXYZ']):
3881                    SXYZ.append(G2mth.prodQVQ(QuatC,xyz))               
3882                    TXYZ.append(np.inner(Amat,rbAtoms[i]-Orig))
3883                for Oatm,Patm,x,Riders in rbRes['rbSeq']:
3884                    VBR = SXYZ[Oatm]-SXYZ[Patm]
3885                    VAR = SXYZ[Riders[0]]-SXYZ[Patm]
3886                    VAC = TXYZ[Riders[0]]-TXYZ[Patm]
3887                    QuatA,D = G2mth.makeQuat(VAR,VAC,VBR)
3888                    ang = 180.*D/np.pi
3889                    rbObj['Torsions'].append([ang,False])
3890                    for ride in Riders:
3891                        SXYZ[ride] = G2mth.prodQVQ(QuatA,SXYZ[ride]-SXYZ[Patm])+SXYZ[Patm]
3892                rbRes['useCount'] += 1
3893                RBObjs.append(rbObj)
3894            data['RBModels']['Residue'] = RBObjs
3895            for RBObj in RBObjs:
3896                newXYZ = G2mth.UpdateRBXYZ(Bmat,RBObj,RBData,'Residue')[0]
3897                for i,id in enumerate(RBObj['Ids']):
3898                    data['Atoms'][AtLookUp[id]][cx:cx+3] = newXYZ[i]
3899        finally:
3900            wx.EndBusyCursor()
3901        wx.CallAfter(FillRigidBodyGrid,True)
3902       
3903    def OnRBRemoveAll(event):
3904        data['RBModels']['Residue'] = []
3905        data['RBModels']['Vector'] = []
3906        RBData = G2frame.PatternTree.GetItemPyData(   
3907            G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Rigid bodies'))
3908        for RBType in ['Vector','Residue']:
3909            for rbId in RBData[RBType]:
3910                RBData[RBType][rbId]['useCount'] = 0       
3911        FillRigidBodyGrid(True)
3912       
3913    def OnGlobalResRBTherm(event):
3914        RBObjs = data['RBModels']['Residue']
3915        names = ['None','Uiso','T','TL','TLS']
3916        dlg = wx.SingleChoiceDialog(G2frame,'Select','Residue thermal motion model',names)
3917        if dlg.ShowModal() == wx.ID_OK:
3918            sel = dlg.GetSelection()
3919            parm = names[sel]
3920        for rbObj in RBObjs:
3921            rbObj['ThermalMotion'][0] = parm
3922        dlg.Destroy()
3923        FillRigidBodyGrid(True)
3924
3925    def OnGlobalResRBRef(event):
3926        RBObjs = data['RBModels']['Residue']
3927        names = ['Origin','Orient. angle','Full Orient.']
3928        nTor = 0
3929        for rbObj in RBObjs:
3930            nTor = max(nTor,len(rbObj['Torsions']))
3931        names += ['Torsion '+str(i) for i in range(nTor)]
3932        if np.any([rbObj['ThermalMotion'][0] == 'Uiso' for rbObj in RBObjs]):
3933           names += ['Uiso',]
3934        if np.any([rbObj['ThermalMotion'][0] == 'TLS' for rbObj in RBObjs]):
3935           names += ['Tii','Tij','Lii','Lij','Sij']
3936        elif np.any([rbObj['ThermalMotion'][0] == 'TL' for rbObj in RBObjs]):
3937           names += ['Tii','Tij','Lii','Lij']
3938        elif np.any([rbObj['ThermalMotion'][0] == 'T' for rbObj in RBObjs]):
3939           names += ['Tii','Tij']
3940
3941        dlg = wx.MultiChoiceDialog(G2frame,'Select','Refinement controls',names)
3942        if dlg.ShowModal() == wx.ID_OK:
3943            sel = dlg.GetSelections()
3944            parms = []
3945            for x in sel:
3946                parms.append(names[x])
3947            wx.BeginBusyCursor()
3948            try:
3949                for rbObj in RBObjs:
3950                    if 'Origin' in parms:
3951                        rbObj['Orig'][1] = True
3952                    else:
3953                        rbObj['Orig'][1] = False
3954                    if 'Full Orient.' in parms:
3955                        rbObj['Orient'][1] = 'AV'
3956                    elif 'Orient. angle' in parms:
3957                        rbObj['Orient'][1] = 'A'
3958                    else:
3959                        rbObj['Orient'][1] = ' '
3960                    for i in range(len(rbObj['Torsions'])):
3961                        if 'Torsion '+str(i) in parms:
3962                            rbObj['Torsions'][i][1] = True
3963                        else:
3964                            rbObj['Torsions'][i][1] = False
3965                    if rbObj['ThermalMotion'][0] == 'Uiso':
3966                        if 'Uiso' in parms:
3967                           rbObj['ThermalMotion'][2][0] = True
3968                        else:
3969                           rbObj['ThermalMotion'][2][0] = False
3970                    elif 'T' in rbObj['ThermalMotion'][0]:
3971                        if 'Tii' in parms:
3972                            rbObj['ThermalMotion'][2][0:2] = [True,True,True]
3973                        else:
3974                            rbObj['ThermalMotion'][2][0:2] = [False,False,False]
3975                        if 'Tij' in parms:
3976                            rbObj['ThermalMotion'][2][3:6] = [True,True,True]
3977                        else:
3978                            rbObj['ThermalMotion'][2][3:6] = [False,False,False]
3979                    elif 'L' in rbObj['ThermalMotion'][0]:
3980                        if 'Lii' in parms:
3981                            rbObj['ThermalMotion'][2][6:9] = [True,True,True]
3982                        else:
3983                            rbObj['ThermalMotion'][2][6:9] = [False,False,False]
3984                        if 'Lij' in parms:
3985                            rbObj['ThermalMotion'][2][9:12] = [True,True,True]
3986                        else:
3987                            rbObj['ThermalMotion'][2][9:12] = [False,False,False]
3988                    elif 'S' in rbObj['ThermalMotion'][0]:
3989                        if 'Sij' in parms:
3990                            rbObj['ThermalMotion'][2][12:20] = [True,True,True,True,True,True,True,True]
3991                        else:
3992                            rbObj['ThermalMotion'][2][12:20] = [False,False,False,False,False,False,False,False]
3993            finally:
3994                wx.EndBusyCursor()
3995            FillRigidBodyGrid()
3996           
3997################################################################################
3998##### MC/SA routines
3999################################################################################
4000
4001    def UpdateMCSA(refresh=True):
4002        Indx = {}
4003       
4004        def OnPosRef(event):
4005            Obj = event.GetEventObject()
4006            model,item,ix = Indx[Obj.GetId()]
4007            model[item][1][ix] = Obj.GetValue()
4008           
4009        def OnPosVal(event):
4010            Obj = event.GetEventObject()
4011            model,item,ix = Indx[Obj.GetId()]
4012            try:
4013                model[item][0][ix] = float(Obj.GetValue())
4014            except ValueError:
4015                pass
4016            Obj.SetValue("%.4f"%(model[item][0][ix]))
4017            G2plt.PlotStructure(G2frame,data)
4018           
4019        def OnPosRange(event):
4020            Obj = event.GetEventObject()
4021            model,item,ix = Indx[Obj.GetId()]
4022            Range = Obj.GetValue().split()
4023            try:
4024                rmin,rmax = [float(Range[i]) for i in range(2)]
4025                if rmin >= rmax:
4026                    raise ValueError
4027            except (ValueError,IndexError):
4028                rmin,rmax = model[item][2][ix]
4029            model[item][2][ix] = [rmin,rmax]
4030            Obj.SetValue('%.3f %.3f'%(rmin,rmax))                 
4031               
4032        def atomSizer(model):
4033           
4034            atomsizer = wx.FlexGridSizer(1,7,5,5)
4035            atomsizer.Add(wx.StaticText(MCSA,-1,' Atom: '+model['name']+': '),0,wx.ALIGN_CENTER_VERTICAL)
4036            for ix,item in enumerate(['x','y','z']):
4037                posRef = wx.CheckBox(MCSA,-1,label=item+': ')
4038                posRef.SetValue(model['Pos'][1][ix])
4039                posRef.Bind(wx.EVT_CHECKBOX,OnPosRef)
4040                Indx[posRef.GetId()] = [model,'Pos',ix]
4041                atomsizer.Add(posRef,0,wx.ALIGN_CENTER_VERTICAL)
4042                posVal = wx.TextCtrl(MCSA,-1,'%.4f'%(model['Pos'][0][ix]),style=wx.TE_PROCESS_ENTER)
4043                posVal.Bind(wx.EVT_TEXT_ENTER,OnPosVal)
4044                posVal.Bind(wx.EVT_KILL_FOCUS,OnPosVal)
4045                Indx[posVal.GetId()] = [model,'Pos',ix]
4046                atomsizer.Add(posVal,0,wx.ALIGN_CENTER_VERTICAL)
4047            atomsizer.Add((5,5),0)
4048            for ix,item in enumerate(['x','y','z']):
4049                atomsizer.Add(wx.StaticText(MCSA,-1,' Range: '),0,wx.ALIGN_CENTER_VERTICAL)
4050                rmin,rmax = model['Pos'][2][ix]
4051                posRange = wx.TextCtrl(MCSA,-1,'%.3f %.3f'%(rmin,rmax),style=wx.TE_PROCESS_ENTER)
4052                Indx[posRange.GetId()] = [model,'Pos',ix]
4053                posRange.Bind(wx.EVT_TEXT_ENTER,OnPosRange)
4054                posRange.Bind(wx.EVT_KILL_FOCUS,OnPosRange)
4055                atomsizer.Add(posRange,0,wx.ALIGN_CENTER_VERTICAL)
4056            return atomsizer
4057           
4058        def rbSizer(model):
4059           
4060            def OnOrVar(event):
4061                Obj = event.GetEventObject()
4062                model = Indx[Obj.GetId()]
4063                model['Ovar'] = Obj.GetValue()
4064           
4065            def OnOriVal(event):
4066                Obj = event.GetEventObject()
4067                model,ix = Indx[Obj.GetId()]
4068                A,V = G2mth.Q2AVdeg(model['Ori'][0])
4069                if ix:
4070                    Anew = A
4071                    Vec = Obj.GetValue().split()
4072                    try:
4073                        Vnew = [float(Vec[i]) for i in range(3)]
4074                    except ValueError:
4075                        Vnew = V
4076                else:
4077                    Vnew = V
4078                    try:
4079                        Anew = float(Obj.GetValue())
4080                    except ValueError:
4081                        Anew = A
4082                model['Ori'][0] = G2mth.AVdeg2Q(Anew,Vnew)
4083                G2plt.PlotStructure(G2frame,data)
4084                UpdateMCSA()
4085
4086            def OnMolCent(event):
4087                Obj = event.GetEventObject()
4088                model = Indx[Obj.GetId()]
4089                model['MolCent'][1] = Obj.GetValue()
4090                if model['MolCent'][1]:
4091                    G2mth.SetMolCent(model,RBData)               
4092                G2plt.PlotStructure(G2frame,data)
4093           
4094            rbsizer = wx.BoxSizer(wx.VERTICAL)
4095            rbsizer1 = wx.FlexGridSizer(1,7,5,5)
4096            rbsizer1.Add(wx.StaticText(MCSA,-1,model['Type']+': '+model['name']+': '),0,wx.ALIGN_CENTER_VERTICAL)
4097            for ix,item in enumerate(['x','y','z']):
4098                posRef = wx.CheckBox(MCSA,-1,label=item+': ')
4099                posRef.SetValue(model['Pos'][1][ix])
4100                posRef.Bind(wx.EVT_CHECKBOX,OnPosRef)
4101                Indx[posRef.GetId()] = [model,'Pos',ix]
4102                rbsizer1.Add(posRef,0,wx.ALIGN_CENTER_VERTICAL)
4103