source: trunk/GSASIIphsGUI.py @ 916

Last change on this file since 916 was 916, checked in by toby, 10 years ago

switch General & Draw Options tabs to wx.ScrolledWindow?

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