source: trunk/GSASIIphsGUI.py @ 912

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

Change phase data window so that user resize is tracked and saved; reorder G2phsGUI code to be easier to follow; lots more sphinx documentation

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