source: trunk/GSASIIphsGUI.py @ 995

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

remove extra imports, etc. from GSASIIddataGUI.py
Select page --> Select tab
fix doubling up for draw atoms

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