source: trunk/GSASIIphsGUI.py @ 924

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

plot fixes: save more Draw Options widgets & reference directly; fix mousewheel on mac, where smaller movements are possible

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 215.9 KB
Line 
1# -*- coding: utf-8 -*-
2#GSASII - phase data display routines
3########### SVN repository information ###################
4# $Date: 2013-05-17 22:24:47 +0000 (Fri, 17 May 2013) $
5# $Author: toby $
6# $Revision: 924 $
7# $URL: trunk/GSASIIphsGUI.py $
8# $Id: GSASIIphsGUI.py 924 2013-05-17 22:24:47Z toby $
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: 924 $")
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 GSASIIstruct as G2str
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                G2str.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        G2str.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        G2str.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            Size = mainSizer.Fit(G2frame.dataFrame)
2784            Size[0] = max(Size[0]+35,500)           # leave some extra room and don't get too small
2785            Size[1] = max(Size[1]+35,350)                           #compensate for status bar
2786            drawOptions.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
2787            G2frame.dataFrame.setSizePosLeft(Size)
2788        else:
2789            Size = G2frame.dataFrame.PhaseUserSize
2790            drawOptions.SetSize(G2frame.dataFrame.GetClientSize())
2791            Size = mainSizer.ComputeFittingWindowSize(G2frame.dataFrame)
2792            drawOptions.SetVirtualSize(Size)
2793            drawOptions.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
2794            G2frame.dataFrame.Update()
2795        drawOptions.SetSize(G2frame.dataFrame.GetClientSize())
2796
2797################################################################################
2798####  Texture routines
2799################################################################################
2800       
2801    def UpdateTexture():       
2802        def SetSHCoef():
2803            cofNames = G2lat.GenSHCoeff(SGData['SGLaue'],SamSym[textureData['Model']],textureData['Order'])
2804            newSHCoef = dict(zip(cofNames,np.zeros(len(cofNames))))
2805            SHCoeff = textureData['SH Coeff'][1]
2806            for cofName in SHCoeff:
2807                if cofName in  cofNames:
2808                    newSHCoef[cofName] = SHCoeff[cofName]
2809            return newSHCoef
2810       
2811        def OnShOrder(event):
2812            Obj = event.GetEventObject()
2813            textureData['Order'] = int(Obj.GetValue())
2814            textureData['SH Coeff'][1] = SetSHCoef()
2815            wx.CallAfter(UpdateTexture)
2816            G2plt.PlotTexture(G2frame,data)
2817                       
2818        def OnShModel(event):
2819            Obj = event.GetEventObject()
2820            textureData['Model'] = Obj.GetValue()
2821            textureData['SH Coeff'][1] = SetSHCoef()
2822            wx.CallAfter(UpdateTexture)
2823            G2plt.PlotTexture(G2frame,data)
2824           
2825        def OnSHRefine(event):
2826            Obj = event.GetEventObject()
2827            textureData['SH Coeff'][0] = Obj.GetValue()
2828           
2829        def OnSHShow(event):
2830            Obj = event.GetEventObject()
2831            textureData['SHShow'] = Obj.GetValue()
2832            wx.CallAfter(UpdateTexture)
2833           
2834        def OnProjSel(event):
2835            Obj = event.GetEventObject()
2836            G2frame.Projection = Obj.GetValue()
2837            G2plt.PlotTexture(G2frame,data)
2838           
2839        def OnColorSel(event):
2840            Obj = event.GetEventObject()
2841            G2frame.ContourColor = Obj.GetValue()
2842            G2plt.PlotTexture(G2frame,data)
2843           
2844        def OnAngRef(event):
2845            Obj = event.GetEventObject()
2846            textureData[angIndx[Obj.GetId()]][0] = Obj.GetValue()
2847           
2848        def OnAngValue(event):
2849            Obj = event.GetEventObject()
2850            try:
2851                value =  float(Obj.GetValue())
2852            except ValueError:
2853                value = textureData[valIndx[Obj.GetId()]][1]
2854            Obj.SetValue('%8.2f'%(value))
2855            textureData[valIndx[Obj.GetId()]][1] = value
2856           
2857        def OnODFValue(event): 
2858            Obj = event.GetEventObject()
2859            try:
2860                value =  float(Obj.GetValue())
2861            except ValueError:
2862                value = textureData['SH Coeff'][1][ODFIndx[Obj.GetId()]]
2863            Obj.SetValue('%8.3f'%(value))
2864            textureData['SH Coeff'][1][ODFIndx[Obj.GetId()]] = value
2865            G2plt.PlotTexture(G2frame,data)
2866           
2867        def OnPfType(event):
2868            Obj = event.GetEventObject()
2869            textureData['PlotType'] = Obj.GetValue()
2870            wx.CallAfter(UpdateTexture)
2871            G2plt.PlotTexture(G2frame,data)
2872           
2873        def OnPFValue(event):
2874            Obj = event.GetEventObject()
2875            Saxis = Obj.GetValue().split()
2876            if textureData['PlotType'] in ['Pole figure','Axial pole distribution']:               
2877                try:
2878                    hkl = [int(Saxis[i]) for i in range(3)]
2879                except (ValueError,IndexError):
2880                    hkl = textureData['PFhkl']
2881                if not np.any(np.array(hkl)):       #can't be all zeros!
2882                    hkl = textureData['PFhkl']
2883                Obj.SetValue('%d %d %d'%(hkl[0],hkl[1],hkl[2]))
2884                textureData['PFhkl'] = hkl
2885            else:
2886                try:
2887                    xyz = [float(Saxis[i]) for i in range(3)]
2888                except (ValueError,IndexError):
2889                    xyz = textureData['PFxyz']
2890                if not np.any(np.array(xyz)):       #can't be all zeros!
2891                    xyz = textureData['PFxyz']
2892                Obj.SetValue('%3.1f %3.1f %3.1f'%(xyz[0],xyz[1],xyz[2]))
2893                textureData['PFxyz'] = xyz
2894            G2plt.PlotTexture(G2frame,data)
2895
2896        # UpdateTexture executable starts here
2897        G2frame.dataFrame.SetStatusText('')
2898        generalData = data['General']       
2899        SGData = generalData['SGData']
2900        try:
2901            textureData = generalData['SH Texture']
2902        except KeyError:            #fix old files!
2903            textureData = generalData['SH Texture'] = {'Order':0,'Model':'cylindrical',
2904                'Sample omega':[False,0.0],'Sample chi':[False,0.0],'Sample phi':[False,0.0],
2905                'SH Coeff':[False,{}],'SHShow':False,'PFhkl':[0,0,1],
2906                'PFxyz':[0,0,1.],'PlotType':'Pole figure'}
2907        if 'SHShow' not in textureData:     #another fix
2908            textureData.update({'SHShow':False,'PFhkl':[0,0,1],'PFxyz':[0,0,1.],'PlotType':'Pole figure'})
2909        try:                        #another fix!
2910            x = textureData['PlotType']
2911        except KeyError:
2912            textureData.update({'PFxyz':[0,0,1.],'PlotType':'Pole figure'})
2913        shModels = ['cylindrical','none','shear - 2/m','rolling - mmm']
2914        SamSym = dict(zip(shModels,['0','-1','2/m','mmm']))
2915        if generalData['doPawley'] and G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Sequental results'):
2916            G2frame.dataFrame.RefineTexture.Enable(True)
2917        shAngles = ['omega','chi','phi']
2918        if Texture.GetSizer():
2919            Texture.GetSizer().Clear(True)
2920        mainSizer = wx.BoxSizer(wx.VERTICAL)
2921        titleSizer = wx.BoxSizer(wx.HORIZONTAL)
2922        titleSizer.Add(wx.StaticText(Texture,-1,'Spherical harmonics texture data for '+PhaseName+':'),0,wx.ALIGN_CENTER_VERTICAL)
2923        titleSizer.Add(wx.StaticText(Texture,-1,
2924            ' Texture Index J = %7.3f'%(G2lat.textureIndex(textureData['SH Coeff'][1]))),
2925            0,wx.ALIGN_CENTER_VERTICAL)
2926        mainSizer.Add(titleSizer,0)
2927        mainSizer.Add((0,5),0)
2928        shSizer = wx.FlexGridSizer(1,6,5,5)
2929        shSizer.Add(wx.StaticText(Texture,-1,'Texture model: '),0,wx.ALIGN_CENTER_VERTICAL)
2930        shModel = wx.ComboBox(Texture,-1,value=textureData['Model'],choices=shModels,
2931            style=wx.CB_READONLY|wx.CB_DROPDOWN)
2932        shModel.Bind(wx.EVT_COMBOBOX,OnShModel)
2933        shSizer.Add(shModel,0,wx.ALIGN_CENTER_VERTICAL)
2934        shSizer.Add(wx.StaticText(Texture,-1,'  Harmonic order: '),0,wx.ALIGN_CENTER_VERTICAL)
2935        shOrder = wx.ComboBox(Texture,-1,value=str(textureData['Order']),choices=[str(2*i) for i in range(18)],
2936            style=wx.CB_READONLY|wx.CB_DROPDOWN)
2937        shOrder.Bind(wx.EVT_COMBOBOX,OnShOrder)
2938        shSizer.Add(shOrder,0,wx.ALIGN_CENTER_VERTICAL)
2939        shRef = wx.CheckBox(Texture,-1,label=' Refine texture?')
2940        shRef.SetValue(textureData['SH Coeff'][0])
2941        shRef.Bind(wx.EVT_CHECKBOX, OnSHRefine)
2942        shSizer.Add(shRef,0,wx.ALIGN_CENTER_VERTICAL)
2943        shShow = wx.CheckBox(Texture,-1,label=' Show coeff.?')
2944        shShow.SetValue(textureData['SHShow'])
2945        shShow.Bind(wx.EVT_CHECKBOX, OnSHShow)
2946        shSizer.Add(shShow,0,wx.ALIGN_CENTER_VERTICAL)
2947        mainSizer.Add(shSizer,0,0)
2948        mainSizer.Add((0,5),0)
2949        PTSizer = wx.FlexGridSizer(2,4,5,5)
2950        PTSizer.Add(wx.StaticText(Texture,-1,' Texture plot type: '),0,wx.ALIGN_CENTER_VERTICAL)
2951        choices = ['Axial pole distribution','Pole figure','Inverse pole figure']           
2952        pfType = wx.ComboBox(Texture,-1,value=str(textureData['PlotType']),choices=choices,
2953            style=wx.CB_READONLY|wx.CB_DROPDOWN)
2954        pfType.Bind(wx.EVT_COMBOBOX,OnPfType)
2955        PTSizer.Add(pfType,0,wx.ALIGN_CENTER_VERTICAL)
2956        if 'Axial' not in textureData['PlotType']:
2957            PTSizer.Add(wx.StaticText(Texture,-1,' Projection type: '),0,wx.ALIGN_CENTER_VERTICAL)
2958            projSel = wx.ComboBox(Texture,-1,value=G2frame.Projection,choices=['equal area','stereographic','3D display'],
2959                style=wx.CB_READONLY|wx.CB_DROPDOWN)
2960            projSel.Bind(wx.EVT_COMBOBOX,OnProjSel)
2961            PTSizer.Add(projSel,0,wx.ALIGN_CENTER_VERTICAL)
2962        if textureData['PlotType'] in ['Pole figure','Axial pole distribution']:
2963            PTSizer.Add(wx.StaticText(Texture,-1,' Pole figure HKL: '),0,wx.ALIGN_CENTER_VERTICAL)
2964            PH = textureData['PFhkl']
2965            pfVal = wx.TextCtrl(Texture,-1,'%d %d %d'%(PH[0],PH[1],PH[2]),style=wx.TE_PROCESS_ENTER)
2966        else:
2967            PTSizer.Add(wx.StaticText(Texture,-1,' Inverse pole figure XYZ: '),0,wx.ALIGN_CENTER_VERTICAL)
2968            PX = textureData['PFxyz']
2969            pfVal = wx.TextCtrl(Texture,-1,'%3.1f %3.1f %3.1f'%(PX[0],PX[1],PX[2]),style=wx.TE_PROCESS_ENTER)
2970        pfVal.Bind(wx.EVT_TEXT_ENTER,OnPFValue)
2971        pfVal.Bind(wx.EVT_KILL_FOCUS,OnPFValue)
2972        PTSizer.Add(pfVal,0,wx.ALIGN_CENTER_VERTICAL)
2973        if 'Axial' not in textureData['PlotType']:
2974            PTSizer.Add(wx.StaticText(Texture,-1,' Color scheme'),0,wx.ALIGN_CENTER_VERTICAL)
2975            choice = [m for m in mpl.cm.datad.keys() if not m.endswith("_r")]
2976            choice.sort()
2977            colorSel = wx.ComboBox(Texture,-1,value=G2frame.ContourColor,choices=choice,
2978                style=wx.CB_READONLY|wx.CB_DROPDOWN)
2979            colorSel.Bind(wx.EVT_COMBOBOX,OnColorSel)
2980            PTSizer.Add(colorSel,0,wx.ALIGN_CENTER_VERTICAL)       
2981        mainSizer.Add(PTSizer,0,wx.ALIGN_CENTER_VERTICAL)
2982        mainSizer.Add((0,5),0)
2983        if textureData['SHShow']:
2984            mainSizer.Add(wx.StaticText(Texture,-1,'Spherical harmonic coefficients: '),0,wx.ALIGN_CENTER_VERTICAL)
2985            mainSizer.Add((0,5),0)
2986            ODFSizer = wx.FlexGridSizer(2,8,2,2)
2987            ODFIndx = {}
2988            ODFkeys = textureData['SH Coeff'][1].keys()
2989            ODFkeys.sort()
2990            for item in ODFkeys:
2991                ODFSizer.Add(wx.StaticText(Texture,-1,item),0,wx.ALIGN_CENTER_VERTICAL)
2992                ODFval = wx.TextCtrl(Texture,wx.ID_ANY,'%8.3f'%(textureData['SH Coeff'][1][item]),style=wx.TE_PROCESS_ENTER)
2993                ODFIndx[ODFval.GetId()] = item
2994                ODFval.Bind(wx.EVT_TEXT_ENTER,OnODFValue)
2995                ODFval.Bind(wx.EVT_KILL_FOCUS,OnODFValue)
2996                ODFSizer.Add(ODFval,0,wx.ALIGN_CENTER_VERTICAL)
2997            mainSizer.Add(ODFSizer,0,wx.ALIGN_CENTER_VERTICAL)
2998            mainSizer.Add((0,5),0)
2999        mainSizer.Add((0,5),0)
3000        mainSizer.Add(wx.StaticText(Texture,-1,'Sample orientation angles: '),0,wx.ALIGN_CENTER_VERTICAL)
3001        mainSizer.Add((0,5),0)
3002        angSizer = wx.BoxSizer(wx.HORIZONTAL)
3003        angIndx = {}
3004        valIndx = {}
3005        for item in ['Sample omega','Sample chi','Sample phi']:
3006            angRef = wx.CheckBox(Texture,-1,label=item+': ')
3007            angRef.SetValue(textureData[item][0])
3008            angIndx[angRef.GetId()] = item
3009            angRef.Bind(wx.EVT_CHECKBOX, OnAngRef)
3010            angSizer.Add(angRef,0,wx.ALIGN_CENTER_VERTICAL)
3011            angVal = wx.TextCtrl(Texture,wx.ID_ANY,'%8.2f'%(textureData[item][1]),style=wx.TE_PROCESS_ENTER)
3012            valIndx[angVal.GetId()] = item
3013            angVal.Bind(wx.EVT_TEXT_ENTER,OnAngValue)
3014            angVal.Bind(wx.EVT_KILL_FOCUS,OnAngValue)
3015            angSizer.Add(angVal,0,wx.ALIGN_CENTER_VERTICAL)
3016            angSizer.Add((5,0),0)
3017        mainSizer.Add(angSizer,0,wx.ALIGN_CENTER_VERTICAL)
3018        Texture.SetSizer(mainSizer,True)
3019        if G2frame.dataFrame.PhaseUserSize is None:
3020            mainSizer.Fit(G2frame.dataFrame)
3021            Size = mainSizer.GetMinSize()
3022            Size[0] += 40
3023            Size[1] = max(Size[1],250) + 35
3024            Texture.SetSize(Size)
3025            Texture.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
3026            Size[1] = min(Size[1],450)
3027            G2frame.dataFrame.setSizePosLeft(Size)
3028        else:
3029            Size = G2frame.dataFrame.PhaseUserSize
3030            Texture.SetSize(G2frame.dataFrame.GetClientSize())
3031            Texture.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
3032            G2frame.dataFrame.Update()
3033################################################################################
3034##### DData routines - GUI stuff in GSASIIddataGUI.py
3035################################################################################
3036       
3037    def OnHklfAdd(event):
3038        UseList = data['Histograms']
3039        keyList = UseList.keys()
3040        TextList = []
3041        if G2frame.PatternTree.GetCount():
3042            item, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)
3043            while item:
3044                name = G2frame.PatternTree.GetItemText(item)
3045                if name not in keyList and 'HKLF' in name:
3046                    TextList.append(name)
3047                item, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)                       
3048            dlg = wx.MultiChoiceDialog(G2frame, 'Which new data to use?', 'Use data', TextList, wx.CHOICEDLG_STYLE)
3049            try:
3050                if dlg.ShowModal() == wx.ID_OK:
3051                    result = dlg.GetSelections()
3052                    for i in result:
3053                        histoName = TextList[i]
3054                        UseList[histoName] = {'Histogram':histoName,'Show':False,'Scale':[1.0,True],
3055                            'Babinet':{'BabA':[0.0,False],'BabU':[0.0,False]},
3056                            'Extinction':['Lorentzian','None',
3057                            {'Tbar':0.1,'Cos2TM':0.955,'Eg':[1.e-10,False],'Es':[1.e-10,False],'Ep':[1.e-10,False]},]}                       
3058                        wx.BeginBusyCursor()
3059                        UpdateHKLFdata(histoName)
3060                        wx.EndBusyCursor()
3061                    data['Histograms'] = UseList
3062                    wx.CallAfter(G2ddG.UpdateDData,G2frame,DData,data)
3063            finally:
3064                dlg.Destroy()
3065               
3066    def UpdateHKLFdata(histoName):
3067        generalData = data['General']
3068        Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,histoName)
3069        reflData = G2frame.PatternTree.GetItemPyData(Id)[1]
3070        SGData = generalData['SGData']
3071        Cell = generalData['Cell'][1:7]
3072        G,g = G2lat.cell2Gmat(Cell)
3073        for ref in reflData:
3074            H = ref[:3]
3075            ref[4] = np.sqrt(1./G2lat.calc_rDsq2(H,G))
3076            iabsnt,ref[3],ref[11],ref[12] = G2spc.GenHKLf(H,SGData)
3077        G2frame.PatternTree.SetItemPyData(Id,[histoName,reflData])
3078       
3079    def OnPwdrAdd(event):
3080        generalData = data['General']
3081        SGData = generalData['SGData']
3082        UseList = data['Histograms']
3083        newList = []
3084        NShkl = len(G2spc.MustrainNames(SGData))
3085        NDij = len(G2spc.HStrainNames(SGData))
3086        keyList = UseList.keys()
3087        TextList = ['All PWDR']
3088        if G2frame.PatternTree.GetCount():
3089            item, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)
3090            while item:
3091                name = G2frame.PatternTree.GetItemText(item)
3092                if name not in keyList and 'PWDR' in name:
3093                    TextList.append(name)
3094                item, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)
3095            dlg = wx.MultiChoiceDialog(G2frame, 'Which new data to use?', 'Use data', TextList, wx.CHOICEDLG_STYLE)
3096            try:
3097                if dlg.ShowModal() == wx.ID_OK:
3098                    result = dlg.GetSelections()
3099                    for i in result: newList.append(TextList[i])
3100                    if 'All PWDR' in newList:
3101                        newList = TextList[1:]
3102                    for histoName in newList:
3103                        pId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,histoName)
3104                        UseList[histoName] = {'Histogram':histoName,'Show':False,
3105                            'Scale':[1.0,False],'Pref.Ori.':['MD',1.0,False,[0,0,1],0,{}],
3106                            'Size':['isotropic',[1.,1.,1.],[False,False,False],[0,0,1],
3107                                [1.,1.,1.,0.,0.,0.],6*[False,]],
3108                            'Mustrain':['isotropic',[1000.0,1000.0,1.0],[False,False,False],[0,0,1],
3109                                NShkl*[0.01,],NShkl*[False,]],
3110                            'HStrain':[NDij*[0.0,],NDij*[False,]],                         
3111                            'Extinction':[0.0,False],'Babinet':{'BabA':[0.0,False],'BabU':[0.0,False]}}
3112                        refList = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,pId,'Reflection Lists'))
3113                        refList[generalData['Name']] = []                       
3114                    data['Histograms'] = UseList
3115                    wx.CallAfter(G2ddG.UpdateDData,G2frame,DData,data)
3116            finally:
3117                dlg.Destroy()
3118       
3119    def OnDataDelete(event):
3120        UseList = data['Histograms']
3121        keyList = ['All',]+UseList.keys()
3122        keyList.sort()
3123        DelList = []
3124        if UseList:
3125            DelList = []
3126            dlg = wx.MultiChoiceDialog(G2frame, 
3127                'Which histogram to delete from this phase?', 'Delete histogram', 
3128                keyList, wx.CHOICEDLG_STYLE)
3129            try:
3130                if dlg.ShowModal() == wx.ID_OK:
3131                    result = dlg.GetSelections()
3132                    for i in result: 
3133                        DelList.append(keyList[i])
3134                    if 'All' in DelList:
3135                        DelList = keyList[1:]
3136                    for i in DelList:
3137                        del UseList[i]
3138                    wx.CallAfter(G2ddG.UpdateDData,G2frame,DData,data)
3139            finally:
3140                dlg.Destroy()
3141               
3142################################################################################
3143##### Rigid bodies
3144################################################################################
3145
3146    def FillRigidBodyGrid(refresh=True):
3147        '''Fill the Rigid Body Phase information tab page.
3148        Note that the page is a ScrolledWindow, not a Grid
3149        '''
3150        def OnThermSel(event):       #needs to be seen by VecRbSizer!
3151            Obj = event.GetEventObject()
3152            RBObj = Indx[Obj.GetId()]
3153            val = Obj.GetValue()
3154            if val == 'Uiso':
3155                RBObj['ThermalMotion'][0] = 'Uiso'
3156            elif val == 'T':
3157                RBObj['ThermalMotion'][0] = 'T'
3158            elif val == 'TL':
3159                RBObj['ThermalMotion'][0] = 'TL'
3160            elif val == 'TLS':
3161                RBObj['ThermalMotion'][0] = 'TLS'
3162            wx.CallAfter(FillRigidBodyGrid,True)
3163           
3164        def ThermDataSizer(RBObj):
3165           
3166            def OnThermval(event):
3167                Obj = event.GetEventObject()
3168                item = Indx[Obj.GetId()]
3169                try:
3170                    val = float(Obj.GetValue())
3171                    RBObj['ThermalMotion'][1][item] = val
3172                except ValueError:
3173                    pass
3174                Obj.SetValue('%8.4f'%(RBObj['ThermalMotion'][1][item]))
3175                G2plt.PlotStructure(G2frame,data)
3176               
3177            def OnTLSRef(event):
3178                Obj = event.GetEventObject()
3179                item = Indx[Obj.GetId()]
3180                RBObj['ThermalMotion'][2][item] = Obj.GetValue()
3181           
3182            thermSizer = wx.FlexGridSizer(1,9,5,5)
3183            model = RBObj['ThermalMotion']
3184            if model[0] == 'Uiso':
3185                names = ['Uiso',]
3186            elif 'T' in model[0]:
3187                names = ['T11','T22','T33','T12','T13','T23']
3188            if 'L' in model[0]:
3189                names += ['L11','L22','L33','L12','L13','L23']
3190            if 'S' in model[0]:
3191                names += ['S12','S13','S21','S23','S31','S32','SAA','SBB']
3192            for i,name in enumerate(names):
3193                thermSizer.Add(wx.StaticText(RigidBodies,-1,name+': '),0,wx.ALIGN_CENTER_VERTICAL)
3194                thermVal = wx.TextCtrl(RigidBodies,-1,value='%8.4f'%(model[1][i]),
3195                    style=wx.TE_PROCESS_ENTER)
3196                thermVal.Bind(wx.EVT_TEXT_ENTER,OnThermval)
3197                thermVal.Bind(wx.EVT_KILL_FOCUS,OnThermval)
3198                Indx[thermVal.GetId()] = i
3199                thermSizer.Add(thermVal)
3200                Tcheck = wx.CheckBox(RigidBodies,-1,'Refine?')
3201                Tcheck.Bind(wx.EVT_CHECKBOX,OnTLSRef)
3202                Tcheck.SetValue(model[2][i])
3203                Indx[Tcheck.GetId()] = i
3204                thermSizer.Add(Tcheck,0,wx.ALIGN_CENTER_VERTICAL)
3205            return thermSizer
3206           
3207        def LocationSizer(RBObj,rbType):
3208           
3209            def OnOrigRef(event):
3210                RBObj['Orig'][1] = Ocheck.GetValue()
3211             
3212            def OnOrienRef(event):
3213                RBObj['Orient'][1] = Qcheck.GetValue()
3214               
3215            def OnOrigX(event):
3216                Obj = event.GetEventObject()
3217                item = Indx[Obj.GetId()]
3218                try:
3219                    val = float(Obj.GetValue())
3220                    RBObj['Orig'][0][item] = val
3221                    Obj.SetValue('%8.5f'%(val))
3222                    newXYZ = G2mth.UpdateRBXYZ(Bmat,RBObj,RBData,rbType)[0]
3223                    for i,id in enumerate(RBObj['Ids']):
3224                        data['Atoms'][AtLookUp[id]][cx:cx+3] = newXYZ[i]
3225                    data['Drawing']['Atoms'] = []
3226                    UpdateDrawAtoms(atomStyle)
3227                    G2plt.PlotStructure(G2frame,data)
3228                except ValueError:
3229                    pass
3230               
3231            def OnOrien(event):
3232                Obj = event.GetEventObject()
3233                item = Indx[Obj.GetId()]
3234                A,V = G2mth.Q2AVdeg(RBObj['Orient'][0])
3235                V = np.inner(Bmat,V)
3236                try:
3237                    val = float(Obj.GetValue())
3238                    if item:
3239                        V[item-1] = val
3240                    else:
3241                        A = val
3242                    Obj.SetValue('%8.5f'%(val))
3243                    V = np.inner(Amat,V)
3244                    Q = G2mth.AVdeg2Q(A,V)
3245                    if not any(Q):
3246                        raise ValueError
3247                    RBObj['Orient'][0] = Q
3248                    newXYZ = G2mth.UpdateRBXYZ(Bmat,RBObj,RBData,rbType)[0]
3249                    for i,id in enumerate(RBObj['Ids']):
3250                        data['Atoms'][AtLookUp[id]][cx:cx+3] = newXYZ[i]
3251                    data['Drawing']['Atoms'] = []
3252                    UpdateDrawAtoms(atomStyle)
3253                    G2plt.PlotStructure(G2frame,data)
3254                except ValueError:
3255                    pass
3256               
3257            topSizer = wx.FlexGridSizer(2,6,5,5)
3258            Orig = RBObj['Orig'][0]
3259            Orien,OrienV = G2mth.Q2AVdeg(RBObj['Orient'][0])
3260            Orien = [Orien,]
3261            Orien.extend(OrienV/nl.norm(OrienV))
3262            topSizer.Add(wx.StaticText(RigidBodies,-1,'Origin x,y,z:'),0,wx.ALIGN_CENTER_VERTICAL)
3263            for ix,x in enumerate(Orig):
3264                origX = wx.TextCtrl(RigidBodies,-1,value='%8.5f'%(x),style=wx.TE_PROCESS_ENTER)
3265                origX.Bind(wx.EVT_TEXT_ENTER,OnOrigX)
3266                origX.Bind(wx.EVT_KILL_FOCUS,OnOrigX)
3267                Indx[origX.GetId()] = ix
3268                topSizer.Add(origX,0,wx.ALIGN_CENTER_VERTICAL)
3269            topSizer.Add((5,0),)
3270            Ocheck = wx.CheckBox(RigidBodies,-1,'Refine?')
3271            Ocheck.Bind(wx.EVT_CHECKBOX,OnOrigRef)
3272            Ocheck.SetValue(RBObj['Orig'][1])
3273            topSizer.Add(Ocheck,0,wx.ALIGN_CENTER_VERTICAL)
3274            topSizer.Add(wx.StaticText(RigidBodies,-1,'Rotation angle, vector:'),0,wx.ALIGN_CENTER_VERTICAL)
3275            for ix,x in enumerate(Orien):
3276                orien = wx.TextCtrl(RigidBodies,-1,value='%8.4f'%(x),style=wx.TE_PROCESS_ENTER)
3277                orien.Bind(wx.EVT_TEXT_ENTER,OnOrien)
3278                orien.Bind(wx.EVT_KILL_FOCUS,OnOrien)
3279                Indx[orien.GetId()] = ix
3280                topSizer.Add(orien,0,wx.ALIGN_CENTER_VERTICAL)
3281            Qcheck = wx.ComboBox(RigidBodies,-1,value='',choices=[' ','A','AV'],
3282                style=wx.CB_READONLY|wx.CB_DROPDOWN)
3283            Qcheck.Bind(wx.EVT_COMBOBOX,OnOrienRef)
3284            Qcheck.SetValue(RBObj['Orient'][1])
3285            topSizer.Add(Qcheck)
3286            return topSizer
3287                         
3288        def ResrbSizer(RBObj):
3289            G2frame.dataFrame.SetStatusText('NB: Rotation vector is in crystallographic space')
3290             
3291            def OnTorsionRef(event):
3292                Obj = event.GetEventObject()
3293                item = Indx[Obj.GetId()]
3294                RBObj['Torsions'][item][1] = Obj.GetValue()               
3295               
3296            def OnTorsion(event):
3297                Obj = event.GetEventObject()
3298                item = Indx[Obj.GetId()]
3299                try:
3300                    val = float(Obj.GetValue())
3301                    RBObj['Torsions'][item][0] = val
3302                    newXYZ = G2mth.UpdateRBXYZ(Bmat,RBObj,RBData,'Residue')[0]
3303                    for i,id in enumerate(RBObj['Ids']):
3304                        data['Atoms'][AtLookUp[id]][cx:cx+3] = newXYZ[i]
3305                except ValueError:
3306                    pass
3307                Obj.SetValue("%10.3f"%(RBObj['Torsions'][item][0]))               
3308                data['Drawing']['Atoms'] = []
3309                UpdateDrawAtoms(atomStyle)
3310                drawAtoms.ClearSelection()
3311                G2plt.PlotStructure(G2frame,data)
3312               
3313            def OnDelResRB(event):
3314                Obj = event.GetEventObject()
3315                RBId = Indx[Obj.GetId()]
3316                RBData['Residue'][RBId]['useCount'] -= 1
3317                RBObjs = data['RBModels']['Residue']
3318                for rbObj in RBObjs:
3319                    if RBId == rbObj['RBId']:
3320                       data['RBModels']['Residue'].remove(rbObj)                 
3321                G2plt.PlotStructure(G2frame,data)
3322                wx.CallAfter(FillRigidBodyGrid,True)
3323               
3324            resrbSizer = wx.BoxSizer(wx.VERTICAL)
3325            resrbSizer.Add(wx.StaticText(RigidBodies,-1,120*'-'))
3326            topLine = wx.BoxSizer(wx.HORIZONTAL)
3327            topLine.Add(wx.StaticText(RigidBodies,-1,
3328                'Name: '+RBObj['RBname']+RBObj['numChain']+'   '),0,wx.ALIGN_CENTER_VERTICAL)
3329            rbId = RBObj['RBId']
3330            delRB = wx.CheckBox(RigidBodies,-1,'Delete?')
3331            delRB.Bind(wx.EVT_CHECKBOX,OnDelResRB)
3332            Indx[delRB.GetId()] = rbId
3333            topLine.Add(delRB,0,wx.ALIGN_CENTER_VERTICAL)
3334            resrbSizer.Add(topLine)
3335            resrbSizer.Add(LocationSizer(RBObj,'Residue'))
3336            resrbSizer.Add(wx.StaticText(RigidBodies,-1,'Torsions:'),0,wx.ALIGN_CENTER_VERTICAL)
3337            torSizer = wx.FlexGridSizer(1,6,5,5)
3338            for itors,tors in enumerate(RBObj['Torsions']):
3339                torSizer.Add(wx.StaticText(RigidBodies,-1,'Torsion '+'%d'%(itors)),0,wx.ALIGN_CENTER_VERTICAL)
3340                torsTxt = wx.TextCtrl(RigidBodies,-1,value='%.3f'%(tors[0]),style=wx.TE_PROCESS_ENTER)
3341                torsTxt.Bind(wx.EVT_TEXT_ENTER,OnTorsion)
3342                torsTxt.Bind(wx.EVT_KILL_FOCUS,OnTorsion)
3343                Indx[torsTxt.GetId()] = itors
3344                torSizer.Add(torsTxt)
3345                torCheck = wx.CheckBox(RigidBodies,-1,'Refine?')
3346                torCheck.Bind(wx.EVT_CHECKBOX,OnTorsionRef)
3347                torCheck.SetValue(tors[1])
3348                Indx[torCheck.GetId()] = itors
3349                torSizer.Add(torCheck,0,wx.ALIGN_CENTER_VERTICAL)
3350            resrbSizer.Add(torSizer)
3351            tchoice = ['None','Uiso','T','TL','TLS']
3352            thermSizer = wx.BoxSizer(wx.HORIZONTAL)
3353            thermSizer.Add(wx.StaticText(RigidBodies,-1,'Rigid body thermal motion model: '),0,wx.ALIGN_CENTER_VERTICAL)
3354            thermSel = wx.ComboBox(RigidBodies,-1,value=RBObj['ThermalMotion'][0],choices=tchoice,
3355                style=wx.CB_READONLY|wx.CB_DROPDOWN)
3356            Indx[thermSel.GetId()] = RBObj
3357            thermSel.Bind(wx.EVT_COMBOBOX,OnThermSel)
3358            thermSizer.Add(thermSel,0,wx.ALIGN_CENTER_VERTICAL)
3359            thermSizer.Add(wx.StaticText(RigidBodies,-1,' Units: T A^2, L deg^2, S deg-A'),0,wx.ALIGN_CENTER_VERTICAL)
3360            resrbSizer.Add(thermSizer)
3361            if RBObj['ThermalMotion'][0] != 'None':
3362                resrbSizer.Add(ThermDataSizer(RBObj))
3363            return resrbSizer
3364           
3365        def VecrbSizer(RBObj):
3366            G2frame.dataFrame.SetStatusText('NB: Rotation vector is in crystallographic space')
3367                   
3368            def OnDelVecRB(event):
3369                Obj = event.GetEventObject()
3370                RBId = Indx[Obj.GetId()]
3371                RBData['Vector'][RBId]['useCount'] -= 1               
3372                RBObjs = data['RBModels']['Vector']
3373                for rbObj in RBObjs:
3374                    if RBId == rbObj['RBId']:
3375                       data['RBModels']['Vector'].remove(rbObj)                 
3376                G2plt.PlotStructure(G2frame,data)
3377                wx.CallAfter(FillRigidBodyGrid,True)
3378             
3379            vecrbSizer = wx.BoxSizer(wx.VERTICAL)
3380            vecrbSizer.Add(wx.StaticText(RigidBodies,-1,120*'-'))
3381            topLine = wx.BoxSizer(wx.HORIZONTAL)
3382            topLine.Add(wx.StaticText(RigidBodies,-1,
3383                'Name: '+RBObj['RBname']+'   '),0,wx.ALIGN_CENTER_VERTICAL)
3384            rbId = RBObj['RBId']
3385            delRB = wx.CheckBox(RigidBodies,-1,'Delete?')
3386            delRB.Bind(wx.EVT_CHECKBOX,OnDelVecRB)
3387            Indx[delRB.GetId()] = rbId
3388            topLine.Add(delRB,0,wx.ALIGN_CENTER_VERTICAL)
3389            vecrbSizer.Add(topLine)
3390            vecrbSizer.Add(LocationSizer(RBObj,'Vector'))
3391            tchoice = ['None','Uiso','T','TL','TLS']
3392            thermSizer = wx.BoxSizer(wx.HORIZONTAL)
3393            thermSizer.Add(wx.StaticText(RigidBodies,-1,'Rigid body thermal motion model: '),0,wx.ALIGN_CENTER_VERTICAL)
3394            thermSel = wx.ComboBox(RigidBodies,-1,value=RBObj['ThermalMotion'][0],choices=tchoice,
3395                style=wx.CB_READONLY|wx.CB_DROPDOWN)
3396            Indx[thermSel.GetId()] = RBObj
3397            thermSel.Bind(wx.EVT_COMBOBOX,OnThermSel)
3398            thermSizer.Add(thermSel,0,wx.ALIGN_CENTER_VERTICAL)
3399            thermSizer.Add(wx.StaticText(RigidBodies,-1,' Units: T A^2, L deg^2, S deg-A'),0,wx.ALIGN_CENTER_VERTICAL)
3400            vecrbSizer.Add(thermSizer)
3401            if RBObj['ThermalMotion'][0] != 'None':
3402                vecrbSizer.Add(ThermDataSizer(RBObj))
3403            return vecrbSizer               
3404       
3405        # FillRigidBodyGrid executable code starts here
3406        if refresh:
3407            RigidBodies.DestroyChildren()
3408        AtLookUp = G2mth.FillAtomLookUp(data['Atoms'])
3409        general = data['General']
3410        cx = general['AtomPtrs'][0]
3411        Amat,Bmat = G2lat.cell2AB(general['Cell'][1:7])
3412        RBData = G2frame.PatternTree.GetItemPyData(   
3413            G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Rigid bodies'))
3414        Indx = {}
3415        atomStyle = 'balls & sticks'
3416        if 'macro' in general['Type']:
3417            atomStyle = 'sticks'
3418        G2frame.dataFrame.SetStatusText('')
3419        mainSizer = wx.BoxSizer(wx.VERTICAL)
3420        if not data['RBModels']:
3421            mainSizer.Add((5,5),0)
3422            mainSizer.Add(wx.StaticText(RigidBodies,-1,'No rigid body models:'),0,wx.ALIGN_CENTER_VERTICAL)
3423            mainSizer.Add((5,5),0)
3424        if 'Residue' in data['RBModels']:
3425            mainSizer.Add((5,5),0)
3426            mainSizer.Add(wx.StaticText(RigidBodies,-1,'Residue rigid bodies:'),0,wx.ALIGN_CENTER_VERTICAL)
3427            mainSizer.Add((5,5),0)
3428            for RBObj in data['RBModels']['Residue']:
3429                mainSizer.Add(ResrbSizer(RBObj))
3430        if 'Vector' in data['RBModels']:
3431            mainSizer.Add((5,5),0)
3432            mainSizer.Add(wx.StaticText(RigidBodies,-1,'Vector rigid bodies:'),0,wx.ALIGN_CENTER_VERTICAL)
3433            mainSizer.Add((5,5),0)
3434            for RBObj in data['RBModels']['Vector']:
3435                mainSizer.Add(VecrbSizer(RBObj))
3436
3437        RigidBodies.SetSizer(mainSizer)
3438        if G2frame.dataFrame.PhaseUserSize is None:
3439            mainSizer.FitInside(G2frame.dataFrame)
3440            Size = mainSizer.GetMinSize()
3441            Size[0] += 40
3442            Size[1] = max(Size[1],290) + 35
3443            RigidBodies.SetSize(Size)
3444            RigidBodies.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
3445            Size[1] = min(Size[1],450)
3446            G2frame.dataFrame.setSizePosLeft(Size)
3447        else:
3448            Size = G2frame.dataFrame.PhaseUserSize
3449            RigidBodies.SetSize(Size)
3450            RigidBodies.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
3451            G2frame.dataFrame.Update()
3452
3453    def OnRBCopyParms(event):
3454        RBObjs = []
3455        for rbType in ['Vector','Residue']:           
3456            RBObjs += data['RBModels'].get(rbType,[])
3457        if not len(RBObjs):
3458            print '**** ERROR - no rigid bodies defined ****'
3459            return
3460        if len(RBObjs) == 1:
3461            print '**** INFO - only one rigid body defined; nothing to copy to ****'
3462            return
3463        Source = []
3464        sourceRB = {}
3465        for RBObj in RBObjs:
3466            Source.append(RBObj['RBname'])
3467        dlg = wx.SingleChoiceDialog(G2frame,'Select source','Copy rigid body parameters',Source)
3468        if dlg.ShowModal() == wx.ID_OK:
3469            sel = dlg.GetSelection()
3470            name = Source[sel]
3471            for item in ['Orig','Orient','ThermalMotion']: 
3472                sourceRB.update({item:RBObjs[sel][item],})
3473        dlg.Destroy()
3474        if not sourceRB:
3475            return
3476        dlg = wx.MultiChoiceDialog(G2frame,'Select targets','Copy rigid body parameters',Source)
3477        if dlg.ShowModal() == wx.ID_OK:
3478            sel = dlg.GetSelections()
3479            for x in sel:
3480                RBObjs[x].update(copy.copy(sourceRB))
3481        G2plt.PlotStructure(G2frame,data)
3482        wx.CallAfter(FillRigidBodyGrid(True))
3483               
3484    def OnRBAssign(event):
3485       
3486        G2frame.dataFrame.SetStatusText('')
3487        RBData = G2frame.PatternTree.GetItemPyData(   
3488            G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Rigid bodies'))
3489        rbNames = {}
3490        for rbVec in RBData['Vector']:
3491            if rbVec != 'AtInfo':
3492                rbNames[RBData['Vector'][rbVec]['RBname']] =['Vector',rbVec]
3493        for rbRes in RBData['Residue']:
3494            if rbRes != 'AtInfo':
3495                rbNames[RBData['Residue'][rbRes]['RBname']] = ['Residue',rbRes]
3496        if not rbNames:
3497            print '**** ERROR - no rigid bodies defined ****'
3498            return
3499        general = data['General']
3500        Amat,Bmat = G2lat.cell2AB(general['Cell'][1:7])
3501        cx,ct = general['AtomPtrs'][:2]
3502        atomData = data['Atoms']
3503        Indx = {}
3504        atInd = [-1,-1,-1]
3505        data['testRBObj'] = {}
3506           
3507        def Draw():
3508           
3509            def OnOk(event):
3510                rbType = data['testRBObj']['rbType']
3511                RBObjs = data['RBModels'].get(rbType,[])
3512                rbObj = data['testRBObj']['rbObj']
3513                rbId = rbObj['RBId']
3514                newXYZ = G2mth.UpdateRBXYZ(Bmat,rbObj,RBData,rbType)[0]
3515                Ids = []
3516                dmax = 0.0
3517                oldXYZ = G2mth.getAtomXYZ(atomData,cx)
3518                for xyz in newXYZ:
3519                    dist = G2mth.GetXYZDist(xyz,oldXYZ,Amat)
3520                    dmax = max(dmax,np.min(dist))
3521                    id = np.argmin(dist)
3522                    Ids.append(atomData[id][-1])
3523                    atomData[id][cx:cx+3] = xyz
3524                if dmax > 0.5:
3525                    print '**** WARNING - some atoms not found or misidentified ****'
3526                    print '****           check torsion angles & try again      ****'
3527                    OkBtn.SetLabel('Not Ready')
3528                    OkBtn.Enable(False)
3529                    return
3530                rbObj['Ids'] = Ids
3531                rbObj['ThermalMotion'] = ['None',[0. for i in range(21)],[False for i in range(21)]] #type,values,flags
3532                rbObj['RBname'] += ':'+str(RBData[rbType][rbId]['useCount'])
3533                RBObjs.append(rbObj)
3534                data['RBModels'][rbType] = RBObjs
3535                RBData[rbType][rbId]['useCount'] += 1
3536                del data['testRBObj']
3537                G2plt.PlotStructure(G2frame,data)
3538                FillRigidBodyGrid(True)
3539               
3540            def OnCancel(event):
3541                del data['testRBObj']
3542                FillRigidBodyGrid(True)
3543               
3544            def OnRBSel(event):
3545                selection = rbSel.GetValue()
3546                rbType,rbId = rbNames[selection]
3547                data['testRBObj']['rbAtTypes'] = RBData[rbType][rbId]['rbTypes']
3548                data['testRBObj']['AtInfo'] = RBData[rbType]['AtInfo']
3549                data['testRBObj']['rbType'] = rbType
3550                data['testRBObj']['rbData'] = RBData
3551                data['testRBObj']['Sizers'] = {}
3552                rbRef = RBData[rbType][rbId]['rbRef']
3553                data['testRBObj']['rbRef'] = rbRef
3554                refType = []
3555                refName = []
3556                for ref in rbRef[:3]:
3557                    reftype = data['testRBObj']['rbAtTypes'][ref]
3558                    refType.append(reftype)
3559                    refName.append(reftype+' '+str(rbRef[0]))
3560                atNames,AtNames = fillAtNames(refType,atomData,ct)
3561                data['testRBObj']['atNames'] = atNames
3562                data['testRBObj']['AtNames'] = AtNames
3563                data['testRBObj']['rbObj'] = {'Orig':[[0,0,0],False],
3564                    'Orient':[[0.,0.,0.,1.],' '],'Ids':[],'RBId':rbId,'Torsions':[],
3565                    'numChain':'','RBname':RBData[rbType][rbId]['RBname']}
3566                data['testRBObj']['torAtms'] = []               
3567                for item in RBData[rbType][rbId].get('rbSeq',[]):
3568                    data['testRBObj']['rbObj']['Torsions'].append([item[2],False])
3569                    data['testRBObj']['torAtms'].append([-1,-1,-1])
3570                Draw()
3571               
3572            def fillAtNames(refType,atomData,ct):
3573                atNames = [{},{},{}]
3574                AtNames = {}
3575                for iatm,atom in enumerate(atomData):
3576                    AtNames[atom[ct-1]] = iatm
3577                    for i,reftype in enumerate(refType):
3578                        if atom[ct] == reftype:
3579                            atNames[i][atom[ct-1]] = iatm
3580                return atNames,AtNames
3581               
3582            def OnAtOrigPick(event):
3583                Obj = event.GetEventObject()
3584                item = Indx[Obj.GetId()]
3585                atName = Obj.GetValue()
3586                rbType = data['testRBObj']['rbType']
3587                atInd[0] = atNames[item][atName]
3588                if 'Vector' in rbType:
3589                    rbObj = data['testRBObj']['rbObj']
3590                    rbId = rbObj['RBId']
3591                    rbRef = data['testRBObj']['rbRef']
3592                    rbXYZ = -RBData[rbType][rbId]['rbXYZ']
3593                    nref = atNames[item][atName]
3594                    Oxyz = np.inner(Bmat,np.array(rbXYZ[rbRef[0]]))
3595                    Nxyz = np.array(atomData[nref][cx:cx+3])
3596                    Orig = Nxyz-Oxyz
3597                    data['testRBObj']['rbObj']['Orig'][0] = Orig   
3598                else:
3599                    Orig = atomData[atNames[item][atName]][cx:cx+3]
3600                    data['testRBObj']['rbObj']['Orig'][0] = Orig
3601                for x,item in zip(Orig,Xsizers):
3602                    item.SetLabel('%10.5f'%(x))
3603                G2plt.PlotStructure(G2frame,data)
3604               
3605            def OnAtQPick(event):
3606                Obj = event.GetEventObject()
3607                item = Indx[Obj.GetId()]
3608                atName = Obj.GetValue()
3609                atInd[item] = atNames[item][atName]
3610                if any([x<0 for x in atInd]):
3611                    return
3612                OkBtn.SetLabel('OK')
3613                OkBtn.Enable(True)
3614                rbType = data['testRBObj']['rbType']
3615                rbObj = data['testRBObj']['rbObj']
3616                rbId = rbObj['RBId']
3617                rbRef = data['testRBObj']['rbRef']
3618                rbXYZ = RBData[rbType][rbId]['rbXYZ']
3619                rbOrig = rbXYZ[rbRef[0]]
3620                VAR = rbXYZ[rbRef[1]]-rbOrig
3621                VBR = rbXYZ[rbRef[2]]-rbOrig
3622                if rbType == 'Vector':
3623                    Orig = np.array(atomData[atInd[0]][cx:cx+3])
3624                else:
3625                    Orig = np.array(data['testRBObj']['rbObj']['Orig'][0])               
3626                VAC = np.inner(Amat,np.array(atomData[atInd[1]][cx:cx+3])-Orig)
3627                VBC = np.inner(Amat,np.array(atomData[atInd[2]][cx:cx+3])-Orig)
3628                VCC = np.cross(VAR,VAC)
3629                QuatA = G2mth.makeQuat(VAR,VAC,VCC)[0]
3630                VAR = G2mth.prodQVQ(QuatA,VAR)
3631                VBR = G2mth.prodQVQ(QuatA,VBR)
3632                QuatB = G2mth.makeQuat(VBR,VBC,VAR)[0]
3633                QuatC = G2mth.prodQQ(QuatB,QuatA)
3634                data['testRBObj']['rbObj']['Orient'] = [QuatC,' ']
3635                for x,item in zip(QuatC,Osizers):
3636                    item.SetLabel('%10.4f'%(x))               
3637                if rbType == 'Vector':
3638                    Oxyz = np.inner(Bmat,G2mth.prodQVQ(QuatC,rbOrig))
3639                    Nxyz = np.array(atomData[atInd[0]][cx:cx+3])
3640                    Orig = Nxyz-Oxyz
3641                    data['testRBObj']['rbObj']['Orig'][0] = Orig
3642                    for x,item in zip(Orig,Xsizers):
3643                        item.SetLabel('%10.5f'%(x))
3644                G2plt.PlotStructure(G2frame,data)
3645               
3646            def OnTorAngle(event):
3647                OkBtn.SetLabel('OK')
3648                OkBtn.Enable(True)
3649                Obj = event.GetEventObject()
3650                [tor,torSlide] = Indx[Obj.GetId()]
3651                Tors = data['testRBObj']['rbObj']['Torsions'][tor]
3652                try:
3653                    value = float(Obj.GetValue())
3654                except ValueError:
3655                    value = Tors[0]
3656                Tors[0] = value
3657                Obj.SetValue('%8.3f'%(value))
3658                torSlide.SetValue(int(value*10))
3659                G2plt.PlotStructure(G2frame,data)
3660               
3661            def OnTorSlide(event):
3662                OkBtn.SetLabel('OK')
3663                OkBtn.Enable(True)
3664                Obj = event.GetEventObject()
3665                tor,ang = Indx[Obj.GetId()]
3666                Tors = data['testRBObj']['rbObj']['Torsions'][tor]
3667                val = float(Obj.GetValue())/10.
3668                Tors[0] = val
3669                ang.SetValue('%8.3f'%(val))
3670                G2plt.PlotStructure(G2frame,data)
3671
3672            if len(data['testRBObj']):
3673                G2plt.PlotStructure(G2frame,data)
3674                   
3675            RigidBodies.DestroyChildren()
3676            mainSizer = wx.BoxSizer(wx.VERTICAL)
3677            mainSizer.Add((5,5),0)
3678            if data['testRBObj']:
3679                Xsizers = []
3680                Osizers = []
3681                rbObj = data['testRBObj']['rbObj']
3682                rbName = rbObj['RBname']
3683                rbId = rbObj['RBId']
3684                Orig = rbObj['Orig'][0]
3685                Orien = rbObj['Orient'][0]
3686                rbRef = data['testRBObj']['rbRef']
3687                Torsions = rbObj['Torsions']
3688                refName = []
3689                for ref in rbRef:
3690                    refName.append(data['testRBObj']['rbAtTypes'][ref]+str(ref))
3691                atNames = data['testRBObj']['atNames']
3692                mainSizer.Add(wx.StaticText(RigidBodies,-1,'Locate rigid body : '+rbName),
3693                    0,wx.ALIGN_CENTER_VERTICAL)
3694                mainSizer.Add((5,5),0)
3695                OriSizer = wx.FlexGridSizer(1,5,5,5)
3696                OriSizer.Add(wx.StaticText(RigidBodies,-1,'Origin x,y,z: '),0,wx.ALIGN_CENTER_VERTICAL)
3697                for ix,x in enumerate(Orig):
3698                    origX = wx.StaticText(RigidBodies,-1,'%10.5f'%(x))
3699                    OriSizer.Add(origX,0,wx.ALIGN_CENTER_VERTICAL)
3700                    Xsizers.append(origX)
3701                OriSizer.Add((5,0),)
3702                if len(atomData):
3703                    choice = atNames[0].keys()
3704                    choice.sort()
3705                    data['testRBObj']['Sizers']['Xsizers'] = Xsizers
3706                OriSizer.Add(wx.StaticText(RigidBodies,-1,'Orientation quaternion: '),0,wx.ALIGN_CENTER_VERTICAL)
3707                for ix,x in enumerate(Orien):
3708                    orien = wx.StaticText(RigidBodies,-1,'%10.4f'%(x))
3709                    OriSizer.Add(orien,0,wx.ALIGN_CENTER_VERTICAL)
3710                    Osizers.append(orien)
3711                data['testRBObj']['Sizers']['Osizers'] = Osizers
3712                mainSizer.Add(OriSizer)
3713                mainSizer.Add((5,5),0)
3714                RefSizer = wx.FlexGridSizer(1,7,5,5)
3715                if len(atomData):
3716                    RefSizer.Add(wx.StaticText(RigidBodies,-1,'Location setting: Select match to'),0,wx.ALIGN_CENTER_VERTICAL)
3717                    for i in [0,1,2]:
3718                        choice = ['',]+atNames[i].keys()
3719                        choice.sort()
3720                        RefSizer.Add(wx.StaticText(RigidBodies,-1,' '+refName[i]+': '),0,wx.ALIGN_CENTER_VERTICAL)
3721                        atPick = wx.ComboBox(RigidBodies,-1,value='',
3722                            choices=choice[1:],style=wx.CB_READONLY|wx.CB_DROPDOWN)
3723                        if i:
3724                            atPick.Bind(wx.EVT_COMBOBOX, OnAtQPick)
3725                        else:
3726                            atPick.Bind(wx.EVT_COMBOBOX, OnAtOrigPick)                           
3727                        Indx[atPick.GetId()] = i
3728                        RefSizer.Add(atPick,0,wx.ALIGN_CENTER_VERTICAL)
3729                mainSizer.Add(RefSizer)
3730                mainSizer.Add((5,5),0)
3731                if Torsions:                   
3732                    AtNames = data['testRBObj']['AtNames']
3733                    rbAtTypes = data['testRBObj']['rbAtTypes']
3734                    rbSeq = RBData['Residue'][rbId]['rbSeq']
3735                    TorSizer = wx.FlexGridSizer(1,4)
3736                    TorSizer.AddGrowableCol(1,1)
3737                    for t,[torsion,seq] in enumerate(zip(Torsions,rbSeq)):
3738                        torName = ''
3739                        for item in [seq[0],seq[1],seq[3][0]]:
3740                            torName += data['testRBObj']['rbAtTypes'][item]+str(item)+' '
3741                        TorSizer.Add(wx.StaticText(RigidBodies,-1,'Side chain torsion for rb seq: '+torName),0,wx.ALIGN_CENTER_VERTICAL)
3742                        torSlide = wx.Slider(RigidBodies,style=wx.SL_HORIZONTAL)
3743                        torSlide.SetRange(0,3600)
3744                        torSlide.SetValue(int(torsion[0]*10.))
3745                        torSlide.Bind(wx.EVT_SLIDER, OnTorSlide)
3746                        TorSizer.Add(torSlide,1,wx.EXPAND|wx.RIGHT)
3747                        TorSizer.Add(wx.StaticText(RigidBodies,-1,' Angle: '),0,wx.ALIGN_CENTER_VERTICAL)
3748                        ang = wx.TextCtrl(RigidBodies,-1,value='%8.3f'%(torsion[0]),style=wx.TE_PROCESS_ENTER)
3749                        ang.Bind(wx.EVT_TEXT_ENTER,OnTorAngle)
3750                        ang.Bind(wx.EVT_KILL_FOCUS,OnTorAngle)
3751                        Indx[torSlide.GetId()] = [t,ang]
3752                        Indx[ang.GetId()] = [t,torSlide]
3753                        TorSizer.Add(ang,0,wx.ALIGN_CENTER_VERTICAL)                           
3754                    mainSizer.Add(TorSizer,1,wx.EXPAND|wx.RIGHT)
3755                else:
3756                    mainSizer.Add(wx.StaticText(RigidBodies,-1,'No side chain torsions'),0,wx.ALIGN_CENTER_VERTICAL)
3757            else:
3758                mainSizer.Add(wx.StaticText(RigidBodies,-1,'Assign rigid body:'),0,wx.ALIGN_CENTER_VERTICAL)
3759                mainSizer.Add((5,5),0)
3760                topSizer = wx.BoxSizer(wx.HORIZONTAL)
3761                topSizer.Add(wx.StaticText(RigidBodies,-1,'Select rigid body model'),0,wx.ALIGN_CENTER_VERTICAL)
3762                rbSel = wx.ComboBox(RigidBodies,-1,value='',choices=rbNames.keys(),
3763                    style=wx.CB_READONLY|wx.CB_DROPDOWN)
3764                rbSel.Bind(wx.EVT_COMBOBOX, OnRBSel)
3765                topSizer.Add((5,5),0)
3766                topSizer.Add(rbSel,0,wx.ALIGN_CENTER_VERTICAL)
3767                mainSizer.Add(topSizer)               
3768               
3769            OkBtn = wx.Button(RigidBodies,-1,"Not ready")
3770            OkBtn.Bind(wx.EVT_BUTTON, OnOk)
3771            OkBtn.Enable(False)
3772            CancelBtn = wx.Button(RigidBodies,-1,'Cancel')
3773            CancelBtn.Bind(wx.EVT_BUTTON, OnCancel)
3774            btnSizer = wx.BoxSizer(wx.HORIZONTAL)
3775            btnSizer.Add((20,20),1)
3776            btnSizer.Add(OkBtn)
3777            btnSizer.Add(CancelBtn)
3778            btnSizer.Add((20,20),1)
3779            mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
3780            RigidBodies.SetSizer(mainSizer)
3781            Size = mainSizer.Fit(RigidBodies)
3782            Size[0] += 40
3783            Size[1] = min(max(Size[1],290) + 35,560)
3784            RigidBodies.SetSize(Size)
3785            RigidBodies.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
3786            G2frame.dataFrame.setSizePosLeft(Size)
3787        Draw()
3788       
3789    def OnAutoFindResRB(event):
3790        RBData = G2frame.PatternTree.GetItemPyData(   
3791            G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Rigid bodies'))
3792        rbKeys = RBData['Residue'].keys()
3793        rbKeys.remove('AtInfo')
3794        if not len(rbKeys):
3795            print '**** ERROR - no residue rigid bodies are defined ****'
3796            return
3797        RBNames = [RBData['Residue'][k]['RBname'] for k in rbKeys]
3798        RBIds = dict(zip(RBNames,rbKeys))
3799        general = data['General']
3800        Amat,Bmat = G2lat.cell2AB(general['Cell'][1:7])
3801        Atoms = data['Atoms']
3802        AtLookUp = G2mth.FillAtomLookUp(Atoms)
3803        if 'macro' not in general['Type']:
3804            print '**** ERROR - this phase is not a macromolecule ****'
3805            return
3806        if not len(Atoms):
3807            print '**** ERROR - this phase has no atoms ****'
3808            return
3809        RBObjs = []
3810        cx,ct = general['AtomPtrs'][:2]
3811        iatm = 0
3812        wx.BeginBusyCursor()
3813        try:
3814            while iatm < len(Atoms):
3815                atom = Atoms[iatm]
3816                res = atom[1].strip()
3817                numChain = ' %s %s'%(atom[0],atom[2])
3818                if res not in RBIds or atom[ct-1] == 'OXT':
3819                    iatm += 1
3820                    continue        #skip for OXT, water molecules, etc.
3821                rbRes = RBData['Residue'][RBIds[res]]
3822                rbRef = rbRes['rbRef']
3823                VAR = rbRes['rbXYZ'][rbRef[1]]-rbRes['rbXYZ'][rbRef[0]]
3824                VBR = rbRes['rbXYZ'][rbRef[2]]-rbRes['rbXYZ'][rbRef[0]]
3825                rbObj = {'RBname':rbRes['RBname']+':'+str(rbRes['useCount']),'numChain':numChain}
3826                rbAtoms = []
3827                rbIds = []
3828                for iratm in range(len(rbRes['atNames'])):
3829                    rbAtoms.append(np.array(Atoms[iatm][cx:cx+3]))
3830                    rbIds.append(Atoms[iatm][20])
3831                    iatm += 1    #puts this at beginning of next residue?
3832                Orig = rbAtoms[rbRef[0]]
3833                rbObj['RBId'] = RBIds[res]
3834                rbObj['Ids'] = rbIds
3835                rbObj['Orig'] = [Orig,False]
3836#                print ' residue '+rbRes['RBname']+str(atom[0]).strip()+ \
3837#                    ' origin at: ','%.5f %.5f %.5f'%(Orig[0],Orig[1],Orig[2])
3838                VAC = np.inner(Amat,rbAtoms[rbRef[1]]-Orig)
3839                VBC = np.inner(Amat,rbAtoms[rbRef[2]]-Orig)
3840                VCC = np.cross(VAR,VAC)
3841                QuatA = G2mth.makeQuat(VAR,VAC,VCC)[0]
3842                VAR = G2mth.prodQVQ(QuatA,VAR)
3843                VBR = G2mth.prodQVQ(QuatA,VBR)
3844                QuatB = G2mth.makeQuat(VBR,VBC,VAR)[0]
3845                QuatC = G2mth.prodQQ(QuatB,QuatA)
3846                rbObj['Orient'] = [QuatC,' ']
3847                rbObj['ThermalMotion'] = ['None',[0. for i in range(21)],[False for i in range(21)]] #type,values,flags
3848                SXYZ = []
3849                TXYZ = []
3850                rbObj['Torsions'] = []
3851                for i,xyz in enumerate(rbRes['rbXYZ']):
3852                    SXYZ.append(G2mth.prodQVQ(QuatC,xyz))               
3853                    TXYZ.append(np.inner(Amat,rbAtoms[i]-Orig))
3854                for Oatm,Patm,x,Riders in rbRes['rbSeq']:
3855                    VBR = SXYZ[Oatm]-SXYZ[Patm]
3856                    VAR = SXYZ[Riders[0]]-SXYZ[Patm]
3857                    VAC = TXYZ[Riders[0]]-TXYZ[Patm]
3858                    QuatA,D = G2mth.makeQuat(VAR,VAC,VBR)
3859                    ang = 180.*D/np.pi
3860                    rbObj['Torsions'].append([ang,False])
3861                    for ride in Riders:
3862                        SXYZ[ride] = G2mth.prodQVQ(QuatA,SXYZ[ride]-SXYZ[Patm])+SXYZ[Patm]
3863                rbRes['useCount'] += 1
3864                RBObjs.append(rbObj)
3865            data['RBModels']['Residue'] = RBObjs
3866            for RBObj in RBObjs:
3867                newXYZ = G2mth.UpdateRBXYZ(Bmat,RBObj,RBData,'Residue')[0]
3868                for i,id in enumerate(RBObj['Ids']):
3869                    data['Atoms'][AtLookUp[id]][cx:cx+3] = newXYZ[i]
3870        finally:
3871            wx.EndBusyCursor()
3872        wx.CallAfter(FillRigidBodyGrid,True)
3873       
3874    def OnRBRemoveAll(event):
3875        data['RBModels']['Residue'] = []
3876        data['RBModels']['Vector'] = []
3877        RBData = G2frame.PatternTree.GetItemPyData(   
3878            G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Rigid bodies'))
3879        for RBType in ['Vector','Residue']:
3880            for rbId in RBData[RBType]:
3881                RBData[RBType][rbId]['useCount'] = 0       
3882        FillRigidBodyGrid(True)
3883       
3884    def OnGlobalResRBRef(event):
3885        RBObjs = data['RBModels']['Residue']
3886        names = ['Origin','Orient. angle','Full Orient.']
3887        nTor = 0
3888        for rbObj in RBObjs:
3889            nTor = max(nTor,len(rbObj['Torsions']))
3890        names += ['Torsion '+str(i) for i in range(nTor)]
3891        dlg = wx.MultiChoiceDialog(G2frame,'Select','Refinement controls',names)
3892        if dlg.ShowModal() == wx.ID_OK:
3893            sel = dlg.GetSelections()
3894            parms = []
3895            for x in sel:
3896                parms.append(names[x])
3897            wx.BeginBusyCursor()
3898            try:
3899                for rbObj in RBObjs:
3900                    if 'Origin' in parms:
3901                        rbObj['Orig'][1] = True
3902                    else:
3903                        rbObj['Orig'][1] = False
3904                    if 'Full Orient.' in parms:
3905                        rbObj['Orient'][1] = 'AV'
3906                    elif 'Orient. angle' in parms:
3907                        rbObj['Orient'][1] = 'A'
3908                    else:
3909                        rbObj['Orient'][1] = ' '
3910                    for i in range(len(rbObj['Torsions'])):
3911                        if 'Torsion '+str(i) in parms:
3912                            rbObj['Torsions'][i][1] = True
3913                        else:
3914                            rbObj['Torsions'][i][1] = False           
3915            finally:
3916                wx.EndBusyCursor()
3917            FillRigidBodyGrid()
3918                       
3919
3920################################################################################
3921##### Pawley routines
3922################################################################################
3923
3924    def FillPawleyReflectionsGrid():
3925        def KeyEditPawleyGrid(event):
3926            colList = G2frame.PawleyRefl.GetSelectedCols()
3927            PawleyPeaks = data['Pawley ref']
3928            if event.GetKeyCode() == wx.WXK_RETURN:
3929                event.Skip(True)
3930            elif event.GetKeyCode() == wx.WXK_CONTROL:
3931                event.Skip(True)
3932            elif event.GetKeyCode() == wx.WXK_SHIFT:
3933                event.Skip(True)
3934            elif colList:
3935                G2frame.PawleyRefl.ClearSelection()
3936                key = event.GetKeyCode()
3937                for col in colList:
3938                    if PawleyTable.GetTypeName(0,col) == wg.GRID_VALUE_BOOL:
3939                        if key == 89: #'Y'
3940                            for row in range(PawleyTable.GetNumberRows()): PawleyPeaks[row][col]=True
3941                        elif key == 78:  #'N'
3942                            for row in range(PawleyTable.GetNumberRows()): PawleyPeaks[row][col]=False
3943                        FillPawleyReflectionsGrid()
3944           
3945        # FillPawleyReflectionsGrid executable starts here
3946        G2frame.dataFrame.SetStatusText('')                       
3947        if 'Pawley ref' in data:
3948            PawleyPeaks = data['Pawley ref']                       
3949            rowLabels = []
3950            for i in range(len(PawleyPeaks)): rowLabels.append(str(i))
3951            colLabels = ['h','k','l','mul','d','refine','Fsq(hkl)','sig(Fsq)']
3952            Types = 4*[wg.GRID_VALUE_LONG,]+[wg.GRID_VALUE_FLOAT+':10,4',wg.GRID_VALUE_BOOL,]+ \
3953                2*[wg.GRID_VALUE_FLOAT+':10,2',]
3954            PawleyTable = G2gd.Table(PawleyPeaks,rowLabels=rowLabels,colLabels=colLabels,types=Types)
3955            G2frame.PawleyRefl.SetTable(PawleyTable, True)
3956            G2frame.PawleyRefl.Bind(wx.EVT_KEY_DOWN, KeyEditPawleyGrid)                 
3957            for r in range(G2frame.PawleyRefl.GetNumberRows()):
3958                for c in range(G2frame.PawleyRefl.GetNumberCols()):
3959                    if c in [5,6]:
3960                        G2frame.PawleyRefl.SetReadOnly(r,c,isReadOnly=False)
3961                    else:
3962                        G2frame.PawleyRefl.SetCellStyle(r,c,VERY_LIGHT_GREY,True)
3963            G2frame.PawleyRefl.SetMargins(0,0)
3964            G2frame.PawleyRefl.AutoSizeColumns(False)
3965            if G2frame.dataFrame.PhaseUserSize is None:
3966                G2frame.dataFrame.setSizePosLeft([500,300])
3967            else:
3968                G2frame.dataFrame.Update()
3969                   
3970    def OnPawleyLoad(event):
3971        generalData = data['General']
3972        dmin = generalData['Pawley dmin']
3973        cell = generalData['Cell'][1:7]
3974        A = G2lat.cell2A(cell)
3975        SGData = generalData['SGData']
3976        HKLd = np.array(G2lat.GenHLaue(dmin,SGData,A))
3977        PawleyPeaks = []
3978        wx.BeginBusyCursor()
3979        try:
3980            for h,k,l,d in HKLd:
3981                ext,mul = G2spc.GenHKLf([h,k,l],SGData)[:2]
3982                if not ext:
3983                    mul *= 2        #for powder multiplicity
3984                    PawleyPeaks.append([h,k,l,mul,d,False,100.0,1.0])
3985        finally:
3986            wx.EndBusyCursor()
3987        data['Pawley ref'] = PawleyPeaks
3988        FillPawleyReflectionsGrid()
3989       
3990    def OnPawleyEstimate(event):
3991        try:
3992            Refs = data['Pawley ref']
3993            Histograms = data['Histograms']
3994        except KeyError:
3995            print '**** Error - no histograms defined for this phase ****'
3996            return
3997        HistoNames = Histograms.keys()
3998        PatternId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,HistoNames[0])
3999        xdata = G2frame.PatternTree.GetItemPyData(PatternId)[1]
4000        Inst = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId,'Instrument Parameters'))[0]
4001        Sample = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId,'Sample Parameters'))
4002        wave = G2mth.getWave(Inst)
4003        posCorr = Inst['Zero'][1]
4004        const = 9.e-2/(np.pi*Sample['Gonio. radius'])                  #shifts in microns
4005       
4006        wx.BeginBusyCursor()
4007        try:
4008            for ref in Refs:
4009                pos = 2.0*asind(wave/(2.0*ref[4]))
4010                if 'Bragg' in Sample['Type']:
4011                    pos -= const*(4.*Sample['Shift'][0]*cosd(pos/2.0)+ \
4012                        Sample['Transparency'][0]*sind(pos)*100.0)            #trans(=1/mueff) in cm
4013                else:               #Debye-Scherrer - simple but maybe not right
4014                    pos -= const*(Sample['DisplaceX'][0]*cosd(pos)+Sample['DisplaceY'][0]*sind(pos))
4015                indx = np.searchsorted(xdata[0],pos)
4016                try:
4017                    FWHM = max(0.001,G2pwd.getFWHM(pos,Inst))/2.
4018                    dx = xdata[0][indx+1]-xdata[0][indx]
4019                    ref[6] = FWHM*(xdata[1][indx]-xdata[4][indx])*cosd(pos/2.)**3/dx
4020                    Lorenz = 1./(2.*sind(xdata[0][indx]/2.)**2*cosd(xdata[0][indx]/2.))           #Lorentz correction
4021                    pola,dIdPola = G2pwd.Polarization(Inst['Polariz.'][1],xdata[0][indx],Inst['Azimuth'][1])
4022                    ref[6] /= (Lorenz*pola*ref[3])
4023                except IndexError:
4024                    pass
4025        finally:
4026            wx.EndBusyCursor()
4027        FillPawleyReflectionsGrid()
4028
4029    def OnPawleyUpdate(event):
4030        try:
4031            Refs = data['Pawley ref']
4032            Histograms = data['Histograms']
4033        except KeyError:
4034            print '**** Error - no histograms defined for this phase ****'
4035            return
4036        HistoNames = Histograms.keys()
4037        PatternId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,HistoNames[0])
4038        refData = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId,'Reflection Lists'))[PhaseName]
4039
4040        wx.BeginBusyCursor()
4041        try:
4042            for iref,ref in enumerate(Refs):
4043                try:
4044                    if refData[iref][9] < 0.:
4045                        ref[6] = abs(refData[iref][9])
4046                        ref[7] = 1.0
4047                except IndexError:
4048                    pass
4049        finally:
4050            wx.EndBusyCursor()
4051        FillPawleyReflectionsGrid()
4052                           
4053    def OnPawleyDelete(event):          #doesn't work
4054        dlg = wx.MessageDialog(G2frame,'Do you really want to delete selected Pawley reflections?','Delete', 
4055            wx.YES_NO | wx.ICON_QUESTION)
4056        try:
4057            result = dlg.ShowModal()
4058            if result == wx.ID_YES: 
4059                Refs = data['Pawley ref']
4060                Ind = G2frame.PawleyRefl.GetSelectedRows()
4061                Ind.sort()
4062                Ind.reverse()
4063                for ind in Ind:
4064                    Refs = np.delete(Refs,ind,0)
4065                data['Pawley ref'] = Refs
4066                FillPawleyReflectionsGrid()
4067        finally:
4068            dlg.Destroy()
4069
4070################################################################################
4071##### Fourier routines
4072################################################################################
4073
4074    def FillMapPeaksGrid():
4075                       
4076        def RowSelect(event):
4077            r,c =  event.GetRow(),event.GetCol()
4078            if r < 0 and c < 0:
4079                if MapPeaks.IsSelection():
4080                    MapPeaks.ClearSelection()
4081                else:
4082                    for row in range(MapPeaks.GetNumberRows()):
4083                        MapPeaks.SelectRow(row,True)
4084                   
4085            elif c < 0:                   #only row clicks
4086                if event.ControlDown():                   
4087                    if r in MapPeaks.GetSelectedRows():
4088                        MapPeaks.DeselectRow(r)
4089                    else:
4090                        MapPeaks.SelectRow(r,True)
4091                elif event.ShiftDown():
4092                    indxs = MapPeaks.GetSelectedRows()
4093                    MapPeaks.ClearSelection()
4094                    ibeg = 0
4095                    if indxs:
4096                        ibeg = indxs[-1]
4097                    for row in range(ibeg,r+1):
4098                        MapPeaks.SelectRow(row,True)
4099                else:
4100                    MapPeaks.ClearSelection()
4101                    MapPeaks.SelectRow(r,True)
4102            elif r < 0:                 #a column pick
4103                mapPeaks = data['Map Peaks']
4104                c =  event.GetCol()
4105                if colLabels[c] == 'mag':
4106                    mapPeaks = G2mth.sortArray(mapPeaks,c,reverse=True)
4107                elif colLabels[c] in ['x','y','z','dzero']:
4108                    mapPeaks = G2mth.sortArray(mapPeaks,c)
4109                else:
4110                    return
4111                data['Map Peaks'] = mapPeaks
4112                wx.CallAfter(FillMapPeaksGrid)
4113            G2plt.PlotStructure(G2frame,data)                   
4114           
4115        if G2frame.dataFrame.PhaseUserSize is None:
4116            G2frame.dataFrame.setSizePosLeft([450,300])
4117        else:
4118            G2frame.dataFrame.Update()
4119        G2frame.dataFrame.SetStatusText('')
4120        if 'Map Peaks' in data:
4121            G2frame.dataFrame.SetStatusText('Select mag or dzero columns to sort')
4122            mapPeaks = data['Map Peaks']                       
4123            rowLabels = []
4124            for i in range(len(mapPeaks)): rowLabels.append(str(i))
4125            colLabels = ['mag','x','y','z','dzero']
4126            Types = 5*[wg.GRID_VALUE_FLOAT+':10,4',]
4127            G2frame.MapPeaksTable = G2gd.Table(mapPeaks,rowLabels=rowLabels,colLabels=colLabels,types=Types)
4128            MapPeaks.SetTable(G2frame.MapPeaksTable, True)
4129            MapPeaks.Bind(wg.EVT_GRID_LABEL_LEFT_CLICK, RowSelect)
4130            for r in range(MapPeaks.GetNumberRows()):
4131                for c in range(MapPeaks.GetNumberCols()):
4132                    MapPeaks.SetCellStyle(r,c,VERY_LIGHT_GREY,True)
4133            MapPeaks.SetMargins(0,0)
4134            MapPeaks.AutoSizeColumns(False)
4135                   
4136    def OnPeaksMove(event):
4137        if 'Map Peaks' in data:
4138            mapPeaks = np.array(data['Map Peaks'])
4139            peakMax = np.max(mapPeaks.T[0])
4140            Ind = MapPeaks.GetSelectedRows()
4141            for ind in Ind:
4142                mag,x,y,z,d = mapPeaks[ind]
4143                AtomAdd(x,y,z,'H',Name