source: trunk/GSASIIphsGUI.py @ 927

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

more G2str fixes

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