source: trunk/GSASIIphsGUI.py @ 1007

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

"improved" Pawley extraction by flipping negative intensitied to 1/2 or 1/3 value on Pawley Update.

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