source: trunk/GSASIIphsGUI.py @ 854

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

more rigid body stuff

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