source: trunk/GSASIIphsGUI.py @ 860

Last change on this file since 860 was 860, checked in by vondreele, 11 years ago

more fixes to rigid body stuff

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