source: trunk/GSASIIphsGUI.py @ 1071

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

change tolerance on RB atom matching; wasn't big enough

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