source: trunk/GSASIIphsGUI.py @ 1097

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

mods to restraint GUI & LS output for restraints
correct torsion & Ramachandran penalties

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