source: trunk/GSASIIphsGUI.py @ 861

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

more rigid body stuff

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 209.4 KB
Line 
1# -*- coding: utf-8 -*-
2#GSASII - phase data display routines
3########### SVN repository information ###################
4# $Date: 2013-03-01 20:59:47 +0000 (Fri, 01 Mar 2013) $
5# $Author: vondreele $
6# $Revision: 861 $
7# $URL: trunk/GSASIIphsGUI.py $
8# $Id: GSASIIphsGUI.py 861 2013-03-01 20:59:47Z 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: 861 $")
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(atomStyle=''):
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        if atomStyle:
1674            for atom in atomData:
1675                atom[cs] = atomStyle
1676        Types = [wg.GRID_VALUE_STRING,wg.GRID_VALUE_STRING,]+3*[wg.GRID_VALUE_FLOAT+':10,5',]+ \
1677            [wg.GRID_VALUE_STRING,wg.GRID_VALUE_CHOICE+": ,lines,vdW balls,sticks,balls & sticks,ellipsoids,polyhedra",
1678            wg.GRID_VALUE_CHOICE+": ,type,name,number",wg.GRID_VALUE_STRING,wg.GRID_VALUE_STRING,]
1679        styleChoice = [' ','lines','vdW balls','sticks','balls & sticks','ellipsoids','polyhedra']
1680        labelChoice = [' ','type','name','number']
1681        colLabels = ['Name','Type','x','y','z','Sym Op','Style','Label','Color','I/A']
1682        if generalData['Type'] == 'macromolecular':
1683            colLabels = ['Residue','1-letter','Chain'] + colLabels
1684            Types = 3*[wg.GRID_VALUE_STRING,]+Types
1685            Types[8] = wg.GRID_VALUE_CHOICE+": ,lines,vdW balls,sticks,balls & sticks,ellipsoids,backbone,ribbons,schematic"
1686            styleChoice = [' ','lines','vdW balls','sticks','balls & sticks','ellipsoids','backbone','ribbons','schematic']
1687            labelChoice = [' ','type','name','number','residue','1-letter','chain']
1688            Types[9] = wg.GRID_VALUE_CHOICE+": ,type,name,number,residue,1-letter,chain"
1689#        elif generalData['Type'] == 'modulated':
1690#            Types += []
1691#            colLabels += []
1692
1693        def RefreshAtomGrid(event):
1694
1695            def SetChoice(name,c,n=0):
1696                choice = []
1697                for r in range(len(atomData)):
1698                    if n:
1699                        srchStr = str(atomData[r][c][:n])
1700                    else:
1701                        srchStr = str(atomData[r][c])
1702                    if srchStr not in choice:
1703                        if n:
1704                            choice.append(str(atomData[r][c][:n]))
1705                        else:
1706                            choice.append(str(atomData[r][c]))
1707                choice.sort()
1708
1709                dlg = wx.MultiChoiceDialog(G2frame,'Select',name,choice)
1710                if dlg.ShowModal() == wx.ID_OK:
1711                    sel = dlg.GetSelections()
1712                    parms = []
1713                    for x in sel:
1714                        parms.append(choice[x])
1715                    noSkip = False
1716                    drawAtoms.ClearSelection()
1717                    drawingData['selectedAtoms'] = []
1718                    for row in range(len(atomData)):
1719                        test = atomData[row][c]
1720                        if n:
1721                            test = test[:n]
1722                        if  test in parms:
1723                            drawAtoms.SelectRow(row,True)
1724                            drawingData['selectedAtoms'].append(row)
1725                    G2plt.PlotStructure(G2frame,data)                   
1726                dlg.Destroy()
1727               
1728            r,c =  event.GetRow(),event.GetCol()
1729            if r < 0 and c < 0:
1730                for row in range(drawAtoms.GetNumberRows()):
1731                    drawingData['selectedAtoms'].append(row)
1732                    drawAtoms.SelectRow(row,True)                   
1733            elif r < 0:                          #dclick on col label
1734                sel = -1
1735                Parms = False
1736                noSkip = True
1737                if drawAtoms.GetColLabelValue(c) == 'Style':
1738                    dlg = wx.SingleChoiceDialog(G2frame,'Select','Atom drawing style',styleChoice)
1739                    if dlg.ShowModal() == wx.ID_OK:
1740                        sel = dlg.GetSelection()
1741                        parms = styleChoice[sel]
1742                        for r in range(len(atomData)):
1743                            atomData[r][c] = parms
1744                            drawAtoms.SetCellValue(r,c,parms)
1745                        FindBondsDraw()
1746                        G2plt.PlotStructure(G2frame,data)
1747                    dlg.Destroy()
1748                elif drawAtoms.GetColLabelValue(c) == 'Label':
1749                    dlg = wx.SingleChoiceDialog(G2frame,'Select','Atom labelling style',labelChoice)
1750                    if dlg.ShowModal() == wx.ID_OK:
1751                        sel = dlg.GetSelection()
1752                        parms = labelChoice[sel]
1753                        for r in range(len(atomData)):
1754                            atomData[r][c] = parms
1755                            drawAtoms.SetCellValue(r,c,parms)
1756                    dlg.Destroy()                   
1757                elif drawAtoms.GetColLabelValue(c) == 'Color':
1758                    dlg = wx.ColourDialog(G2frame)
1759                    if dlg.ShowModal() == wx.ID_OK:
1760                        color = dlg.GetColourData().GetColour()
1761                        attr = wg.GridCellAttr()                #needs to be here - gets lost if outside loop!
1762                        attr.SetReadOnly(True)
1763                        attr.SetBackgroundColour(color)
1764                        for r in range(len(atomData)):
1765                            atomData[r][c] = color
1766                            drawingData['Atoms'][r][c] = color
1767                            drawAtoms.SetAttr(r,c,attr)
1768                        UpdateDrawAtoms()
1769                    dlg.Destroy()
1770                elif drawAtoms.GetColLabelValue(c) == 'Residue':
1771                    SetChoice('Residue',c,3)
1772                elif drawAtoms.GetColLabelValue(c) == '1-letter':
1773                    SetChoice('1-letter',c,1)
1774                elif drawAtoms.GetColLabelValue(c) == 'Chain':
1775                    SetChoice('Chain',c)
1776                elif drawAtoms.GetColLabelValue(c) == 'Name':
1777                    SetChoice('Name',c)
1778                elif drawAtoms.GetColLabelValue(c) == 'Sym Op':
1779                    SetChoice('Name',c)
1780                elif drawAtoms.GetColLabelValue(c) == 'Type':
1781                    SetChoice('Type',c)
1782                elif drawAtoms.GetColLabelValue(c) in ['x','y','z','I/A']:
1783                    drawAtoms.ClearSelection()
1784            else:
1785                if drawAtoms.GetColLabelValue(c) in ['Style','Label']:
1786                    atomData[r][c] = drawAtoms.GetCellValue(r,c)
1787                    FindBondsDraw()
1788                elif drawAtoms.GetColLabelValue(c) == 'Color':
1789                    dlg = wx.ColourDialog(G2frame)
1790                    if dlg.ShowModal() == wx.ID_OK:
1791                        color = dlg.GetColourData().GetColour()
1792                        attr = wg.GridCellAttr()                #needs to be here - gets lost if outside loop!
1793                        attr.SetReadOnly(True)
1794                        attr.SetBackgroundColour(color)
1795                        atomData[r][c] = color
1796                        drawingData['Atoms'][r][c] = color
1797                        drawAtoms.SetAttr(i,cs+2,attr)
1798                    dlg.Destroy()
1799                    UpdateDrawAtoms()
1800            G2plt.PlotStructure(G2frame,data)
1801                   
1802        def RowSelect(event):
1803            r,c =  event.GetRow(),event.GetCol()
1804            if r < 0 and c < 0:
1805                if drawAtoms.IsSelection():
1806                    drawAtoms.ClearSelection()
1807            elif c < 0:                   #only row clicks
1808                if event.ControlDown():                   
1809                    if r in drawAtoms.GetSelectedRows():
1810                        drawAtoms.DeselectRow(r)
1811                    else:
1812                        drawAtoms.SelectRow(r,True)
1813                elif event.ShiftDown():
1814                    indxs = drawAtoms.GetSelectedRows()
1815                    drawAtoms.ClearSelection()
1816                    ibeg = 0
1817                    if indxs:
1818                        ibeg = indxs[-1]
1819                    for row in range(ibeg,r+1):
1820                        drawAtoms.SelectRow(row,True)
1821                else:
1822                    drawAtoms.ClearSelection()
1823                    drawAtoms.SelectRow(r,True)               
1824            drawingData['selectedAtoms'] = []
1825            drawingData['selectedAtoms'] = drawAtoms.GetSelectedRows()
1826            G2plt.PlotStructure(G2frame,data)                   
1827               
1828        table = []
1829        rowLabels = []
1830        for i,atom in enumerate(drawingData['Atoms']):
1831            table.append(atom[:colLabels.index('I/A')+1])
1832            rowLabels.append(str(i))
1833
1834        atomTable = G2gd.Table(table,rowLabels=rowLabels,colLabels=colLabels,types=Types)
1835        drawAtoms.SetTable(atomTable, True)
1836        drawAtoms.SetMargins(0,0)
1837        drawAtoms.AutoSizeColumns(True)
1838        drawAtoms.SetColSize(colLabels.index('Style'),80)
1839        drawAtoms.SetColSize(colLabels.index('Color'),50)
1840        drawAtoms.Bind(wg.EVT_GRID_CELL_CHANGE, RefreshAtomGrid)
1841        drawAtoms.Bind(wg.EVT_GRID_LABEL_LEFT_DCLICK, RefreshAtomGrid)
1842        drawAtoms.Bind(wg.EVT_GRID_CELL_LEFT_DCLICK, RefreshAtomGrid)
1843        drawAtoms.Bind(wg.EVT_GRID_LABEL_LEFT_CLICK, RowSelect)
1844        for i,atom in enumerate(drawingData['Atoms']):
1845            attr = wg.GridCellAttr()                #needs to be here - gets lost if outside loop!
1846            attr.SetReadOnly(True)
1847            attr.SetBackgroundColour(atom[cs+2])
1848            drawAtoms.SetAttr(i,cs+2,attr)
1849            drawAtoms.SetCellValue(i,cs+2,'')
1850        indx = drawingData['selectedAtoms']
1851        if indx:
1852            for r in range(len(atomData)):
1853                if r in indx:
1854                    drawAtoms.SelectRow(r)
1855        for c in range(len(colLabels)):
1856           attr = wg.GridCellAttr()                #needs to be here - gets lost if outside loop!
1857           attr.SetReadOnly(True)
1858           attr.SetBackgroundColour(VERY_LIGHT_GREY)
1859           if colLabels[c] not in ['Style','Label','Color']:
1860                drawAtoms.SetColAttr(c,attr)
1861        G2frame.dataFrame.setSizePosLeft([600,300])
1862       
1863        FindBondsDraw()
1864        drawAtoms.ClearSelection()
1865        G2plt.PlotStructure(G2frame,data)
1866
1867    def DrawAtomStyle(event):
1868        indx = drawAtoms.GetSelectedRows()
1869        if indx:
1870            generalData = data['General']
1871            atomData = data['Drawing']['Atoms']
1872            cx,ct,cs,ci = data['Drawing']['atomPtrs']
1873            styleChoice = [' ','lines','vdW balls','sticks','balls & sticks','ellipsoids','polyhedra']
1874            if generalData['Type'] == 'macromolecular':
1875                styleChoice = [' ','lines','vdW balls','sticks','balls & sticks','ellipsoids',
1876                'backbone','ribbons','schematic']
1877            dlg = wx.SingleChoiceDialog(G2frame,'Select','Atom drawing style',styleChoice)
1878            if dlg.ShowModal() == wx.ID_OK:
1879                sel = dlg.GetSelection()
1880                parms = styleChoice[sel]
1881                for r in indx:
1882                    atomData[r][cs] = parms
1883                    drawAtoms.SetCellValue(r,cs,parms)
1884            dlg.Destroy()
1885            FindBondsDraw()
1886            drawAtoms.ClearSelection()
1887            G2plt.PlotStructure(G2frame,data)
1888
1889    def DrawAtomLabel(event):
1890        indx = drawAtoms.GetSelectedRows()
1891        if indx:
1892            generalData = data['General']
1893            atomData = data['Drawing']['Atoms']
1894            cx,ct,cs,ci = data['Drawing']['atomPtrs']
1895            styleChoice = [' ','type','name','number']
1896            if generalData['Type'] == 'macromolecular':
1897                styleChoice = [' ','type','name','number','residue','1-letter','chain']
1898            dlg = wx.SingleChoiceDialog(G2frame,'Select','Atom label style',styleChoice)
1899            if dlg.ShowModal() == wx.ID_OK:
1900                sel = dlg.GetSelection()
1901                parms = styleChoice[sel]
1902                for r in indx:
1903                    atomData[r][cs+1] = parms
1904                    drawAtoms.SetCellValue(r,cs+1,parms)
1905            dlg.Destroy()
1906            drawAtoms.ClearSelection()
1907            G2plt.PlotStructure(G2frame,data)
1908           
1909    def DrawAtomColor(event):
1910
1911        indx = drawAtoms.GetSelectedRows()
1912        if indx:
1913            if len(indx) > 1:
1914                G2frame.dataFrame.SetStatusText('Select Custom Color, change color, Add to Custom Colors, then OK')
1915            else:
1916                G2frame.dataFrame.SetStatusText('Change color, Add to Custom Colors, then OK')
1917            generalData = data['General']
1918            atomData = data['Drawing']['Atoms']
1919            cx,ct,cs,ci = data['Drawing']['atomPtrs']
1920            atmColors = []
1921            atmTypes = []
1922            for r in indx:
1923                if atomData[r][cs+2] not in atmColors:
1924                    atmColors.append(atomData[r][cs+2])
1925                    atmTypes.append(atomData[r][ct])
1926                    if len(atmColors) > 16:
1927                        break
1928            colors = wx.ColourData()
1929            colors.SetChooseFull(True)
1930            dlg = wx.ColourDialog(G2frame)
1931            if dlg.ShowModal() == wx.ID_OK:
1932                for i in range(len(atmColors)):                   
1933                    atmColors[i] = dlg.GetColourData().GetColour()
1934                colorDict = dict(zip(atmTypes,atmColors))
1935                for r in indx:
1936                    color = colorDict[atomData[r][ct]]
1937                    atomData[r][cs+2] = color
1938                    attr = wg.GridCellAttr()                #needs to be here - gets lost if outside loop!
1939                    attr.SetBackgroundColour(color)
1940                    drawAtoms.SetAttr(r,cs+2,attr)
1941                    data['Drawing']['Atoms'][r][cs+2] = color
1942            drawAtoms.ClearSelection()
1943            dlg.Destroy()
1944            G2frame.dataFrame.SetStatusText('')
1945            G2plt.PlotStructure(G2frame,data)
1946           
1947    def ResetAtomColors(event):
1948        generalData = data['General']
1949        atomData = data['Drawing']['Atoms']
1950        cx,ct,cs,ci = data['Drawing']['atomPtrs']
1951        for atom in atomData:           
1952            atNum = generalData['AtomTypes'].index(atom[ct])
1953            atom[cs+2] = list(generalData['Color'][atNum])
1954        UpdateDrawAtoms()
1955        drawAtoms.ClearSelection()
1956        G2plt.PlotStructure(G2frame,data)       
1957       
1958    def SetViewPoint(event):
1959        indx = drawAtoms.GetSelectedRows()
1960        if indx:
1961            atomData = data['Drawing']['Atoms']
1962            cx = data['Drawing']['atomPtrs'][0]
1963            data['Drawing']['viewPoint'] = [atomData[indx[0]][cx:cx+3],[indx[0],0]]
1964            drawAtoms.ClearSelection()                                  #do I really want to do this?
1965            G2plt.PlotStructure(G2frame,data)
1966           
1967    def noDuplicate(xyz,atomData):                  #be careful where this is used - it's slow
1968        cx = data['Drawing']['atomPtrs'][0]
1969        if True in [np.allclose(np.array(xyz),np.array(atom[cx:cx+3]),atol=0.0002) for atom in atomData]:
1970            return False
1971        else:
1972            return True
1973               
1974    def AddSymEquiv(event):
1975        indx = drawAtoms.GetSelectedRows()
1976        indx.sort()
1977        if indx:
1978            colLabels = [drawAtoms.GetColLabelValue(c) for c in range(drawAtoms.GetNumberCols())]
1979            cx = colLabels.index('x')
1980            cuia = colLabels.index('I/A')
1981            cuij = cuia+2
1982            atomData = data['Drawing']['Atoms']
1983            generalData = data['General']
1984            SGData = generalData['SGData']
1985            dlg = G2gd.SymOpDialog(G2frame,SGData,False,True)
1986            try:
1987                if dlg.ShowModal() == wx.ID_OK:
1988                    Inv,Cent,Opr,Cell,New,Force = dlg.GetSelection()
1989                    Cell = np.array(Cell)
1990                    cent = SGData['SGCen'][Cent]
1991                    M,T = SGData['SGOps'][Opr]
1992                    for ind in indx:
1993                        XYZ = np.array(atomData[ind][cx:cx+3])
1994                        XYZ = np.inner(M,XYZ)+T
1995                        if Inv:
1996                            XYZ = -XYZ
1997                        XYZ = XYZ+cent+Cell
1998                        if Force:
1999                            XYZ = G2spc.MoveToUnitCell(XYZ)
2000                        if noDuplicate(XYZ,atomData):
2001                            atom = copy.copy(atomData[ind])
2002                            atom[cx:cx+3] = XYZ
2003                            atomOp = atom[cx+3]
2004                            newOp = str(((Opr+1)+100*Cent)*(1-2*Inv))+'+'+ \
2005                                str(int(Cell[0]))+','+str(int(Cell[1]))+','+str(int(Cell[2]))                           
2006                            atom[cx+3] = G2spc.StringOpsProd(atomOp,newOp,SGData)
2007                            if atom[cuia] == 'A':
2008                                Uij = atom[cuij:cuij+6]
2009                                U = G2spc.Uij2U(Uij)
2010                                U = np.inner(np.inner(M,U),M)
2011                                Uij = G2spc.U2Uij(U)
2012                                atom[cuij:cuij+6] = Uij
2013                            atomData.append(atom)
2014            finally:
2015                dlg.Destroy()
2016            UpdateDrawAtoms()
2017            drawAtoms.ClearSelection()
2018            G2plt.PlotStructure(G2frame,data)
2019           
2020    def TransformSymEquiv(event):
2021        indx = drawAtoms.GetSelectedRows()
2022        indx.sort()
2023        if indx:
2024            atomData = data['Drawing']['Atoms']
2025            colLabels = [drawAtoms.GetColLabelValue(c) for c in range(drawAtoms.GetNumberCols())]
2026            cx = colLabels.index('x')
2027            cuia = colLabels.index('I/A')
2028            cuij = cuia+2
2029            atomData = data['Drawing']['Atoms']
2030            generalData = data['General']
2031            SGData = generalData['SGData']
2032            dlg = G2gd.SymOpDialog(G2frame,SGData,False,True)
2033            try:
2034                if dlg.ShowModal() == wx.ID_OK:
2035                    Inv,Cent,Opr,Cell,New,Force = dlg.GetSelection()
2036                    Cell = np.array(Cell)
2037                    cent = SGData['SGCen'][Cent]
2038                    M,T = SGData['SGOps'][Opr]
2039                    for ind in indx:
2040                        XYZ = np.array(atomData[ind][cx:cx+3])
2041                        XYZ = np.inner(M,XYZ)+T
2042                        if Inv:
2043                            XYZ = -XYZ
2044                        XYZ = XYZ+cent+Cell
2045                        if Force:
2046                            XYZ = G2spc.MoveToUnitCell(XYZ)
2047                        atom = atomData[ind]
2048                        atom[cx:cx+3] = XYZ
2049                        atomOp = atom[cx+3]
2050                        newOp = str(((Opr+1)+100*Cent)*(1-2*Inv))+'+'+ \
2051                            str(int(Cell[0]))+','+str(int(Cell[1]))+','+str(int(Cell[2]))
2052                        atom[cx+3] = G2spc.StringOpsProd(atomOp,newOp,SGData)
2053                        if atom[cuia] == 'A':
2054                            Uij = atom[cuij:cuij+6]
2055                            U = G2spc.Uij2U(Uij)
2056                            U = np.inner(np.inner(M,U),M)
2057                            Uij = G2spc.U2Uij(U)
2058                            atom[cuij:cuij+6] = Uij
2059                    data['Drawing']['Atoms'] = atomData
2060            finally:
2061                dlg.Destroy()
2062            UpdateDrawAtoms()
2063            drawAtoms.ClearSelection()
2064            G2plt.PlotStructure(G2frame,data)
2065           
2066    def FillCoordSphere(event):
2067        generalData = data['General']
2068        Amat,Bmat = G2lat.cell2AB(generalData['Cell'][1:7])
2069        radii = generalData['BondRadii']
2070        atomTypes = generalData['AtomTypes']
2071        try:
2072            indH = atomTypes.index('H')
2073            radii[indH] = 0.5
2074        except:
2075            pass           
2076        indx = drawAtoms.GetSelectedRows()
2077        if indx:
2078            indx.sort()
2079            atomData = data['Drawing']['Atoms']
2080            numAtoms = len(atomData)
2081            cx,ct,cs,ci = data['Drawing']['atomPtrs']
2082            generalData = data['General']
2083            SGData = generalData['SGData']
2084            cellArray = G2lat.CellBlock(1)
2085            wx.BeginBusyCursor()
2086            try:
2087                for ind in indx:
2088                    atomA = atomData[ind]
2089                    xyzA = np.array(atomA[cx:cx+3])
2090                    indA = atomTypes.index(atomA[ct])
2091                    for atomB in atomData[:numAtoms]:
2092                        indB = atomTypes.index(atomB[ct])
2093                        sumR = radii[indA]+radii[indB]
2094                        xyzB = np.array(atomB[cx:cx+3])
2095                        for xyz in cellArray+xyzB:
2096                            dist = np.sqrt(np.sum(np.inner(Amat,xyz-xyzA)**2))
2097                            if 0 < dist <= data['Drawing']['radiusFactor']*sumR:
2098                                if noDuplicate(xyz,atomData):
2099                                    oprB = atomB[cx+3]
2100                                    C = xyz-xyzB
2101                                    newOp = '1+'+str(int(round(C[0])))+','+str(int(round(C[1])))+','+str(int(round(C[2])))
2102                                    newAtom = atomB[:]
2103                                    newAtom[cx:cx+3] = xyz
2104                                    newAtom[cx+3] = G2spc.StringOpsProd(oprB,newOp,SGData)
2105                                    atomData.append(newAtom)
2106            finally:
2107                wx.EndBusyCursor()
2108            data['Drawing']['Atoms'] = atomData
2109            UpdateDrawAtoms()
2110            drawAtoms.ClearSelection()
2111            G2plt.PlotStructure(G2frame,data)
2112           
2113    def FillUnitCell(event):
2114        indx = drawAtoms.GetSelectedRows()
2115        indx.sort()
2116        if indx:
2117            atomData = data['Drawing']['Atoms']
2118            colLabels = [drawAtoms.GetColLabelValue(c) for c in range(drawAtoms.GetNumberCols())]
2119            cx = colLabels.index('x')
2120            cuia = colLabels.index('I/A')
2121            cuij = cuia+2
2122            generalData = data['General']
2123            SGData = generalData['SGData']
2124            wx.BeginBusyCursor()
2125            try:
2126                for ind in indx:
2127                    atom = atomData[ind]
2128                    XYZ = np.array(atom[cx:cx+3])
2129                    if atom[cuia] == 'A':
2130                        Uij = atom[cuij:cuij+6]
2131                        result = G2spc.GenAtom(XYZ,SGData,False,Uij,False)
2132                        for item in result:
2133                            atom = copy.copy(atomData[ind])
2134                            atom[cx:cx+3] = item[0]
2135                            atom[cx+3] = str(item[2])+'+' \
2136                                +str(item[3][0])+','+str(item[3][1])+','+str(item[3][2])
2137                            atom[cuij:cuij+6] = item[1]
2138                            Opp = G2spc.Opposite(item[0])
2139                            for xyz in Opp:
2140                                if noDuplicate(xyz,atomData):
2141                                    cell = np.asarray(np.rint(xyz-atom[cx:cx+3]),dtype=np.int32)
2142                                    cell = '1'+'+'+ \
2143                                        str(cell[0])+','+str(cell[1])+','+str(cell[2])
2144                                    atom[cx:cx+3] = xyz
2145                                    atom[cx+3] = G2spc.StringOpsProd(cell,atom[cx+3],SGData)
2146                                    atomData.append(atom[:])
2147                    else:
2148                        result = G2spc.GenAtom(XYZ,SGData,False,Move=False)
2149                        for item in result:
2150                            atom = copy.copy(atomData[ind])
2151                            atom[cx:cx+3] = item[0]
2152                            atom[cx+3] = str(item[1])+'+' \
2153                                +str(item[2][0])+','+str(item[2][1])+','+str(item[2][2])
2154                            Opp = G2spc.Opposite(item[0])
2155                            for xyz in Opp:
2156                                if noDuplicate(xyz,atomData):
2157                                    cell = np.asarray(np.rint(xyz-atom[cx:cx+3]),dtype=np.int32)
2158                                    cell = '1'+'+'+ \
2159                                        str(cell[0])+','+str(cell[1])+','+str(cell[2])
2160                                    atom[cx:cx+3] = xyz
2161                                    atom[cx+3] = G2spc.StringOpsProd(cell,atom[cx+3],SGData)
2162                                    atomData.append(atom[:])               
2163                    data['Drawing']['Atoms'] = atomData
2164            finally:
2165                wx.EndBusyCursor()
2166            UpdateDrawAtoms()
2167            drawAtoms.ClearSelection()
2168            G2plt.PlotStructure(G2frame,data)
2169           
2170    def FindBondsToo():                         #works but slow for large structures - keep as reference
2171        cx,ct,cs,ci = data['Drawing']['atomPtrs']
2172        atomData = data['Drawing']['Atoms']
2173        generalData = data['General']
2174        Amat,Bmat = G2lat.cell2AB(generalData['Cell'][1:7])
2175        radii = generalData['BondRadii']
2176        atomTypes = generalData['AtomTypes']
2177        try:
2178            indH = atomTypes.index('H')
2179            radii[indH] = 0.5
2180        except:
2181            pass           
2182        for atom in atomData:
2183            atom[-1] = []
2184        Atoms = []
2185        for i,atom in enumerate(atomData):
2186            Atoms.append([i,np.array(atom[cx:cx+3]),atom[cs],radii[atomTypes.index(atom[ct])]])
2187        for atomA in Atoms:
2188            if atomA[2] in ['lines','sticks','ellipsoids','balls & sticks','polyhedra']:
2189                for atomB in Atoms:                   
2190                    Dx = atomB[1]-atomA[1]
2191                    DX = np.inner(Amat,Dx)
2192                    dist = np.sqrt(np.sum(DX**2))
2193                    sumR = atomA[3]+atomB[3]
2194                    if 0.5 < dist <= 0.85*sumR:
2195                        i = atomA[0]
2196                        if atomA[2] == 'polyhedra':
2197                            atomData[i][-1].append(DX)
2198                        elif atomB[1] != 'polyhedra':
2199                            j = atomB[0]
2200                            atomData[i][-1].append(Dx*atomA[3]/sumR)
2201                            atomData[j][-1].append(-Dx*atomB[3]/sumR)
2202                   
2203    def FindBondsDraw():                    #uses numpy & masks - very fast even for proteins!
2204        import numpy.ma as ma
2205        cx,ct,cs,ci = data['Drawing']['atomPtrs']
2206        hydro = data['Drawing']['showHydrogen']
2207        atomData = data['Drawing']['Atoms']
2208        generalData = data['General']
2209        Amat,Bmat = G2lat.cell2AB(generalData['Cell'][1:7])
2210        radii = generalData['BondRadii']
2211        atomTypes = generalData['AtomTypes']
2212        try:
2213            indH = atomTypes.index('H')
2214            radii[indH] = 0.5
2215        except:
2216            pass           
2217        for atom in atomData:
2218            atom[-2] = []               #clear out old bonds/polyhedra
2219            atom[-1] = []
2220        Indx = range(len(atomData))
2221        Atoms = []
2222        Styles = []
2223        Radii = []
2224        for atom in atomData:
2225            Atoms.append(np.array(atom[cx:cx+3]))
2226            Styles.append(atom[cs])
2227            try:
2228                if not hydro and atom[ct] == 'H':
2229                    Radii.append(0.0)
2230                else:
2231                    Radii.append(radii[atomTypes.index(atom[ct])])
2232            except ValueError:          #changed atom type!
2233                Radii.append(0.20)
2234        Atoms = np.array(Atoms)
2235        Radii = np.array(Radii)
2236        IASR = zip(Indx,Atoms,Styles,Radii)
2237        for atomA in IASR:
2238            if atomA[2] in ['lines','sticks','ellipsoids','balls & sticks','polyhedra']:
2239                Dx = Atoms-atomA[1]
2240                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
2241                sumR = atomA[3]+Radii
2242                IndB = ma.nonzero(ma.masked_greater(dist-data['Drawing']['radiusFactor']*sumR,0.))                 #get indices of bonded atoms
2243                i = atomA[0]
2244                for j in IndB[0]:
2245                    if Styles[i] == 'polyhedra':
2246                        atomData[i][-2].append(np.inner(Amat,Dx[j]))
2247                    elif Styles[j] != 'polyhedra' and j > i:
2248                        atomData[i][-2].append(Dx[j]*Radii[i]/sumR[j])
2249                        atomData[j][-2].append(-Dx[j]*Radii[j]/sumR[j])
2250                if Styles[i] == 'polyhedra':
2251                    Bonds = atomData[i][-2]
2252                    Faces = []
2253                    if len(Bonds) > 2:
2254                        FaceGen = G2lat.uniqueCombinations(Bonds,3)     #N.B. this is a generator
2255                        for face in FaceGen:
2256                            vol = nl.det(face)
2257                            if abs(vol) > 1. or len(Bonds) == 3:
2258                                if vol < 0.:
2259                                    face = [face[0],face[2],face[1]]
2260                                face = np.array(face)
2261                                if not np.array([np.array(nl.det(face-bond))+0.0001 < 0 for bond in Bonds]).any():
2262                                    norm = np.cross(face[1]-face[0],face[2]-face[0])
2263                                    norm /= np.sqrt(np.sum(norm**2))
2264                                    Faces.append([face,norm])
2265                        atomData[i][-1] = Faces
2266                       
2267    def DrawAtomsDelete(event):   
2268        indx = drawAtoms.GetSelectedRows()
2269        indx.sort()
2270        if indx:
2271            atomData = data['Drawing']['Atoms']
2272            indx.reverse()
2273            for ind in indx:
2274                del atomData[ind]
2275            UpdateDrawAtoms()
2276            drawAtoms.ClearSelection()
2277            G2plt.PlotStructure(G2frame,data)
2278        event.StopPropagation()
2279       
2280    def OnReloadDrawAtoms(event):
2281        data['Drawing']['Atoms'] = []
2282        UpdateDrawAtoms()
2283        drawAtoms.ClearSelection()
2284        G2plt.PlotStructure(G2frame,data)
2285        event.StopPropagation()
2286       
2287    def DrawAtomsDeleteByIDs(IDs):
2288        atomData = data['Drawing']['Atoms']
2289        indx = G2mth.FindAtomIndexByIDs(atomData,IDs)
2290        indx.reverse()
2291        for ind in indx:
2292            del atomData[ind]
2293           
2294    def ChangeDrawAtomsByIDs(colName,IDs,value):
2295        atomData = data['Drawing']['Atoms']
2296        cx,ct,cs,ci = data['Drawing']['atomPtrs']
2297        if colName == 'Name':
2298            col = ct-1
2299        elif colName == 'Type':
2300            col = ct
2301        elif colName == 'I/A':
2302            col = cs
2303        indx = G2mth.FindAtomIndexByIDs(atomData,IDs)
2304        for ind in indx:
2305            atomData[ind][col] = value
2306               
2307    def OnDrawPlane(event):
2308        indx = drawAtoms.GetSelectedRows()
2309        if len(indx) < 4:
2310            print '**** ERROR - need 4+ atoms for plane calculation'
2311            return
2312        PlaneData = {}
2313        drawingData = data['Drawing']
2314        atomData = drawingData['Atoms']
2315        colLabels = [drawAtoms.GetColLabelValue(c) for c in range(drawAtoms.GetNumberCols())]
2316        cx = colLabels.index('x')
2317        cn = colLabels.index('Name')
2318        xyz = []
2319        for i,atom in enumerate(atomData):
2320            if i in indx:
2321                xyz.append([i,]+atom[cn:cn+2]+atom[cx:cx+3])
2322        generalData = data['General']
2323        PlaneData['Name'] = generalData['Name']
2324        PlaneData['Atoms'] = xyz
2325        PlaneData['Cell'] = generalData['Cell'][1:] #+ volume
2326        G2str.BestPlane(PlaneData)
2327       
2328    def OnDrawDistVP(event):
2329        # distance to view point
2330        indx = drawAtoms.GetSelectedRows()
2331        if not indx:
2332            print '***** ERROR - no atoms selected'
2333            return
2334        generalData = data['General']
2335        Amat,Bmat = G2lat.cell2AB(generalData['Cell'][1:7])           
2336        drawingData = data['Drawing']
2337        viewPt = np.array(drawingData['viewPoint'][0])
2338        print ' Distance from view point at %.3f %.3f %.3f to:'%(viewPt[0],viewPt[1],viewPt[2])
2339        atomDData = drawingData['Atoms']
2340        colLabels = [drawAtoms.GetColLabelValue(c) for c in range(drawAtoms.GetNumberCols())]
2341        cx = colLabels.index('x')
2342        cn = colLabels.index('Name')
2343        for i in indx:
2344            atom = atomDData[i]
2345            Dx = np.array(atom[cx:cx+3])-viewPt
2346            dist = np.sqrt(np.sum(np.inner(Amat,Dx)**2,axis=0))
2347            print 'Atom: %8s (%12s) distance = %.3f'%(atom[cn],atom[cx+3],dist)
2348   
2349    def OnDrawDAT(event):
2350        #distance, angle, torsion
2351        indx = drawAtoms.GetSelectedRows()
2352        if len(indx) not in [2,3,4]:
2353            print '**** ERROR - wrong number of atoms for distance, angle or torsion calculation'
2354            return
2355        DATData = {}
2356        ocx,oct,ocs,cia = data['General']['AtomPtrs']
2357        drawingData = data['Drawing']
2358        atomData = data['Atoms']
2359        atomDData = drawingData['Atoms']
2360        colLabels = [drawAtoms.GetColLabelValue(c) for c in range(drawAtoms.GetNumberCols())]
2361        cx = colLabels.index('x')
2362        cn = colLabels.index('Name')
2363        cid = colLabels.index('I/A')+8
2364        xyz = []
2365        Oxyz = []
2366        DATData['Natoms'] = len(indx)
2367        for i in indx:
2368            atom = atomDData[i]
2369            xyz.append([i,]+atom[cn:cn+2]+atom[cx:cx+4]) #also gets Sym Op
2370            id = G2mth.FindAtomIndexByIDs(atomData,[atom[cid],],False)[0]
2371            Oxyz.append([id,]+atomData[id][cx+1:cx+4])
2372        DATData['Datoms'] = xyz
2373        DATData['Oatoms'] = Oxyz
2374        generalData = data['General']
2375        DATData['Name'] = generalData['Name']
2376        DATData['SGData'] = generalData['SGData']
2377        DATData['Cell'] = generalData['Cell'][1:] #+ volume
2378        if 'pId' in data:
2379            DATData['pId'] = data['pId']
2380            DATData['covData'] = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.root, 'Covariance'))
2381        G2str.DisAglTor(DATData)
2382               
2383################################################################################
2384#### Draw Options page
2385################################################################################
2386
2387    def UpdateDrawOptions():
2388        import copy
2389        import wx.lib.colourselect as wcs
2390        generalData = data['General']
2391        Amat,Bmat = G2lat.cell2AB(generalData['Cell'][1:7])
2392        SetupDrawingData()
2393        drawingData = data['Drawing']
2394        if generalData['Type'] == 'nuclear':
2395            pickChoice = ['Atoms','Bonds','Torsions','Planes']
2396        elif generalData['Type'] == 'macromolecular':
2397            pickChoice = ['Atoms','Residues','Chains','Bonds','Torsions','Planes','phi/psi']
2398
2399        def SlopSizer():
2400           
2401            def OnCameraPos(event):
2402                drawingData['cameraPos'] = cameraPos.GetValue()
2403                cameraPosTxt.SetLabel(' Camera Distance: '+'%.2f'%(drawingData['cameraPos']))
2404                ZclipTxt.SetLabel(' Z clipping: '+'%.2fA'%(drawingData['Zclip']*drawingData['cameraPos']/100.))
2405                G2plt.PlotStructure(G2frame,data)
2406
2407            def OnZclip(event):
2408                drawingData['Zclip'] = Zclip.GetValue()
2409                ZclipTxt.SetLabel(' Z clipping: '+'%.2fA'%(drawingData['Zclip']*drawingData['cameraPos']/100.))
2410                G2plt.PlotStructure(G2frame,data)
2411               
2412            def OnZstep(event):
2413                try:
2414                    step = float(Zstep.GetValue())
2415                    if not (0.01 <= step <= 1.0):
2416                        raise ValueError
2417                except ValueError:
2418                    step = drawingData['Zstep']
2419                drawingData['Zstep'] = step
2420                Zstep.SetValue('%.2fA'%(drawingData['Zstep']))
2421               
2422            def OnMoveZ(event):
2423                move = MoveZ.GetValue()*drawingData['Zstep']
2424                MoveZ.SetValue(0)
2425                VP = np.inner(Amat,np.array(drawingData['viewPoint'][0]))
2426                VD = np.inner(Amat,np.array(drawingData['viewDir']))
2427                VD /= np.sqrt(np.sum(VD**2))
2428                VP += move*VD
2429                VP = np.inner(Bmat,VP)
2430                drawingData['viewPoint'][0] = VP
2431                panel = dataDisplay.GetChildren()
2432                names = [child.GetName() for child in panel]
2433                panel[names.index('viewPoint')].SetValue('%.3f %.3f %.3f'%(VP[0],VP[1],VP[2]))               
2434                G2plt.PlotStructure(G2frame,data)
2435               
2436            def OnVdWScale(event):
2437                drawingData['vdwScale'] = vdwScale.GetValue()/100.
2438                vdwScaleTxt.SetLabel(' van der Waals scale: '+'%.2f'%(drawingData['vdwScale']))
2439                G2plt.PlotStructure(G2frame,data)
2440   
2441            def OnEllipseProb(event):
2442                drawingData['ellipseProb'] = ellipseProb.GetValue()
2443                ellipseProbTxt.SetLabel(' Ellipsoid probability: '+'%d%%'%(drawingData['ellipseProb']))
2444                G2plt.PlotStructure(G2frame,data)
2445   
2446            def OnBallScale(event):
2447                drawingData['ballScale'] = ballScale.GetValue()/100.
2448                ballScaleTxt.SetLabel(' Ball scale: '+'%.2f'%(drawingData['ballScale']))
2449                G2plt.PlotStructure(G2frame,data)
2450
2451            def OnBondRadius(event):
2452                drawingData['bondRadius'] = bondRadius.GetValue()/100.
2453                bondRadiusTxt.SetLabel(' Bond radius, A: '+'%.2f'%(drawingData['bondRadius']))
2454                G2plt.PlotStructure(G2frame,data)
2455               
2456            def OnContourLevel(event):
2457                drawingData['contourLevel'] = contourLevel.GetValue()/100.
2458                contourLevelTxt.SetLabel(' Contour level: '+'%.2f'%(drawingData['contourLevel']*generalData['Map']['rhoMax']))
2459                G2plt.PlotStructure(G2frame,data)
2460
2461            def OnMapSize(event):
2462                drawingData['mapSize'] = mapSize.GetValue()/10.
2463                mapSizeTxt.SetLabel(' Map radius, A: '+'%.1f'%(drawingData['mapSize']))
2464                G2plt.PlotStructure(G2frame,data)
2465
2466           
2467            slopSizer = wx.BoxSizer(wx.HORIZONTAL)
2468            slideSizer = wx.FlexGridSizer(7,2)
2469            slideSizer.AddGrowableCol(1,1)
2470   
2471            cameraPosTxt = wx.StaticText(dataDisplay,-1,
2472                ' Camera Distance: '+'%.2f'%(drawingData['cameraPos']),name='cameraPos')
2473            slideSizer.Add(cameraPosTxt,0,wx.ALIGN_CENTER_VERTICAL)
2474            cameraPos = wx.Slider(dataDisplay,style=wx.SL_HORIZONTAL,value=drawingData['cameraPos'],name='cameraSlider')
2475            cameraPos.SetRange(10,500)
2476            cameraPos.Bind(wx.EVT_SLIDER, OnCameraPos)
2477            slideSizer.Add(cameraPos,1,wx.EXPAND|wx.RIGHT)
2478           
2479            ZclipTxt = wx.StaticText(dataDisplay,-1,' Z clipping: '+'%.2fA'%(drawingData['Zclip']*drawingData['cameraPos']/100.))
2480            slideSizer.Add(ZclipTxt,0,wx.ALIGN_CENTER_VERTICAL)
2481            Zclip = wx.Slider(dataDisplay,style=wx.SL_HORIZONTAL,value=drawingData['Zclip'])
2482            Zclip.SetRange(1,99)
2483            Zclip.Bind(wx.EVT_SLIDER, OnZclip)
2484            slideSizer.Add(Zclip,1,wx.EXPAND|wx.RIGHT)
2485           
2486            ZstepSizer = wx.BoxSizer(wx.HORIZONTAL)
2487            ZstepSizer.Add(wx.StaticText(dataDisplay,-1,' Z step:'),0,wx.ALIGN_CENTER_VERTICAL)
2488            Zstep = wx.TextCtrl(dataDisplay,value='%.2f'%(drawingData['Zstep']),
2489                style=wx.TE_PROCESS_ENTER)
2490            Zstep.Bind(wx.EVT_TEXT_ENTER,OnZstep)
2491            Zstep.Bind(wx.EVT_KILL_FOCUS,OnZstep)
2492            ZstepSizer.Add(Zstep,0,wx.ALIGN_CENTER_VERTICAL)
2493            slideSizer.Add(ZstepSizer)
2494            MoveSizer = wx.BoxSizer(wx.HORIZONTAL)
2495            MoveSizer.Add(wx.StaticText(dataDisplay,-1,'   Press to step:'),0,wx.ALIGN_CENTER_VERTICAL)
2496            MoveZ = wx.SpinButton(dataDisplay,style=wx.SP_HORIZONTAL,size=wx.Size(100,20))
2497            MoveZ.SetValue(0)
2498            MoveZ.SetRange(-1,1)
2499            MoveZ.Bind(wx.EVT_SPIN, OnMoveZ)
2500            MoveSizer.Add(MoveZ)
2501            slideSizer.Add(MoveSizer,1,wx.EXPAND|wx.RIGHT)
2502           
2503            vdwScaleTxt = wx.StaticText(dataDisplay,-1,' van der Waals scale: '+'%.2f'%(drawingData['vdwScale']))
2504            slideSizer.Add(vdwScaleTxt,0,wx.ALIGN_CENTER_VERTICAL)
2505            vdwScale = wx.Slider(dataDisplay,style=wx.SL_HORIZONTAL,value=int(100*drawingData['vdwScale']))
2506            vdwScale.Bind(wx.EVT_SLIDER, OnVdWScale)
2507            slideSizer.Add(vdwScale,1,wx.EXPAND|wx.RIGHT)
2508   
2509            ellipseProbTxt = wx.StaticText(dataDisplay,-1,' Ellipsoid probability: '+'%d%%'%(drawingData['ellipseProb']))
2510            slideSizer.Add(ellipseProbTxt,0,wx.ALIGN_CENTER_VERTICAL)
2511            ellipseProb = wx.Slider(dataDisplay,style=wx.SL_HORIZONTAL,value=drawingData['ellipseProb'])
2512            ellipseProb.SetRange(1,99)
2513            ellipseProb.Bind(wx.EVT_SLIDER, OnEllipseProb)
2514            slideSizer.Add(ellipseProb,1,wx.EXPAND|wx.RIGHT)
2515   
2516            ballScaleTxt = wx.StaticText(dataDisplay,-1,' Ball scale: '+'%.2f'%(drawingData['ballScale']))
2517            slideSizer.Add(ballScaleTxt,0,wx.ALIGN_CENTER_VERTICAL)
2518            ballScale = wx.Slider(dataDisplay,style=wx.SL_HORIZONTAL,value=int(100*drawingData['ballScale']))
2519            ballScale.Bind(wx.EVT_SLIDER, OnBallScale)
2520            slideSizer.Add(ballScale,1,wx.EXPAND|wx.RIGHT)
2521   
2522            bondRadiusTxt = wx.StaticText(dataDisplay,-1,' Bond radius, A: '+'%.2f'%(drawingData['bondRadius']))
2523            slideSizer.Add(bondRadiusTxt,0,wx.ALIGN_CENTER_VERTICAL)
2524            bondRadius = wx.Slider(dataDisplay,style=wx.SL_HORIZONTAL,value=int(100*drawingData['bondRadius']))
2525            bondRadius.SetRange(1,25)
2526            bondRadius.Bind(wx.EVT_SLIDER, OnBondRadius)
2527            slideSizer.Add(bondRadius,1,wx.EXPAND|wx.RIGHT)
2528           
2529            if generalData['Map']['rhoMax']:
2530                contourLevelTxt = wx.StaticText(dataDisplay,-1,' Contour level: '+'%.2f'%(drawingData['contourLevel']*generalData['Map']['rhoMax']))
2531                slideSizer.Add(contourLevelTxt,0,wx.ALIGN_CENTER_VERTICAL)
2532                contourLevel = wx.Slider(dataDisplay,style=wx.SL_HORIZONTAL,value=int(100*drawingData['contourLevel']))
2533                contourLevel.SetRange(1,100)
2534                contourLevel.Bind(wx.EVT_SLIDER, OnContourLevel)
2535                slideSizer.Add(contourLevel,1,wx.EXPAND|wx.RIGHT)
2536                mapSizeTxt = wx.StaticText(dataDisplay,-1,' Map radius, A: '+'%.1f'%(drawingData['mapSize']))
2537                slideSizer.Add(mapSizeTxt,0,wx.ALIGN_CENTER_VERTICAL)
2538                mapSize = wx.Slider(dataDisplay,style=wx.SL_HORIZONTAL,value=int(10*drawingData['mapSize']))
2539                mapSize.SetRange(1,100)
2540                mapSize.Bind(wx.EVT_SLIDER, OnMapSize)
2541                slideSizer.Add(mapSize,1,wx.EXPAND|wx.RIGHT)
2542           
2543            slopSizer.Add(slideSizer,1,wx.EXPAND|wx.RIGHT)
2544            slopSizer.Add((10,5),0)
2545            slopSizer.SetMinSize(wx.Size(350,10))
2546            return slopSizer
2547           
2548        def ShowSizer():
2549           
2550            def OnBackColor(event):
2551                drawingData['backColor'] = event.GetValue()
2552                G2plt.PlotStructure(G2frame,data)
2553   
2554            def OnShowABC(event):
2555                drawingData['showABC'] = showABC.GetValue()
2556                G2plt.PlotStructure(G2frame,data)
2557   
2558            def OnShowUnitCell(event):
2559                drawingData['unitCellBox'] = unitCellBox.GetValue()
2560                G2plt.PlotStructure(G2frame,data)
2561   
2562            def OnShowHyd(event):
2563                drawingData['showHydrogen'] = showHydrogen.GetValue()
2564                FindBondsDraw()
2565                G2plt.PlotStructure(G2frame,data)
2566               
2567            def OnShowRB(event):
2568                drawingData['showRigidBodies'] = showRB.GetValue()
2569                FindBondsDraw()
2570                G2plt.PlotStructure(G2frame,data)
2571               
2572            def OnViewPoint(event):
2573                Obj = event.GetEventObject()
2574                viewPt = Obj.GetValue().split()
2575                try:
2576                    VP = [float(viewPt[i]) for i in range(3)]
2577                except (ValueError,IndexError):
2578                    VP = drawingData['viewPoint'][0]
2579                Obj.SetValue('%.3f %.3f %.3f'%(VP[0],VP[1],VP[2]))
2580                drawingData['viewPoint'][0] = VP
2581                G2plt.PlotStructure(G2frame,data)
2582               
2583            def OnViewDir(event):
2584                Obj = event.GetEventObject()
2585                viewDir = Obj.GetValue().split()
2586                try:
2587                    Amat,Bmat = G2lat.cell2AB(generalData['Cell'][1:7])
2588                    VD = np.array([float(viewDir[i]) for i in range(3)])
2589                    VC = np.inner(Amat,VD)
2590                    VC /= np.sqrt(np.sum(VC**2))
2591                    V = np.array(drawingData['viewDir'])
2592                    VB = np.inner(Amat,V)
2593                    VB /= np.sqrt(np.sum(VB**2))
2594                    VX = np.cross(VC,VB)
2595                    A = acosd(max((2.-np.sum((VB-VC)**2))/2.,-1.))
2596                    QV = G2mth.AVdeg2Q(A,VX)
2597                    Q = drawingData['Quaternion']
2598                    drawingData['Quaternion'] = G2mth.prodQQ(Q,QV)
2599                except (ValueError,IndexError):
2600                    VD = drawingData['viewDir']
2601                Obj.SetValue('%.3f %.3f %.3f'%(VD[0],VD[1],VD[2]))
2602                drawingData['viewDir'] = VD
2603                G2plt.PlotStructure(G2frame,data)
2604                               
2605            showSizer = wx.BoxSizer(wx.VERTICAL)           
2606            lineSizer = wx.BoxSizer(wx.HORIZONTAL)
2607            lineSizer.Add(wx.StaticText(dataDisplay,-1,' Background color:'),0,wx.ALIGN_CENTER_VERTICAL)
2608            backColor = wcs.ColourSelect(dataDisplay, -1,colour=drawingData['backColor'],size=wx.Size(25,25))
2609            backColor.Bind(wcs.EVT_COLOURSELECT, OnBackColor)
2610            lineSizer.Add(backColor,0,wx.ALIGN_CENTER_VERTICAL)
2611            lineSizer.Add(wx.StaticText(dataDisplay,-1,' View Dir.:'),0,wx.ALIGN_CENTER_VERTICAL)
2612            VD = drawingData['viewDir']
2613            viewDir = wx.TextCtrl(dataDisplay,value='%.3f %.3f %.3f'%(VD[0],VD[1],VD[2]),
2614                style=wx.TE_PROCESS_ENTER,size=wx.Size(140,20),name='viewDir')
2615            viewDir.Bind(wx.EVT_TEXT_ENTER,OnViewDir)
2616            viewDir.Bind(wx.EVT_KILL_FOCUS,OnViewDir)
2617            lineSizer.Add(viewDir,0,wx.ALIGN_CENTER_VERTICAL)
2618            showSizer.Add(lineSizer)
2619            showSizer.Add((0,5),0)
2620           
2621            lineSizer = wx.BoxSizer(wx.HORIZONTAL)
2622            showABC = wx.CheckBox(dataDisplay,-1,label=' Show view point?')
2623            showABC.Bind(wx.EVT_CHECKBOX, OnShowABC)
2624            showABC.SetValue(drawingData['showABC'])
2625            lineSizer.Add(showABC,0,wx.ALIGN_CENTER_VERTICAL)
2626            lineSizer.Add(wx.StaticText(dataDisplay,-1,' View Point:'),0,wx.ALIGN_CENTER_VERTICAL)
2627            VP = drawingData['viewPoint'][0]
2628            viewPoint = wx.TextCtrl(dataDisplay,value='%.3f %.3f %.3f'%(VP[0],VP[1],VP[2]),
2629                style=wx.TE_PROCESS_ENTER,size=wx.Size(140,20),name='viewPoint')
2630            viewPoint.Bind(wx.EVT_TEXT_ENTER,OnViewPoint)
2631            viewPoint.Bind(wx.EVT_KILL_FOCUS,OnViewPoint)
2632            lineSizer.Add(viewPoint,0,wx.ALIGN_CENTER_VERTICAL)
2633            showSizer.Add(lineSizer)
2634            showSizer.Add((0,5),0)
2635           
2636            line2Sizer = wx.BoxSizer(wx.HORIZONTAL)
2637   
2638            unitCellBox = wx.CheckBox(dataDisplay,-1,label=' Show unit cell?')
2639            unitCellBox.Bind(wx.EVT_CHECKBOX, OnShowUnitCell)
2640            unitCellBox.SetValue(drawingData['unitCellBox'])
2641            line2Sizer.Add(unitCellBox,0,wx.ALIGN_CENTER_VERTICAL)
2642   
2643            showHydrogen = wx.CheckBox(dataDisplay,-1,label=' Show hydrogens?')
2644            showHydrogen.Bind(wx.EVT_CHECKBOX, OnShowHyd)
2645            showHydrogen.SetValue(drawingData['showHydrogen'])
2646            line2Sizer.Add(showHydrogen,0,wx.ALIGN_CENTER_VERTICAL)
2647           
2648            showRB = wx.CheckBox(dataDisplay,-1,label=' Show rigid Bodies?')
2649            showRB.Bind(wx.EVT_CHECKBOX, OnShowRB)
2650            showRB.SetValue(drawingData['showRigidBodies'])
2651            line2Sizer.Add(showRB,0,wx.ALIGN_CENTER_VERTICAL)
2652           
2653            showSizer.Add(line2Sizer)
2654            return showSizer
2655           
2656        def RadSizer():
2657           
2658            def OnSizeHatoms(event):
2659                try:
2660                    value = max(0.1,min(1.2,float(sizeH.GetValue())))
2661                except ValueError:
2662                    value = 0.5
2663                drawingData['sizeH'] = value
2664                sizeH.SetValue("%.2f"%(value))
2665                G2plt.PlotStructure(G2frame,data)
2666               
2667            def OnRadFactor(event):
2668                try:
2669                    value = max(0.1,min(1.2,float(radFactor.GetValue())))
2670                except ValueError:
2671                    value = 0.85
2672                drawingData['radiusFactor'] = value
2673                radFactor.SetValue("%.2f"%(value))
2674                FindBondsDraw()
2675                G2plt.PlotStructure(G2frame,data)
2676           
2677            radSizer = wx.BoxSizer(wx.HORIZONTAL)
2678            radSizer.Add(wx.StaticText(dataDisplay,-1,' Hydrogen radius, A:  '),0,wx.ALIGN_CENTER_VERTICAL)
2679            sizeH = wx.TextCtrl(dataDisplay,-1,value='%.2f'%(drawingData['sizeH']),size=wx.Size(60,20),style=wx.TE_PROCESS_ENTER)
2680            sizeH.Bind(wx.EVT_TEXT_ENTER,OnSizeHatoms)
2681            sizeH.Bind(wx.EVT_KILL_FOCUS,OnSizeHatoms)
2682            radSizer.Add(sizeH,0,wx.ALIGN_CENTER_VERTICAL)
2683   
2684            radSizer.Add(wx.StaticText(dataDisplay,-1,' Bond search factor:  '),0,wx.ALIGN_CENTER_VERTICAL)
2685            radFactor = wx.TextCtrl(dataDisplay,value='%.2f'%(drawingData['radiusFactor']),size=wx.Size(60,20),style=wx.TE_PROCESS_ENTER)
2686            radFactor.Bind(wx.EVT_TEXT_ENTER,OnRadFactor)
2687            radFactor.Bind(wx.EVT_KILL_FOCUS,OnRadFactor)
2688            radSizer.Add(radFactor,0,wx.ALIGN_CENTER_VERTICAL)
2689            return radSizer
2690
2691        G2frame.dataFrame.SetStatusText('')
2692        drawOptions.DestroyChildren()
2693        dataDisplay = wx.Panel(drawOptions)
2694        mainSizer = wx.BoxSizer(wx.VERTICAL)
2695        mainSizer.Add((5,5),0)
2696        mainSizer.Add(wx.StaticText(dataDisplay,-1,' Drawing controls:'),0,wx.ALIGN_CENTER_VERTICAL)
2697        mainSizer.Add((5,5),0)       
2698        mainSizer.Add(SlopSizer(),0)
2699        mainSizer.Add((5,5),0)
2700        mainSizer.Add(ShowSizer(),0,)
2701        mainSizer.Add((5,5),0)
2702        mainSizer.Add(RadSizer(),0,)
2703
2704        dataDisplay.SetSizer(mainSizer)
2705        Size = mainSizer.Fit(G2frame.dataFrame)
2706        Size[1] += 35                           #compensate for status bar
2707        dataDisplay.SetSize(Size)
2708        G2frame.dataFrame.setSizePosLeft(Size)
2709
2710################################################################################
2711####  Texture routines
2712################################################################################
2713       
2714    def UpdateTexture():
2715        G2frame.dataFrame.SetStatusText('')
2716        generalData = data['General']       
2717        SGData = generalData['SGData']
2718        try:
2719            textureData = generalData['SH Texture']
2720        except KeyError:            #fix old files!
2721            textureData = generalData['SH Texture'] = {'Order':0,'Model':'cylindrical',
2722                'Sample omega':[False,0.0],'Sample chi':[False,0.0],'Sample phi':[False,0.0],
2723                'SH Coeff':[False,{}],'SHShow':False,'PFhkl':[0,0,1],
2724                'PFxyz':[0,0,1.],'PlotType':'Pole figure'}
2725        if 'SHShow' not in textureData:     #another fix
2726            textureData.update({'SHShow':False,'PFhkl':[0,0,1],'PFxyz':[0,0,1.],'PlotType':'Pole figure'})
2727        try:                        #another fix!
2728            x = textureData['PlotType']
2729        except KeyError:
2730            textureData.update({'PFxyz':[0,0,1.],'PlotType':'Pole figure'})
2731        shModels = ['cylindrical','none','shear - 2/m','rolling - mmm']
2732        SamSym = dict(zip(shModels,['0','-1','2/m','mmm']))
2733        if generalData['doPawley'] and G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Sequental results'):
2734            G2frame.dataFrame.RefineTexture.Enable(True)
2735        shAngles = ['omega','chi','phi']
2736       
2737        def SetSHCoef():
2738            cofNames = G2lat.GenSHCoeff(SGData['SGLaue'],SamSym[textureData['Model']],textureData['Order'])
2739            newSHCoef = dict(zip(cofNames,np.zeros(len(cofNames))))
2740            SHCoeff = textureData['SH Coeff'][1]
2741            for cofName in SHCoeff:
2742                if cofName in  cofNames:
2743                    newSHCoef[cofName] = SHCoeff[cofName]
2744            return newSHCoef
2745       
2746        def OnShOrder(event):
2747            Obj = event.GetEventObject()
2748            textureData['Order'] = int(Obj.GetValue())
2749            textureData['SH Coeff'][1] = SetSHCoef()
2750            wx.CallAfter(UpdateTexture)
2751            G2plt.PlotTexture(G2frame,data)
2752                       
2753        def OnShModel(event):
2754            Obj = event.GetEventObject()
2755            textureData['Model'] = Obj.GetValue()
2756            textureData['SH Coeff'][1] = SetSHCoef()
2757            wx.CallAfter(UpdateTexture)
2758            G2plt.PlotTexture(G2frame,data)
2759           
2760        def OnSHRefine(event):
2761            Obj = event.GetEventObject()
2762            textureData['SH Coeff'][0] = Obj.GetValue()
2763           
2764        def OnSHShow(event):
2765            Obj = event.GetEventObject()
2766            textureData['SHShow'] = Obj.GetValue()
2767            wx.CallAfter(UpdateTexture)
2768           
2769        def OnProjSel(event):
2770            Obj = event.GetEventObject()
2771            G2frame.Projection = Obj.GetValue()
2772            G2plt.PlotTexture(G2frame,data)
2773           
2774        def OnColorSel(event):
2775            Obj = event.GetEventObject()
2776            G2frame.ContourColor = Obj.GetValue()
2777            G2plt.PlotTexture(G2frame,data)
2778           
2779        def OnAngRef(event):
2780            Obj = event.GetEventObject()
2781            textureData[angIndx[Obj.GetId()]][0] = Obj.GetValue()
2782           
2783        def OnAngValue(event):
2784            Obj = event.GetEventObject()
2785            try:
2786                value =  float(Obj.GetValue())
2787            except ValueError:
2788                value = textureData[valIndx[Obj.GetId()]][1]
2789            Obj.SetValue('%8.2f'%(value))
2790            textureData[valIndx[Obj.GetId()]][1] = value
2791           
2792        def OnODFValue(event): 
2793            Obj = event.GetEventObject()
2794            try:
2795                value =  float(Obj.GetValue())
2796            except ValueError:
2797                value = textureData['SH Coeff'][1][ODFIndx[Obj.GetId()]]
2798            Obj.SetValue('%8.3f'%(value))
2799            textureData['SH Coeff'][1][ODFIndx[Obj.GetId()]] = value
2800            G2plt.PlotTexture(G2frame,data)
2801           
2802        def OnPfType(event):
2803            Obj = event.GetEventObject()
2804            textureData['PlotType'] = Obj.GetValue()
2805            wx.CallAfter(UpdateTexture)
2806            G2plt.PlotTexture(G2frame,data)
2807           
2808        def OnPFValue(event):
2809            Obj = event.GetEventObject()
2810            Saxis = Obj.GetValue().split()
2811            if textureData['PlotType'] in ['Pole figure','Axial pole distribution']:               
2812                try:
2813                    hkl = [int(Saxis[i]) for i in range(3)]
2814                except (ValueError,IndexError):
2815                    hkl = textureData['PFhkl']
2816                if not np.any(np.array(hkl)):       #can't be all zeros!
2817                    hkl = textureData['PFhkl']
2818                Obj.SetValue('%d %d %d'%(hkl[0],hkl[1],hkl[2]))
2819                textureData['PFhkl'] = hkl
2820            else:
2821                try:
2822                    xyz = [float(Saxis[i]) for i in range(3)]
2823                except (ValueError,IndexError):
2824                    xyz = textureData['PFxyz']
2825                if not np.any(np.array(xyz)):       #can't be all zeros!
2826                    xyz = textureData['PFxyz']
2827                Obj.SetValue('%3.1f %3.1f %3.1f'%(xyz[0],xyz[1],xyz[2]))
2828                textureData['PFxyz'] = xyz
2829            G2plt.PlotTexture(G2frame,data)
2830
2831        if Texture.GetSizer():
2832            Texture.GetSizer().Clear(True)
2833        mainSizer = wx.BoxSizer(wx.VERTICAL)
2834        titleSizer = wx.BoxSizer(wx.HORIZONTAL)
2835        titleSizer.Add(wx.StaticText(Texture,-1,'Spherical harmonics texture data for '+PhaseName+':'),0,wx.ALIGN_CENTER_VERTICAL)
2836        titleSizer.Add(wx.StaticText(Texture,-1,
2837            ' Texture Index J = %7.3f'%(G2lat.textureIndex(textureData['SH Coeff'][1]))),
2838            0,wx.ALIGN_CENTER_VERTICAL)
2839        mainSizer.Add(titleSizer,0)
2840        mainSizer.Add((0,5),0)
2841        shSizer = wx.FlexGridSizer(1,6,5,5)
2842        shSizer.Add(wx.StaticText(Texture,-1,'Texture model: '),0,wx.ALIGN_CENTER_VERTICAL)
2843        shModel = wx.ComboBox(Texture,-1,value=textureData['Model'],choices=shModels,
2844            style=wx.CB_READONLY|wx.CB_DROPDOWN)
2845        shModel.Bind(wx.EVT_COMBOBOX,OnShModel)
2846        shSizer.Add(shModel,0,wx.ALIGN_CENTER_VERTICAL)
2847        shSizer.Add(wx.StaticText(Texture,-1,'  Harmonic order: '),0,wx.ALIGN_CENTER_VERTICAL)
2848        shOrder = wx.ComboBox(Texture,-1,value=str(textureData['Order']),choices=[str(2*i) for i in range(18)],
2849            style=wx.CB_READONLY|wx.CB_DROPDOWN)
2850        shOrder.Bind(wx.EVT_COMBOBOX,OnShOrder)
2851        shSizer.Add(shOrder,0,wx.ALIGN_CENTER_VERTICAL)
2852        shRef = wx.CheckBox(Texture,-1,label=' Refine texture?')
2853        shRef.SetValue(textureData['SH Coeff'][0])
2854        shRef.Bind(wx.EVT_CHECKBOX, OnSHRefine)
2855        shSizer.Add(shRef,0,wx.ALIGN_CENTER_VERTICAL)
2856        shShow = wx.CheckBox(Texture,-1,label=' Show coeff.?')
2857        shShow.SetValue(textureData['SHShow'])
2858        shShow.Bind(wx.EVT_CHECKBOX, OnSHShow)
2859        shSizer.Add(shShow,0,wx.ALIGN_CENTER_VERTICAL)
2860        mainSizer.Add(shSizer,0,0)
2861        mainSizer.Add((0,5),0)
2862        PTSizer = wx.FlexGridSizer(2,4,5,5)
2863        PTSizer.Add(wx.StaticText(Texture,-1,' Texture plot type: '),0,wx.ALIGN_CENTER_VERTICAL)
2864        choices = ['Axial pole distribution','Pole figure','Inverse pole figure']           
2865        pfType = wx.ComboBox(Texture,-1,value=str(textureData['PlotType']),choices=choices,
2866            style=wx.CB_READONLY|wx.CB_DROPDOWN)
2867        pfType.Bind(wx.EVT_COMBOBOX,OnPfType)
2868        PTSizer.Add(pfType,0,wx.ALIGN_CENTER_VERTICAL)
2869        if 'Axial' not in textureData['PlotType']:
2870            PTSizer.Add(wx.StaticText(Texture,-1,' Projection type: '),0,wx.ALIGN_CENTER_VERTICAL)
2871            projSel = wx.ComboBox(Texture,-1,value=G2frame.Projection,choices=['equal area','stereographic','3D display'],
2872                style=wx.CB_READONLY|wx.CB_DROPDOWN)
2873            projSel.Bind(wx.EVT_COMBOBOX,OnProjSel)
2874            PTSizer.Add(projSel,0,wx.ALIGN_CENTER_VERTICAL)
2875        if textureData['PlotType'] in ['Pole figure','Axial pole distribution']:
2876            PTSizer.Add(wx.StaticText(Texture,-1,' Pole figure HKL: '),0,wx.ALIGN_CENTER_VERTICAL)
2877            PH = textureData['PFhkl']
2878            pfVal = wx.TextCtrl(Texture,-1,'%d %d %d'%(PH[0],PH[1],PH[2]),style=wx.TE_PROCESS_ENTER)
2879        else:
2880            PTSizer.Add(wx.StaticText(Texture,-1,' Inverse pole figure XYZ: '),0,wx.ALIGN_CENTER_VERTICAL)
2881            PX = textureData['PFxyz']
2882            pfVal = wx.TextCtrl(Texture,-1,'%3.1f %3.1f %3.1f'%(PX[0],PX[1],PX[2]),style=wx.TE_PROCESS_ENTER)
2883        pfVal.Bind(wx.EVT_TEXT_ENTER,OnPFValue)
2884        pfVal.Bind(wx.EVT_KILL_FOCUS,OnPFValue)
2885        PTSizer.Add(pfVal,0,wx.ALIGN_CENTER_VERTICAL)
2886        if 'Axial' not in textureData['PlotType']:
2887            PTSizer.Add(wx.StaticText(Texture,-1,' Color scheme'),0,wx.ALIGN_CENTER_VERTICAL)
2888            choice = [m for m in mpl.cm.datad.keys() if not m.endswith("_r")]
2889            choice.sort()
2890            colorSel = wx.ComboBox(Texture,-1,value=G2frame.ContourColor,choices=choice,
2891                style=wx.CB_READONLY|wx.CB_DROPDOWN)
2892            colorSel.Bind(wx.EVT_COMBOBOX,OnColorSel)
2893            PTSizer.Add(colorSel,0,wx.ALIGN_CENTER_VERTICAL)       
2894        mainSizer.Add(PTSizer,0,wx.ALIGN_CENTER_VERTICAL)
2895        mainSizer.Add((0,5),0)
2896        if textureData['SHShow']:
2897            mainSizer.Add(wx.StaticText(Texture,-1,'Spherical harmonic coefficients: '),0,wx.ALIGN_CENTER_VERTICAL)
2898            mainSizer.Add((0,5),0)
2899            ODFSizer = wx.FlexGridSizer(2,8,2,2)
2900            ODFIndx = {}
2901            ODFkeys = textureData['SH Coeff'][1].keys()
2902            ODFkeys.sort()
2903            for item in ODFkeys:
2904                ODFSizer.Add(wx.StaticText(Texture,-1,item),0,wx.ALIGN_CENTER_VERTICAL)
2905                ODFval = wx.TextCtrl(Texture,wx.ID_ANY,'%8.3f'%(textureData['SH Coeff'][1][item]),style=wx.TE_PROCESS_ENTER)
2906                ODFIndx[ODFval.GetId()] = item
2907                ODFval.Bind(wx.EVT_TEXT_ENTER,OnODFValue)
2908                ODFval.Bind(wx.EVT_KILL_FOCUS,OnODFValue)
2909                ODFSizer.Add(ODFval,0,wx.ALIGN_CENTER_VERTICAL)
2910            mainSizer.Add(ODFSizer,0,wx.ALIGN_CENTER_VERTICAL)
2911            mainSizer.Add((0,5),0)
2912        mainSizer.Add((0,5),0)
2913        mainSizer.Add(wx.StaticText(Texture,-1,'Sample orientation angles: '),0,wx.ALIGN_CENTER_VERTICAL)
2914        mainSizer.Add((0,5),0)
2915        angSizer = wx.BoxSizer(wx.HORIZONTAL)
2916        angIndx = {}
2917        valIndx = {}
2918        for item in ['Sample omega','Sample chi','Sample phi']:
2919            angRef = wx.CheckBox(Texture,-1,label=item+': ')
2920            angRef.SetValue(textureData[item][0])
2921            angIndx[angRef.GetId()] = item
2922            angRef.Bind(wx.EVT_CHECKBOX, OnAngRef)
2923            angSizer.Add(angRef,0,wx.ALIGN_CENTER_VERTICAL)
2924            angVal = wx.TextCtrl(Texture,wx.ID_ANY,'%8.2f'%(textureData[item][1]),style=wx.TE_PROCESS_ENTER)
2925            valIndx[angVal.GetId()] = item
2926            angVal.Bind(wx.EVT_TEXT_ENTER,OnAngValue)
2927            angVal.Bind(wx.EVT_KILL_FOCUS,OnAngValue)
2928            angSizer.Add(angVal,0,wx.ALIGN_CENTER_VERTICAL)
2929            angSizer.Add((5,0),0)
2930        mainSizer.Add(angSizer,0,wx.ALIGN_CENTER_VERTICAL)
2931        Texture.SetSizer(mainSizer,True)
2932        mainSizer.Fit(G2frame.dataFrame)
2933        Size = mainSizer.GetMinSize()
2934        Size[0] += 40
2935        Size[1] = max(Size[1],250) + 35
2936        Texture.SetSize(Size)
2937        Texture.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
2938        Size[1] = min(Size[1],450)
2939        G2frame.dataFrame.setSizePosLeft(Size)
2940
2941################################################################################
2942##### DData routines - GUI stuff in GSASIIddataGUI.py
2943################################################################################
2944       
2945    def OnHklfAdd(event):
2946        UseList = data['Histograms']
2947        keyList = UseList.keys()
2948        TextList = []
2949        if G2frame.PatternTree.GetCount():
2950            item, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)
2951            while item:
2952                name = G2frame.PatternTree.GetItemText(item)
2953                if name not in keyList and 'HKLF' in name:
2954                    TextList.append(name)
2955                item, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)                       
2956            dlg = wx.MultiChoiceDialog(G2frame, 'Which new data to use?', 'Use data', TextList, wx.CHOICEDLG_STYLE)
2957            try:
2958                if dlg.ShowModal() == wx.ID_OK:
2959                    result = dlg.GetSelections()
2960                    for i in result:
2961                        histoName = TextList[i]
2962                        UseList[histoName] = {'Histogram':histoName,'Show':False,'Scale':[1.0,True],
2963                            'Babinet':{'BabA':[0.0,False],'BabU':[0.0,False]},
2964                            'Extinction':['Lorentzian','None',
2965                            {'Tbar':0.1,'Cos2TM':0.955,'Eg':[1.e-10,False],'Es':[1.e-10,False],'Ep':[1.e-10,False]},]}                       
2966                    data['Histograms'] = UseList
2967                    wx.BeginBusyCursor()
2968                    UpdateHKLFdata(histoName)
2969                    wx.EndBusyCursor()
2970                    wx.CallAfter(G2ddG.UpdateDData,G2frame,DData,data)
2971            finally:
2972                dlg.Destroy()
2973               
2974    def UpdateHKLFdata(histoName):
2975        generalData = data['General']
2976        Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,histoName)
2977        reflData = G2frame.PatternTree.GetItemPyData(Id)[1]
2978        SGData = generalData['SGData']
2979        Cell = generalData['Cell'][1:7]
2980        G,g = G2lat.cell2Gmat(Cell)
2981        for ref in reflData:
2982            H = ref[:3]
2983            ref[4] = np.sqrt(1./G2lat.calc_rDsq2(H,G))
2984            iabsnt,ref[3],ref[11],ref[12] = G2spc.GenHKLf(H,SGData)
2985        G2frame.PatternTree.SetItemPyData(Id,[histoName,reflData])
2986       
2987    def OnPwdrAdd(event):
2988        generalData = data['General']
2989        SGData = generalData['SGData']
2990        UseList = data['Histograms']
2991        newList = []
2992        NShkl = len(G2spc.MustrainNames(SGData))
2993        NDij = len(G2spc.HStrainNames(SGData))
2994        keyList = UseList.keys()
2995        TextList = ['All PWDR']
2996        if G2frame.PatternTree.GetCount():
2997            item, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)
2998            while item:
2999                name = G2frame.PatternTree.GetItemText(item)
3000                if name not in keyList and 'PWDR' in name:
3001                    TextList.append(name)
3002                item, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)
3003            dlg = wx.MultiChoiceDialog(G2frame, 'Which new data to use?', 'Use data', TextList, wx.CHOICEDLG_STYLE)
3004            try:
3005                if dlg.ShowModal() == wx.ID_OK:
3006                    result = dlg.GetSelections()
3007                    for i in result: newList.append(TextList[i])
3008                    if 'All PWDR' in newList:
3009                        newList = TextList[1:]
3010                    for histoName in newList:
3011                        pId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,histoName)
3012                        UseList[histoName] = {'Histogram':histoName,'Show':False,
3013                            'Scale':[1.0,False],'Pref.Ori.':['MD',1.0,False,[0,0,1],0,{}],
3014                            'Size':['isotropic',[1.,1.,1.],[False,False,False],[0,0,1],
3015                                [1.,1.,1.,0.,0.,0.],6*[False,]],
3016                            'Mustrain':['isotropic',[1000.0,1000.0,1.0],[False,False,False],[0,0,1],
3017                                NShkl*[0.01,],NShkl*[False,]],
3018                            'HStrain':[NDij*[0.0,],NDij*[False,]],                         
3019                            'Extinction':[0.0,False],'Babinet':{'BabA':[0.0,False],'BabU':[0.0,False]}}
3020                        refList = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,pId,'Reflection Lists'))
3021                        refList[generalData['Name']] = []                       
3022                    data['Histograms'] = UseList
3023                    wx.CallAfter(G2ddG.UpdateDData,G2frame,DData,data)
3024            finally:
3025                dlg.Destroy()
3026       
3027    def OnDataDelete(event):
3028        UseList = data['Histograms']
3029        keyList = ['All',]+UseList.keys()
3030        keyList.sort()
3031        DelList = []
3032        if UseList:
3033            DelList = []
3034            dlg = wx.MultiChoiceDialog(G2frame, 
3035                'Which histogram to delete from this phase?', 'Delete histogram', 
3036                keyList, wx.CHOICEDLG_STYLE)
3037            try:
3038                if dlg.ShowModal() == wx.ID_OK:
3039                    result = dlg.GetSelections()
3040                    for i in result: 
3041                        DelList.append(keyList[i])
3042                    if 'All' in DelList:
3043                        DelList = keyList[1:]
3044                    for i in DelList:
3045                        del UseList[i]
3046                    wx.CallAfter(G2ddG.UpdateDData,G2frame,DData,data)
3047            finally:
3048                dlg.Destroy()
3049               
3050################################################################################
3051##### Rigid bodies
3052################################################################################
3053
3054    def FillRigidBodyGrid(refresh=True):
3055        if refresh:
3056            RigidBodies.DestroyChildren()
3057        AtLookUp = G2mth.FillAtomLookUp(data['Atoms'])
3058        general = data['General']
3059        cx = general['AtomPtrs'][0]
3060        Amat,Bmat = G2lat.cell2AB(general['Cell'][1:7])
3061        RBData = G2frame.PatternTree.GetItemPyData(   
3062            G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Rigid bodies'))
3063        Indx = {}
3064       
3065        def OnThermSel(event):       #needs to be seen by VecRbSizer!
3066            Obj = event.GetEventObject()
3067            RBObj = Indx[Obj.GetId()]
3068            val = Obj.GetValue()
3069            RBObj['ThermalMotion'] = ['None',[],[]]
3070            if val == 'Uiso':
3071                RBObj['ThermalMotion'] = ['Uiso',[0.01,],[False,]]
3072            elif val == 'T':
3073                RBObj['ThermalMotion'] = ['T',[0.0 for i in range(6)],[False for i in range(6)]]
3074            elif val == 'TL':
3075                RBObj['ThermalMotion'] = ['TL',[0.0 for i in range(12)],[False for i in range(12)]]
3076            elif val == 'TLS':
3077                RBObj['ThermalMotion'] = ['TLS',[0.0 for i in range(20)],[False for i in range(20)]] #SAA = S33-S11 & SBB = S22-S33
3078            wx.CallAfter(FillRigidBodyGrid,True)
3079           
3080        def ThermDataSizer(RBObj):
3081           
3082            def OnThermval(event):
3083                Obj = event.GetEventObject()
3084                item = Indx[Obj.GetId()]
3085                try:
3086                    val = float(Obj.GetValue())
3087                    RBObj['ThermalMotion'][1][item] = val
3088                except ValueError:
3089                    pass
3090                Obj.SetValue('%8.4f'%(RBObj['ThermalMotion'][1][item]))
3091                G2plt.PlotStructure(G2frame,data)
3092               
3093            def OnTLSRef(event):
3094                Obj = event.GetEventObject()
3095                item = Indx[Obj.GetId()]
3096                RBObj['ThermalMotion'][2][item] = Obj.GetValue()
3097           
3098            thermSizer = wx.FlexGridSizer(1,9,5,5)
3099            model = RBObj['ThermalMotion']
3100            if model[0] == 'Uiso':
3101                names = ['Uiso',]
3102            elif 'T' in model[0]:
3103                names = ['T11','T22','T33','T12','T13','T23']
3104            if 'L' in model[0]:
3105                names += ['L11','L22','L33','L12','L13','L23']
3106            if 'S' in model[0]:
3107                names += ['S12','S13','S21','S23','S31','S32','SAA','SBB']
3108            for i,name in enumerate(names):
3109                thermSizer.Add(wx.StaticText(RigidBodies,-1,name+': '),0,wx.ALIGN_CENTER_VERTICAL)
3110                thermVal = wx.TextCtrl(RigidBodies,-1,value='%8.4f'%(model[1][i]),
3111                    style=wx.TE_PROCESS_ENTER)
3112                thermVal.Bind(wx.EVT_TEXT_ENTER,OnThermval)
3113                thermVal.Bind(wx.EVT_KILL_FOCUS,OnThermval)
3114                Indx[thermVal.GetId()] = i
3115                thermSizer.Add(thermVal)
3116                Tcheck = wx.CheckBox(RigidBodies,-1,'Refine?')
3117                Tcheck.Bind(wx.EVT_CHECKBOX,OnTLSRef)
3118                Tcheck.SetValue(model[2][i])
3119                Indx[Tcheck.GetId()] = i
3120                thermSizer.Add(Tcheck,0,wx.ALIGN_CENTER_VERTICAL)
3121            return thermSizer
3122           
3123        def LocationSizer(RBObj,rbType):
3124           
3125            def OnOrigRef(event):
3126                RBObj['Orig'][1] = Ocheck.GetValue()
3127             
3128            def OnOrienRef(event):
3129                RBObj['Orient'][1] = Qcheck.GetValue()
3130               
3131            def OnOrigX(event):
3132                Obj = event.GetEventObject()
3133                item = Indx[Obj.GetId()]
3134                try:
3135                    val = float(Obj.GetValue())
3136                    RBObj['Orig'][0][item] = val
3137                    Obj.SetValue('%8.5f'%(val))
3138                    newXYZ = G2mth.UpdateRBAtoms(Bmat,RBObj,RBData,rbType)
3139                    for i,id in enumerate(RBObj['Ids']):
3140                        data['Atoms'][AtLookUp[id]][cx:cx+3] = newXYZ[i]
3141                    data['Drawing']['Atoms'] = []
3142                    UpdateDrawAtoms('balls & sticks')
3143                    G2plt.PlotStructure(G2frame,data)
3144                except ValueError:
3145                    pass
3146               
3147            def OnOrien(event):
3148                Obj = event.GetEventObject()
3149                item = Indx[Obj.GetId()]
3150                A,V = G2mth.Q2AVdeg(RBObj['Orient'][0])
3151                V = np.inner(Bmat,V)
3152                try:
3153                    val = float(Obj.GetValue())
3154                    if item:
3155                        V[item-1] = val
3156                    else:
3157                        A = val
3158                    Obj.SetValue('%8.5f'%(val))
3159                    V = np.inner(Amat,V)
3160                    Q = G2mth.AVdeg2Q(A,V)
3161                    if not any(Q):
3162                        raise ValueError
3163                    RBObj['Orient'][0] = Q
3164                    newXYZ = G2mth.UpdateRBAtoms(Bmat,RBObj,RBData,rbType)
3165                    for i,id in enumerate(RBObj['Ids']):
3166                        data['Atoms'][AtLookUp[id]][cx:cx+3] = newXYZ[i]
3167                    data['Drawing']['Atoms'] = []
3168                    UpdateDrawAtoms('balls & sticks')
3169                    G2plt.PlotStructure(G2frame,data)
3170                except ValueError:
3171                    pass
3172               
3173            topSizer = wx.FlexGridSizer(2,6,5,5)
3174            Orig = RBObj['Orig'][0]
3175            Orien,OrienV = G2mth.Q2AVdeg(RBObj['Orient'][0])
3176            OrienV = np.inner(Bmat,OrienV)
3177            Orien = [Orien,]
3178            Orien.extend(OrienV/nl.norm(OrienV))
3179            topSizer.Add(wx.StaticText(RigidBodies,-1,'Origin x,y,z:'),0,wx.ALIGN_CENTER_VERTICAL)
3180            for ix,x in enumerate(Orig):
3181                origX = wx.TextCtrl(RigidBodies,-1,value='%8.5f'%(x),style=wx.TE_PROCESS_ENTER)
3182                origX.Bind(wx.EVT_TEXT_ENTER,OnOrigX)
3183                origX.Bind(wx.EVT_KILL_FOCUS,OnOrigX)
3184                Indx[origX.GetId()] = ix
3185                topSizer.Add(origX,0,wx.ALIGN_CENTER_VERTICAL)
3186            topSizer.Add((5,0),)
3187            Ocheck = wx.CheckBox(RigidBodies,-1,'Refine?')
3188            Ocheck.Bind(wx.EVT_CHECKBOX,OnOrigRef)
3189            Ocheck.SetValue(RBObj['Orig'][1])
3190            topSizer.Add(Ocheck,0,wx.ALIGN_CENTER_VERTICAL)
3191            topSizer.Add(wx.StaticText(RigidBodies,-1,'Rotation angle, vector:'),0,wx.ALIGN_CENTER_VERTICAL)
3192            for ix,x in enumerate(Orien):
3193                orien = wx.TextCtrl(RigidBodies,-1,value='%8.4f'%(x),style=wx.TE_PROCESS_ENTER)
3194                orien.Bind(wx.EVT_TEXT_ENTER,OnOrien)
3195                orien.Bind(wx.EVT_KILL_FOCUS,OnOrien)
3196                Indx[orien.GetId()] = ix
3197                topSizer.Add(orien,0,wx.ALIGN_CENTER_VERTICAL)
3198            Qcheck = wx.ComboBox(RigidBodies,-1,value='',choices=[' ','A','AV'],
3199                style=wx.CB_READONLY|wx.CB_DROPDOWN)
3200            Qcheck.Bind(wx.EVT_COMBOBOX,OnOrienRef)
3201            Qcheck.SetValue(RBObj['Orient'][1])
3202            topSizer.Add(Qcheck)
3203            return topSizer
3204                         
3205        def ResrbSizer(RBObj):
3206            G2frame.dataFrame.SetStatusText('NB: Rotation vector is in crystallographic space')
3207             
3208            def OnTorsionRef(event):
3209                Obj = event.GetEventObject()
3210                item = Indx[Obj.GetId()]
3211                RBObj['Torsions'][item][1] = Obj.GetValue()               
3212               
3213            def OnTorsion(event):
3214                Obj = event.GetEventObject()
3215                item = Indx[Obj.GetId()]
3216                try:
3217                    val = float(Obj.GetValue())
3218                    RBObj['Torsions'][item][0] = val
3219                    newXYZ = G2mth.UpdateResRBAtoms(Bmat,RBObj,RBData['Residue'])
3220                    for i,id in enumerate(RBObj['Ids']):
3221                        data['Atoms'][AtLookUp[id]][cx:cx+3] = newXYZ[i]
3222                except ValueError:
3223                    pass
3224                Obj.SetValue("%10.3f"%(RBObj['Torsions'][item][0]))               
3225                data['Drawing']['Atoms'] = []
3226                UpdateDrawAtoms('balls & sticks')
3227                drawAtoms.ClearSelection()
3228                G2plt.PlotStructure(G2frame,data)
3229               
3230            def OnDelResRB(event):
3231                Obj = event.GetEventObject()
3232                RBId = Indx[Obj.GetId()]
3233                RBData['Residue'][RBId]['useCount'] -= 1
3234                RBObjs = data['RBModels']['Residue']
3235                for rbObj in RBObjs:
3236                    if RBId == rbObj['RBId']:
3237                       data['RBModels']['Residue'].remove(rbObj)                 
3238                G2plt.PlotStructure(G2frame,data)
3239                wx.CallAfter(FillRigidBodyGrid,True)
3240               
3241            resrbSizer = wx.BoxSizer(wx.VERTICAL)
3242            resrbSizer.Add(wx.StaticText(RigidBodies,-1,120*'-'))
3243            topLine = wx.BoxSizer(wx.HORIZONTAL)
3244            topLine.Add(wx.StaticText(RigidBodies,-1,
3245                'Name: '+RBObj['RBname']+RBObj['numChain']+'   '),0,wx.ALIGN_CENTER_VERTICAL)
3246            rbId = RBObj['RBId']
3247            delRB = wx.CheckBox(RigidBodies,-1,'Delete?')
3248            delRB.Bind(wx.EVT_CHECKBOX,OnDelResRB)
3249            Indx[delRB.GetId()] = rbId
3250            topLine.Add(delRB,0,wx.ALIGN_CENTER_VERTICAL)
3251            resrbSizer.Add(topLine)
3252            resrbSizer.Add(LocationSizer(RBObj,'Residue'))
3253            resrbSizer.Add(wx.StaticText(RigidBodies,-1,'Torsions:'),0,wx.ALIGN_CENTER_VERTICAL)
3254            torSizer = wx.FlexGridSizer(1,6,5,5)
3255            for itors,tors in enumerate(RBObj['Torsions']):
3256                torSizer.Add(wx.StaticText(RigidBodies,-1,'Torsion '+'%d'%(itors)),0,wx.ALIGN_CENTER_VERTICAL)
3257                torsTxt = wx.TextCtrl(RigidBodies,-1,value='%.3f'%(tors[0]),style=wx.TE_PROCESS_ENTER)
3258                torsTxt.Bind(wx.EVT_TEXT_ENTER,OnTorsion)
3259                torsTxt.Bind(wx.EVT_KILL_FOCUS,OnTorsion)
3260                Indx[torsTxt.GetId()] = itors
3261                torSizer.Add(torsTxt)
3262                torCheck = wx.CheckBox(RigidBodies,-1,'Refine?')
3263                torCheck.Bind(wx.EVT_CHECKBOX,OnTorsionRef)
3264                torCheck.SetValue(tors[1])
3265                Indx[torCheck.GetId()] = itors
3266                torSizer.Add(torCheck,0,wx.ALIGN_CENTER_VERTICAL)
3267            resrbSizer.Add(torSizer)
3268            tchoice = ['None','Uiso','T','TL','TLS']
3269            thermSizer = wx.BoxSizer(wx.HORIZONTAL)
3270            thermSizer.Add(wx.StaticText(RigidBodies,-1,'Rigid body thermal motion model: '),0,wx.ALIGN_CENTER_VERTICAL)
3271            thermSel = wx.ComboBox(RigidBodies,-1,value=RBObj['ThermalMotion'][0],choices=tchoice,
3272                style=wx.CB_READONLY|wx.CB_DROPDOWN)
3273            Indx[thermSel.GetId()] = RBObj
3274            thermSel.Bind(wx.EVT_COMBOBOX,OnThermSel)
3275            thermSizer.Add(thermSel,0,wx.ALIGN_CENTER_VERTICAL)
3276            resrbSizer.Add(thermSizer)
3277            if RBObj['ThermalMotion'][0] != 'None':
3278                resrbSizer.Add(ThermDataSizer(RBObj))
3279            return resrbSizer
3280           
3281        def VecrbSizer(RBObj):
3282            G2frame.dataFrame.SetStatusText('NB: Rotation vector is in crystallographic space')
3283                   
3284            def OnDelVecRB(event):
3285                Obj = event.GetEventObject()
3286                RBId = Indx[Obj.GetId()]
3287                RBData['Vector'][RBId]['useCount'] -= 1               
3288                RBObjs = data['RBModels']['Vector']
3289                for rbObj in RBObjs:
3290                    if RBId == rbObj['RBId']:
3291                       data['RBModels']['Vector'].remove(rbObj)                 
3292                G2plt.PlotStructure(G2frame,data)
3293                wx.CallAfter(FillRigidBodyGrid,True)
3294             
3295            vecrbSizer = wx.BoxSizer(wx.VERTICAL)
3296            vecrbSizer.Add(wx.StaticText(RigidBodies,-1,120*'-'))
3297            topLine = wx.BoxSizer(wx.HORIZONTAL)
3298            topLine.Add(wx.StaticText(RigidBodies,-1,
3299                'Name: '+RBObj['RBname']+'   '),0,wx.ALIGN_CENTER_VERTICAL)
3300            rbId = RBObj['RBId']
3301            delRB = wx.CheckBox(RigidBodies,-1,'Delete?')
3302            delRB.Bind(wx.EVT_CHECKBOX,OnDelVecRB)
3303            Indx[delRB.GetId()] = rbId
3304            topLine.Add(delRB,0,wx.ALIGN_CENTER_VERTICAL)
3305            vecrbSizer.Add(topLine)
3306            vecrbSizer.Add(LocationSizer(RBObj,'Vector'))
3307            tchoice = ['None','Uiso','T','TL','TLS']
3308            thermSizer = wx.BoxSizer(wx.HORIZONTAL)
3309            thermSizer.Add(wx.StaticText(RigidBodies,-1,'Rigid body thermal motion model: '),0,wx.ALIGN_CENTER_VERTICAL)
3310            thermSel = wx.ComboBox(RigidBodies,-1,value=RBObj['ThermalMotion'][0],choices=tchoice,
3311                style=wx.CB_READONLY|wx.CB_DROPDOWN)
3312            Indx[thermSel.GetId()] = RBObj
3313            thermSel.Bind(wx.EVT_COMBOBOX,OnThermSel)
3314            thermSizer.Add(thermSel,0,wx.ALIGN_CENTER_VERTICAL)
3315            vecrbSizer.Add(thermSizer)
3316            if RBObj['ThermalMotion'][0] != 'None':
3317                vecrbSizer.Add(ThermDataSizer(RBObj))
3318            return vecrbSizer               
3319       
3320        G2frame.dataFrame.SetStatusText('')
3321        mainSizer = wx.BoxSizer(wx.VERTICAL)
3322        if not data['RBModels']:
3323            mainSizer.Add((5,5),0)
3324            mainSizer.Add(wx.StaticText(RigidBodies,-1,'No rigid body models:'),0,wx.ALIGN_CENTER_VERTICAL)
3325            mainSizer.Add((5,5),0)
3326        if 'Residue' in data['RBModels']:
3327            mainSizer.Add((5,5),0)
3328            mainSizer.Add(wx.StaticText(RigidBodies,-1,'Residue rigid bodies:'),0,wx.ALIGN_CENTER_VERTICAL)
3329            mainSizer.Add((5,5),0)
3330            for RBObj in data['RBModels']['Residue']:
3331                mainSizer.Add(ResrbSizer(RBObj))
3332        if 'Vector' in data['RBModels']:
3333            mainSizer.Add((5,5),0)
3334            mainSizer.Add(wx.StaticText(RigidBodies,-1,'Vector rigid bodies:'),0,wx.ALIGN_CENTER_VERTICAL)
3335            mainSizer.Add((5,5),0)
3336            for RBObj in data['RBModels']['Vector']:
3337                mainSizer.Add(VecrbSizer(RBObj))
3338
3339        RigidBodies.SetSizer(mainSizer)
3340        mainSizer.FitInside(G2frame.dataFrame)
3341        Size = mainSizer.GetMinSize()
3342        Size[0] += 40
3343        Size[1] = max(Size[1],290) + 35
3344        RigidBodies.SetSize(Size)
3345        RigidBodies.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
3346        Size[1] = min(Size[1],450)
3347        G2frame.dataFrame.setSizePosLeft(Size)
3348       
3349    def OnRBCopyParms(event):
3350        RBObjs = []
3351        for rbType in ['Vector','Residue']:           
3352            RBObjs += data['RBModels'].get(rbType,[])
3353        if not len(RBObjs):
3354            print '**** ERROR - no rigid bodies defined ****'
3355            return
3356        if len(RBObjs) == 1:
3357            print '**** INFO - only one rigid body defined; nothing to copy to ****'
3358            return
3359        Source = []
3360        sourceRB = {}
3361        for RBObj in RBObjs:
3362            Source.append(RBObj['RBname'])
3363        dlg = wx.SingleChoiceDialog(G2frame,'Select source','Copy rigid body parameters',Source)
3364        if dlg.ShowModal() == wx.ID_OK:
3365            sel = dlg.GetSelection()
3366            name = Source[sel]
3367            for item in ['Orig','Orient','ThermalMotion']: 
3368                sourceRB.update({item:RBObjs[sel][item],})
3369        dlg.Destroy()
3370        if not sourceRB:
3371            return
3372        dlg = wx.MultiChoiceDialog(G2frame,'Select targets','Copy rigid body parameters',Source)
3373        if dlg.ShowModal() == wx.ID_OK:
3374            sel = dlg.GetSelections()
3375            for x in sel:
3376                RBObjs[x].update(sourceRB)
3377        G2plt.PlotStructure(G2frame,data)
3378        wx.CallAfter(FillRigidBodyGrid(True))
3379               
3380    def OnRBAssign(event):
3381       
3382        G2frame.dataFrame.SetStatusText('')
3383        RBData = G2frame.PatternTree.GetItemPyData(   
3384            G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Rigid bodies'))
3385        rbNames = {}
3386        for rbVec in RBData['Vector']:
3387            if rbVec != 'AtInfo':
3388                rbNames[RBData['Vector'][rbVec]['RBname']] =['Vector',rbVec]
3389        for rbRes in RBData['Residue']:
3390            if rbRes != 'AtInfo':
3391                rbNames[RBData['Residue'][rbRes]['RBname']] = ['Residue',rbRes]
3392        if not rbNames:
3393            print '**** ERROR - no rigid bodies defined ****'
3394            return
3395        general = data['General']
3396        Amat,Bmat = G2lat.cell2AB(general['Cell'][1:7])
3397        cx,ct = general['AtomPtrs'][:2]
3398        atomData = data['Atoms']
3399        Indx = {}
3400        atInd = [-1,-1,-1]
3401        data['testRBObj'] = {}
3402           
3403        def Draw():
3404           
3405            def OnOk(event):
3406                rbType = data['testRBObj']['rbType']
3407                RBObjs = data['RBModels'].get(rbType,[])
3408                rbObj = data['testRBObj']['rbObj']
3409                rbId = rbObj['RBId']
3410                newXYZ = G2mth.UpdateRBAtoms(Bmat,rbObj,RBData,rbType)
3411                Ids = []
3412                dmax = 0.0
3413                oldXYZ = G2mth.getAtomXYZ(atomData,cx)
3414                for xyz in newXYZ:
3415                    dist = G2mth.GetXYZDist(xyz,oldXYZ,Amat)
3416                    dmax = max(dmax,np.min(dist))
3417                    id = np.argmin(dist)
3418                    Ids.append(atomData[id][-1])
3419                    atomData[id][cx:cx+3] = xyz
3420                if dmax > 0.5:
3421                    print '**** WARNING - some atoms not found or misidentified ****'
3422                    print '****           check torsion angles & try again      ****'
3423                    OkBtn.SetLabel('Not Ready')
3424                    OkBtn.Enable(False)
3425                    return
3426                rbObj['Ids'] = Ids
3427                rbObj['ThermalMotion'] = ['None',[],[]] #type,values,flags
3428                rbObj['RBname'] += ':'+str(RBData[rbType][rbId]['useCount'])
3429                RBObjs.append(rbObj)
3430                data['RBModels'][rbType] = RBObjs
3431                RBData[rbType][rbId]['useCount'] += 1
3432                del data['testRBObj']
3433                G2plt.PlotStructure(G2frame,data)
3434                FillRigidBodyGrid(True)
3435               
3436            def OnCancel(event):
3437                del data['testRBObj']
3438                FillRigidBodyGrid(True)
3439               
3440            def OnRBSel(event):
3441                selection = rbSel.GetValue()
3442                rbType,rbId = rbNames[selection]
3443                data['testRBObj']['rbAtTypes'] = RBData[rbType][rbId]['rbTypes']
3444                data['testRBObj']['AtInfo'] = RBData[rbType]['AtInfo']
3445                data['testRBObj']['rbType'] = rbType
3446                data['testRBObj']['rbData'] = RBData
3447                data['testRBObj']['Sizers'] = {}
3448                rbRef = RBData[rbType][rbId]['rbRef']
3449                data['testRBObj']['rbRef'] = rbRef
3450                refType = []
3451                refName = []
3452                for ref in rbRef[:3]:
3453                    reftype = data['testRBObj']['rbAtTypes'][ref]
3454                    refType.append(reftype)
3455                    refName.append(reftype+' '+str(rbRef[0]))
3456                atNames,AtNames = fillAtNames(refType,atomData,ct)
3457                data['testRBObj']['atNames'] = atNames
3458                data['testRBObj']['AtNames'] = AtNames
3459                data['testRBObj']['rbObj'] = {'Orig':[[0,0,0],False],
3460                    'Orient':[[0.,0.,0.,1.],' '],'Ids':[],'RBId':rbId,'Torsions':[],
3461                    'numChain':'','RBname':RBData[rbType][rbId]['RBname']}
3462                data['testRBObj']['torAtms'] = []               
3463                for item in RBData[rbType][rbId].get('rbSeq',[]):
3464                    data['testRBObj']['rbObj']['Torsions'].append([item[2],False])
3465                    data['testRBObj']['torAtms'].append([-1,-1,-1])
3466                Draw()
3467               
3468            def fillAtNames(refType,atomData,ct):
3469                atNames = [{},{},{}]
3470                AtNames = {}
3471                for iatm,atom in enumerate(atomData):
3472                    AtNames[atom[ct-1]] = iatm
3473                    for i,reftype in enumerate(refType):
3474                        if atom[ct] == reftype:
3475                            atNames[i][atom[ct-1]] = iatm
3476                return atNames,AtNames
3477               
3478            def OnAtOrigPick(event):
3479                Obj = event.GetEventObject()
3480                item = Indx[Obj.GetId()]
3481                atName = Obj.GetValue()
3482                rbType = data['testRBObj']['rbType']
3483                atInd[0] = atNames[item][atName]
3484                if 'Vector' in rbType:
3485                    rbObj = data['testRBObj']['rbObj']
3486                    rbId = rbObj['RBId']
3487                    rbRef = data['testRBObj']['rbRef']
3488                    rbXYZ = -RBData[rbType][rbId]['rbXYZ']
3489                    nref = atNames[item][atName]
3490                    Oxyz = np.inner(Bmat,np.array(rbXYZ[rbRef[0]]))
3491                    Nxyz = np.array(atomData[nref][cx:cx+3])
3492                    Orig = Nxyz-Oxyz
3493                    data['testRBObj']['rbObj']['Orig'][0] = Orig   
3494                else:
3495                    Orig = atomData[atNames[item][atName]][cx:cx+3]
3496                    data['testRBObj']['rbObj']['Orig'][0] = Orig
3497                for x,item in zip(Orig,Xsizers):
3498                    item.SetLabel('%10.5f'%(x))
3499                G2plt.PlotStructure(G2frame,data)
3500               
3501            def OnAtQPick(event):
3502                Obj = event.GetEventObject()
3503                item = Indx[Obj.GetId()]
3504                atName = Obj.GetValue()
3505                atInd[item] = atNames[item][atName]
3506                if any([x<0 for x in atInd]):
3507                    return
3508                OkBtn.SetLabel('OK')
3509                OkBtn.Enable(True)
3510                rbType = data['testRBObj']['rbType']
3511                rbObj = data['testRBObj']['rbObj']
3512                rbId = rbObj['RBId']
3513                rbRef = data['testRBObj']['rbRef']
3514                rbXYZ = RBData[rbType][rbId]['rbXYZ']
3515                rbOrig = rbXYZ[rbRef[0]]
3516                VAR = rbXYZ[rbRef[1]]-rbOrig
3517                VBR = rbXYZ[rbRef[2]]-rbOrig
3518                if rbType == 'Vector':
3519                    Orig = np.array(atomData[atInd[0]][cx:cx+3])
3520                else:
3521                    Orig = np.array(data['testRBObj']['rbObj']['Orig'][0])               
3522                VAC = np.inner(Amat,np.array(atomData[atInd[1]][cx:cx+3])-Orig)
3523                VBC = np.inner(Amat,np.array(atomData[atInd[2]][cx:cx+3])-Orig)
3524                VCC = np.cross(VAR,VAC)
3525                QuatA = G2mth.makeQuat(VAR,VAC,VCC)[0]
3526                VAR = G2mth.prodQVQ(QuatA,VAR)
3527                VBR = G2mth.prodQVQ(QuatA,VBR)
3528                QuatB = G2mth.makeQuat(VBR,VBC,VAR)[0]
3529                QuatC = G2mth.prodQQ(QuatB,QuatA)
3530                data['testRBObj']['rbObj']['Orient'] = [QuatC,' ']
3531                for x,item in zip(QuatC,Osizers):
3532                    item.SetLabel('%10.4f'%(x))               
3533                if rbType == 'Vector':
3534                    Oxyz = np.inner(Bmat,G2mth.prodQVQ(QuatC,rbOrig))
3535                    Nxyz = np.array(atomData[atInd[0]][cx:cx+3])
3536                    Orig = Nxyz-Oxyz
3537                    data['testRBObj']['rbObj']['Orig'][0] = Orig
3538                    for x,item in zip(Orig,Xsizers):
3539                        item.SetLabel('%10.5f'%(x))
3540                G2plt.PlotStructure(G2frame,data)
3541               
3542            def OnTorAngle(event):
3543                OkBtn.SetLabel('OK')
3544                OkBtn.Enable(True)
3545                Obj = event.GetEventObject()
3546                [tor,torSlide] = Indx[Obj.GetId()]
3547                Tors = data['testRBObj']['rbObj']['Torsions'][tor]
3548                try:
3549                    value = float(Obj.GetValue())
3550                except ValueError:
3551                    value = Tors[0]
3552                Tors[0] = value
3553                Obj.SetValue('%8.3f'%(value))
3554                torSlide.SetValue(int(value*10))
3555                G2plt.PlotStructure(G2frame,data)
3556               
3557            def OnTorSlide(event):
3558                OkBtn.SetLabel('OK')
3559                OkBtn.Enable(True)
3560                Obj = event.GetEventObject()
3561                tor,ang = Indx[Obj.GetId()]
3562                Tors = data['testRBObj']['rbObj']['Torsions'][tor]
3563                val = float(Obj.GetValue())/10.
3564                Tors[0] = val
3565                ang.SetValue('%8.3f'%(val))
3566                G2plt.PlotStructure(G2frame,data)
3567
3568            if len(data['testRBObj']):
3569                G2plt.PlotStructure(G2frame,data)
3570                   
3571            RigidBodies.DestroyChildren()
3572            mainSizer = wx.BoxSizer(wx.VERTICAL)
3573            mainSizer.Add((5,5),0)
3574            if data['testRBObj']:
3575                Xsizers = []
3576                Osizers = []
3577                rbObj = data['testRBObj']['rbObj']
3578                rbName = rbObj['RBname']
3579                rbId = rbObj['RBId']
3580                Orig = rbObj['Orig'][0]
3581                Orien = rbObj['Orient'][0]
3582                rbRef = data['testRBObj']['rbRef']
3583                Torsions = rbObj['Torsions']
3584                refName = []
3585                for ref in rbRef:
3586                    refName.append(data['testRBObj']['rbAtTypes'][ref]+str(ref))
3587                atNames = data['testRBObj']['atNames']
3588                mainSizer.Add(wx.StaticText(RigidBodies,-1,'Locate rigid body : '+rbName),
3589                    0,wx.ALIGN_CENTER_VERTICAL)
3590                mainSizer.Add((5,5),0)
3591                OriSizer = wx.FlexGridSizer(1,5,5,5)
3592                OriSizer.Add(wx.StaticText(RigidBodies,-1,'Origin x,y,z: '),0,wx.ALIGN_CENTER_VERTICAL)
3593                for ix,x in enumerate(Orig):
3594                    origX = wx.StaticText(RigidBodies,-1,'%10.5f'%(x))
3595                    OriSizer.Add(origX,0,wx.ALIGN_CENTER_VERTICAL)
3596                    Xsizers.append(origX)
3597                OriSizer.Add((5,0),)
3598                if len(atomData):
3599                    choice = atNames[0].keys()
3600                    choice.sort()
3601                    data['testRBObj']['Sizers']['Xsizers'] = Xsizers
3602                OriSizer.Add(wx.StaticText(RigidBodies,-1,'Orientation quaternion: '),0,wx.ALIGN_CENTER_VERTICAL)
3603                for ix,x in enumerate(Orien):
3604                    orien = wx.StaticText(RigidBodies,-1,'%10.4f'%(x))
3605                    OriSizer.Add(orien,0,wx.ALIGN_CENTER_VERTICAL)
3606                    Osizers.append(orien)
3607                data['testRBObj']['Sizers']['Osizers'] = Osizers
3608                mainSizer.Add(OriSizer)
3609                mainSizer.Add((5,5),0)
3610                RefSizer = wx.FlexGridSizer(1,7,5,5)
3611                if len(atomData):
3612                    RefSizer.Add(wx.StaticText(RigidBodies,-1,'Location setting: Select match to'),0,wx.ALIGN_CENTER_VERTICAL)
3613                    for i in [0,1,2]:
3614                        choice = ['',]+atNames[i].keys()
3615                        choice.sort()
3616                        RefSizer.Add(wx.StaticText(RigidBodies,-1,' '+refName[i]+': '),0,wx.ALIGN_CENTER_VERTICAL)
3617                        atPick = wx.ComboBox(RigidBodies,-1,value='',
3618                            choices=choice[1:],style=wx.CB_READONLY|wx.CB_DROPDOWN)
3619                        if i:
3620                            atPick.Bind(wx.EVT_COMBOBOX, OnAtQPick)
3621                        else:
3622                            atPick.Bind(wx.EVT_COMBOBOX, OnAtOrigPick)                           
3623                        Indx[atPick.GetId()] = i
3624                        RefSizer.Add(atPick,0,wx.ALIGN_CENTER_VERTICAL)
3625                mainSizer.Add(RefSizer)
3626                mainSizer.Add((5,5),0)
3627                if Torsions:                   
3628                    AtNames = data['testRBObj']['AtNames']
3629                    rbAtTypes = data['testRBObj']['rbAtTypes']
3630                    rbSeq = RBData['Residue'][rbId]['rbSeq']
3631                    TorSizer = wx.FlexGridSizer(1,4)
3632                    TorSizer.AddGrowableCol(1,1)
3633                    for t,[torsion,seq] in enumerate(zip(Torsions,rbSeq)):
3634                        torName = ''
3635                        for item in [seq[0],seq[1],seq[3][0]]:
3636                            torName += data['testRBObj']['rbAtTypes'][item]+str(item)+' '
3637                        TorSizer.Add(wx.StaticText(RigidBodies,-1,'Side chain torsion for rb seq: '+torName),0,wx.ALIGN_CENTER_VERTICAL)
3638                        torSlide = wx.Slider(RigidBodies,style=wx.SL_HORIZONTAL)
3639                        torSlide.SetRange(0,3600)
3640                        torSlide.SetValue(int(torsion[0]*10.))
3641                        torSlide.Bind(wx.EVT_SLIDER, OnTorSlide)
3642                        TorSizer.Add(torSlide,1,wx.EXPAND|wx.RIGHT)
3643                        TorSizer.Add(wx.StaticText(RigidBodies,-1,' Angle: '),0,wx.ALIGN_CENTER_VERTICAL)
3644                        ang = wx.TextCtrl(RigidBodies,-1,value='%8.3f'%(torsion[0]),style=wx.TE_PROCESS_ENTER)
3645                        ang.Bind(wx.EVT_TEXT_ENTER,OnTorAngle)
3646                        ang.Bind(wx.EVT_KILL_FOCUS,OnTorAngle)
3647                        Indx[torSlide.GetId()] = [t,ang]
3648                        Indx[ang.GetId()] = [t,torSlide]
3649                        TorSizer.Add(ang,0,wx.ALIGN_CENTER_VERTICAL)                           
3650                    mainSizer.Add(TorSizer,1,wx.EXPAND|wx.RIGHT)
3651                else:
3652                    mainSizer.Add(wx.StaticText(RigidBodies,-1,'No side chain torsions'),0,wx.ALIGN_CENTER_VERTICAL)
3653            else:
3654                mainSizer.Add(wx.StaticText(RigidBodies,-1,'Assign rigid body:'),0,wx.ALIGN_CENTER_VERTICAL)
3655                mainSizer.Add((5,5),0)
3656                topSizer = wx.BoxSizer(wx.HORIZONTAL)
3657                topSizer.Add(wx.StaticText(RigidBodies,-1,'Select rigid body model'),0,wx.ALIGN_CENTER_VERTICAL)
3658                rbSel = wx.ComboBox(RigidBodies,-1,value='',choices=rbNames.keys(),
3659                    style=wx.CB_READONLY|wx.CB_DROPDOWN)
3660                rbSel.Bind(wx.EVT_COMBOBOX, OnRBSel)
3661                topSizer.Add((5,5),0)
3662                topSizer.Add(rbSel,0,wx.ALIGN_CENTER_VERTICAL)
3663                mainSizer.Add(topSizer)               
3664               
3665            OkBtn = wx.Button(RigidBodies,-1,"Not ready")
3666            OkBtn.Bind(wx.EVT_BUTTON, OnOk)
3667            OkBtn.Enable(False)
3668            CancelBtn = wx.Button(RigidBodies,-1,'Cancel')
3669            CancelBtn.Bind(wx.EVT_BUTTON, OnCancel)
3670            btnSizer = wx.BoxSizer(wx.HORIZONTAL)
3671            btnSizer.Add((20,20),1)
3672            btnSizer.Add(OkBtn)
3673            btnSizer.Add(CancelBtn)
3674            btnSizer.Add((20,20),1)
3675            mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
3676            RigidBodies.SetSizer(mainSizer)
3677            Size = mainSizer.Fit(RigidBodies)
3678            Size[0] += 40
3679            Size[1] = min(max(Size[1],290) + 35,560)
3680            RigidBodies.SetSize(Size)
3681            RigidBodies.SetScrollbars(10,10,Size[0]/10-4,Size[1]/10-1)
3682            G2frame.dataFrame.setSizePosLeft(Size)
3683        Draw()
3684       
3685    def OnAutoFindResRB(event):
3686        RBData = G2frame.PatternTree.GetItemPyData(   
3687            G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Rigid bodies'))
3688        rbKeys = RBData['Residue'].keys()
3689        rbKeys.remove('AtInfo')
3690        if not len(rbKeys):
3691            print '**** ERROR - no residue rigid bodies are defined ****'
3692            return
3693        RBNames = [RBData['Residue'][k]['RBname'] for k in rbKeys]
3694        RBIds = dict(zip(RBNames,rbKeys))
3695        general = data['General']
3696        Amat,Bmat = G2lat.cell2AB(general['Cell'][1:7])
3697        Atoms = data['Atoms']
3698        AtLookUp = G2mth.FillAtomLookUp(Atoms)
3699        if 'macro' not in general['Type']:
3700            print '**** ERROR - this phase is not a macromolecule ****'
3701            return
3702        if not len(Atoms):
3703            print '**** ERROR - this phase has no atoms ****'
3704            return
3705        RBObjs = []
3706        cx,ct = general['AtomPtrs'][:2]
3707        iatm = 0
3708        wx.BeginBusyCursor()
3709        try:
3710            while iatm < len(Atoms):
3711                atom = Atoms[iatm]
3712                res = atom[1].strip()
3713                numChain = ' %s %s'%(atom[0],atom[2])
3714                if res not in RBIds or atom[ct-1] == 'OXT':
3715                    iatm += 1
3716                    continue        #skip for OXT, water molecules, etc.
3717                rbRes = RBData['Residue'][RBIds[res]]
3718                rbRef = rbRes['rbRef']
3719                VAR = rbRes['rbXYZ'][rbRef[1]]-rbRes['rbXYZ'][rbRef[0]]
3720                VBR = rbRes['rbXYZ'][rbRef[2]]-rbRes['rbXYZ'][rbRef[0]]
3721                rbObj = {'RBname':rbRes['RBname']+':'+str(rbRes['useCount']),'numChain':numChain}
3722                rbAtoms = []
3723                rbIds = []
3724                for iratm in range(len(rbRes['atNames'])):
3725                    rbAtoms.append(np.array(Atoms[iatm][cx:cx+3]))
3726                    rbIds.append(Atoms[iatm][20])
3727                    iatm += 1    #puts this at beginning of next residue?
3728                Orig = rbAtoms[rbRef[0]]
3729                rbObj['RBId'] = RBIds[res]
3730                rbObj['Ids'] = rbIds
3731                rbObj['Orig'] = [Orig,False]
3732#                print ' residue '+rbRes['RBname']+str(atom[0]).strip()+ \
3733#                    ' origin at: ','%.5f %.5f %.5f'%(Orig[0],Orig[1],Orig[2])
3734                VAC = np.inner(Amat,rbAtoms[rbRef[1]]-Orig)
3735                VBC = np.inner(Amat,rbAtoms[rbRef[2]]-Orig)
3736                VCC = np.cross(VAR,VAC)
3737                QuatA = G2mth.makeQuat(VAR,VAC,VCC)[0]
3738                VAR = G2mth.prodQVQ(QuatA,VAR)
3739                VBR = G2mth.prodQVQ(QuatA,VBR)
3740                QuatB = G2mth.makeQuat(VBR,VBC,VAR)[0]
3741                QuatC = G2mth.prodQQ(QuatB,QuatA)
3742                rbObj['Orient'] = [QuatC,' ']
3743                rbObj['ThermalMotion'] = ['None',[],[]] #type,values,flags
3744                SXYZ = []
3745                TXYZ = []
3746                rbObj['Torsions'] = []
3747                for i,xyz in enumerate(rbRes['rbXYZ']):
3748                    SXYZ.append(G2mth.prodQVQ(QuatC,xyz))               
3749                    TXYZ.append(np.inner(Amat,rbAtoms[i]-Orig))
3750                for Oatm,Patm,x,Riders in rbRes['rbSeq']:
3751                    VBR = SXYZ[Oatm]-SXYZ[Patm]
3752                    VAR = SXYZ[Riders[0]]-SXYZ[Patm]
3753                    VAC = TXYZ[Riders[0]]-TXYZ[Patm]
3754                    QuatA,D = G2mth.makeQuat(VAR,VAC,VBR)
3755                    ang = 180.*D/np.pi
3756                    rbObj['Torsions'].append([ang,False])
3757                    for ride in Riders:
3758                        SXYZ[ride] = G2mth.prodQVQ(QuatA,SXYZ[ride]-SXYZ[Patm])+SXYZ[Patm]
3759                rbRes['useCount'] += 1
3760                RBObjs.append(rbObj)
3761            data['RBModels']['Residue'] = RBObjs
3762            for RBObj in RBObjs:
3763                newXYZ = G2mth.UpdateResRBAtoms(Bmat,RBObj,RBData['Residue'])
3764                for i,id in enumerate(RBObj['Ids']):
3765                    data['Atoms'][AtLookUp[id]][cx:cx+3] = newXYZ[i]
3766        finally:
3767            wx.EndBusyCursor()
3768        wx.CallAfter(FillRigidBodyGrid,True)
3769       
3770    def OnRBRemoveAll(event):
3771        data['RBModels']['Residue'] = []
3772        data['RBModels']['Vector'] = []   
3773        RBData = G2frame.PatternTree.GetItemPyData(   
3774            G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Rigid bodies'))
3775        for RBType in ['Vector','Residue']:
3776            for rbId in RBData[RBType]:
3777                RBData[RBType][rbId]['useCount'] = 0       
3778        FillRigidBodyGrid(True)
3779       
3780    def OnGlobalResRBRef(event):
3781        RBObjs = data['RBModels']['Residue']
3782        names = ['Origin','Orientation',]
3783        nTor = 0
3784        for rbObj in RBObjs:
3785            nTor = max(nTor,len(rbObj['Torsions']))
3786        names += ['Torsion '+str(i) for i in range(nTor)]
3787        dlg = wx.MultiChoiceDialog(G2frame,'Select','Refinement controls',names)
3788        if dlg.ShowModal() == wx.ID_OK:
3789            sel = dlg.GetSelections()
3790            parms = []
3791            for x in sel:
3792                parms.append(names[x])
3793            wx.BeginBusyCursor()
3794            try:
3795                for rbObj in RBObjs:
3796                    if 'Origin' in parms:
3797                        rbObj['Orig'][1] = True
3798                    else:
3799                        rbObj['Orig'][1] = False
3800                    if 'Orientation' in parms:
3801                        rbObj['Orient'][1] = 'Q'
3802                    else:
3803                        rbObj['Orient'][1] = ' '
3804                    for i in range(len(rbObj['Torsions'])):
3805                        if 'Torsion '+str(i) in parms:
3806                            rbObj['Torsions'][i][1] = True
3807                        else:
3808                            rbObj['Torsions'][i][1] = False           
3809            finally:
3810                wx.EndBusyCursor()
3811            FillRigidBodyGrid()
3812                       
3813
3814################################################################################
3815##### Pawley routines
3816################################################################################
3817
3818    def FillPawleyReflectionsGrid():
3819        G2frame.dataFrame.SetStatusText('')
3820                       
3821        def KeyEditPawleyGrid(event):
3822            colList = G2frame.PawleyRefl.GetSelectedCols()
3823            PawleyPeaks = data['Pawley ref']
3824            if event.GetKeyCode() == wx.WXK_RETURN:
3825                event.Skip(True)
3826            elif event.GetKeyCode() == wx.WXK_CONTROL:
3827                event.Skip(True)
3828            elif event.GetKeyCode() == wx.WXK_SHIFT:
3829                event.Skip(True)
3830            elif colList:
3831                G2frame.PawleyRefl.ClearSelection()
3832                key = event.GetKeyCode()
3833                for col in colList:
3834                    if PawleyTable.GetTypeName(0,col) == wg.GRID_VALUE_BOOL:
3835                        if key == 89: #'Y'
3836                            for row in range(PawleyTable.GetNumberRows()): PawleyPeaks[row][col]=True
3837                        elif key == 78:  #'N'
3838                            for row in range(PawleyTable.GetNumberRows()): PawleyPeaks[row][col]=False
3839                        FillPawleyReflectionsGrid()
3840           
3841        if 'Pawley ref' in data:
3842            PawleyPeaks = data['Pawley ref']                       
3843            rowLabels = []
3844            for i in range(len(PawleyPeaks)): rowLabels.append(str(i))
3845            colLabels = ['h','k','l','mul','d','refine','Fsq(hkl)','sig(Fsq)']
3846            Types = 4*[wg.GRID_VALUE_LONG,]+[wg.GRID_VALUE_FLOAT+':10,4',wg.GRID_VALUE_BOOL,]+ \
3847                2*[wg.GRID_VALUE_FLOAT+':10,2',]
3848            PawleyTable = G2gd.Table(PawleyPeaks,rowLabels=rowLabels,colLabels=colLabels,types=Types)
3849            G2frame.PawleyRefl.SetTable(PawleyTable, True)
3850            G2frame.PawleyRefl.Bind(wx.EVT_KEY_DOWN, KeyEditPawleyGrid)                 
3851            for r in range(G2frame.PawleyRefl.GetNumberRows()):
3852                for c in range(G2frame.PawleyRefl.GetNumberCols()):
3853                    if c in [5,6]:
3854                        G2frame.PawleyRefl.SetReadOnly(r,c,isReadOnly=False)
3855                    else:
3856                        G2frame.PawleyRefl.SetCellStyle(r,c,VERY_LIGHT_GREY,True)
3857            G2frame.PawleyRefl.SetMargins(0,0)
3858            G2frame.PawleyRefl.AutoSizeColumns(False)
3859            G2frame.dataFrame.setSizePosLeft([500,300])
3860                   
3861    def OnPawleyLoad(event):
3862        generalData = data['General']
3863        dmin = generalData['Pawley dmin']
3864        cell = generalData['Cell'][1:7]
3865        A = G2lat.cell2A(cell)
3866        SGData = generalData['SGData']
3867        HKLd = np.array(G2lat.GenHLaue(dmin,SGData,A))
3868        PawleyPeaks = []
3869        wx.BeginBusyCursor()
3870        try:
3871            for h,k,l,d in HKLd:
3872                ext,mul = G2spc.GenHKLf([h,k,l],SGData)[:2]
3873                if not ext:
3874                    mul *= 2        #for powder multiplicity
3875                    PawleyPeaks.append([h,k,l,mul,d,False,100.0,1.0])
3876        finally:
3877            wx.EndBusyCursor()
3878        data['Pawley ref'] = PawleyPeaks
3879        FillPawleyReflectionsGrid()
3880       
3881    def OnPawleyEstimate(event):
3882        try:
3883            Refs = data['Pawley ref']
3884            Histograms = data['Histograms']
3885        except KeyError:
3886            print '**** Error - no histograms defined for this phase ****'
3887            return
3888        HistoNames = Histograms.keys()
3889        PatternId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,HistoNames[0])
3890        xdata = G2frame.PatternTree.GetItemPyData(PatternId)[1]
3891        Inst = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId,'Instrument Parameters'))[0]
3892        Sample = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId,'Sample Parameters'))
3893        wave = G2mth.getWave(Inst)
3894        posCorr = Inst['Zero'][1]
3895        const = 9.e-2/(np.pi*Sample['Gonio. radius'])                  #shifts in microns
3896       
3897        wx.BeginBusyCursor()
3898        try:
3899            for ref in Refs:
3900                pos = 2.0*asind(wave/(2.0*ref[4]))
3901                if 'Bragg' in Sample['Type']:
3902                    pos -= const*(4.*Sample['Shift'][0]*cosd(pos/2.0)+ \
3903                        Sample['Transparency'][0]*sind(pos)*100.0)            #trans(=1/mueff) in cm
3904                else:               #Debye-Scherrer - simple but maybe not right
3905                    pos -= const*(Sample['DisplaceX'][0]*cosd(pos)+Sample['DisplaceY'][0]*sind(pos))
3906                indx = np.searchsorted(xdata[0],pos)
3907                try:
3908                    FWHM = max(0.001,G2pwd.getFWHM(pos,Inst))/2.
3909                    dx = xdata[0][indx+1]-xdata[0][indx]
3910                    ref[6] = FWHM*(xdata[1][indx]-xdata[4][indx])*cosd(pos/2.)**3/dx
3911                    Lorenz = 1./(2.*sind(xdata[0][indx]/2.)**2*cosd(xdata[0][indx]/2.))           #Lorentz correction
3912                    pola,dIdPola = G2pwd.Polarization(Inst['Polariz.'][1],xdata[0][indx],Inst['Azimuth'][1])
3913                    ref[6] /= (Lorenz*pola*ref[3])
3914                except IndexError:
3915                    pass
3916        finally:
3917            wx.EndBusyCursor()
3918        FillPawleyReflectionsGrid()
3919
3920    def OnPawleyUpdate(event):
3921        try:
3922            Refs = data['Pawley ref']
3923            Histograms = data['Histograms']
3924        except KeyError:
3925            print '**** Error - no histograms defined for this phase ****'
3926            return
3927        HistoNames = Histograms.keys()
3928        PatternId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,HistoNames[0])
3929        refData = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId,'Reflection Lists'))[PhaseName]
3930
3931        wx.BeginBusyCursor()
3932        try:
3933            for iref,ref in enumerate(Refs):
3934                try:
3935                    if refData[iref][9] < 0.:
3936                        ref[6] = abs(refData[iref][9])
3937                        ref[7] = 1.0
3938                except IndexError:
3939                    pass
3940        finally:
3941            wx.EndBusyCursor()
3942        FillPawleyReflectionsGrid()
3943                           
3944    def OnPawleyDelete(event):          #doesn't work
3945        dlg = wx.MessageDialog(G2frame,'Do you really want to delete selected Pawley reflections?','Delete', 
3946            wx.YES_NO | wx.ICON_QUESTION)
3947        try:
3948            result = dlg.ShowModal()
3949            if result == wx.ID_YES: 
3950                Refs = data['Pawley ref']
3951                Ind = G2frame.PawleyRefl.GetSelectedRows()
3952                Ind.sort()
3953                Ind.reverse()
3954                for ind in Ind:
3955                    Refs = np.delete(Refs,ind,0)
3956                data['Pawley ref'] = Refs
3957                FillPawleyReflectionsGrid()
3958        finally:
3959            dlg.Destroy()
3960
3961################################################################################
3962##### Fourier routines
3963################################################################################
3964
3965    def FillMapPeaksGrid():
3966                       
3967        def RowSelect(event):
3968            r,c =  event.GetRow(),event.GetCol()
3969            if r < 0 and c < 0:
3970                if MapPeaks.IsSelection():
3971                    MapPeaks.ClearSelection()
3972                else:
3973                    for row in range(MapPeaks.GetNumberRows()):
3974                        MapPeaks.SelectRow(row,True)
3975                   
3976            elif c < 0:                   #only row clicks
3977                if event.ControlDown():                   
3978                    if r in MapPeaks.GetSelectedRows():
3979                        MapPeaks.DeselectRow(r)
3980                    else:
3981                        MapPeaks.SelectRow(r,True)
3982                elif event.ShiftDown():
3983                    indxs = MapPeaks.GetSelectedRows()
3984                    MapPeaks.ClearSelection()
3985                    ibeg = 0
3986                    if indxs:
3987                        ibeg = indxs[-1]
3988                    for row in range(ibeg,r+1):
3989                        MapPeaks.SelectRow(row,True)
3990                else:
3991                    MapPeaks.ClearSelection()
3992                    MapPeaks.SelectRow(r,True)
3993            elif r < 0:                 #a column pick
3994                mapPeaks = data['Map Peaks']
3995                c =  event.GetCol()
3996                if colLabels[c] == 'mag':
3997                    mapPeaks = G2mth.sortArray(mapPeaks,c,reverse=True)
3998                elif colLabels[c] in ['x','y','z','dzero']:
3999                    mapPeaks = G2mth.sortArray(mapPeaks,c)
4000                else:
4001                    return
4002                data['Map Peaks'] = mapPeaks
4003                wx.CallAfter(FillMapPeaksGrid)
4004            G2plt.PlotStructure(G2frame,data)                   
4005           
4006        G2frame.dataFrame.setSizePosLeft([450,300])
4007        G2frame.dataFrame.SetStatusText('')
4008        if 'Map Peaks' in data:
4009            G2frame.dataFrame.SetStatusText('Select mag or dzero columns to sort')
4010            mapPeaks = data['Map Peaks']                       
4011            rowLabels = []
4012            for i in range(len(mapPeaks)): rowLabels.append(str(i))
4013            colLabels = ['mag','x','y','z','dzero']
4014            Types = 5*[wg.GRID_VALUE_FLOAT+':10,4',]
4015            G2frame.MapPeaksTable = G2gd.Table(mapPeaks,rowLabels=rowLabels,colLabels=colLabels,types=Types)
4016            MapPeaks.SetTable(G2frame.MapPeaksTable, True)
4017            MapPeaks.Bind(wg.EVT_GRID_LABEL_LEFT_CLICK, RowSelect)
4018            for r in range(MapPeaks.GetNumberRows()):
4019                for c in range(MapPeaks.GetNumberCols()):
4020                    MapPeaks.SetCellStyle(r,c,VERY_LIGHT_GREY,True)
4021            MapPeaks.SetMargins(0,0)
4022            MapPeaks.AutoSizeColumns(False)
4023                   
4024    def OnPeaksMove(event):
4025        if 'Map Peaks' in data:
4026            mapPeaks = np.array(data['Map Peaks'])
4027            peakMax = np.max(mapPeaks.T[0])
4028            Ind = MapPeaks.GetSelectedRows()
4029            for ind in Ind:
4030                mag,x,y,z,d = mapPeaks[ind]
4031                AtomAdd(x,y,z,'H',Name='M '+'%d'%(int(100*mag/peakMax)))
4032   
4033    def OnPeaksClear(event):
4034        data['Map Peaks'] = []
4035        FillMapPeaksGrid()
4036        G2plt.PlotStructure(G2frame,data)
4037       
4038    def OnPeaksDelete(event):
4039        if 'Map Peaks' in data:
4040            mapPeaks = data['Map Peaks']
4041            Ind = MapPeaks.GetSelectedRows()
4042            Ind.sort()
4043            Ind.reverse()
4044            for ind in Ind:
4045                mapPeaks = np.delete(mapPeaks,ind,0)
4046            data['Map Peaks'] = mapPeaks
4047        FillMapPeaksGrid()
4048        G2plt.PlotStructure(G2frame,data)
4049       
4050    def OnPeaksEquiv(event):
4051        if 'Map Peaks' in data:
4052            mapPeaks = data['Map Peaks']
4053            Ind = MapPeaks.GetSelectedRows()
4054            if Ind:
4055                wx.BeginBusyCursor()
4056                try:
4057                    Ind = G2mth.PeaksEquiv(data,Ind)
4058                    for r in range(MapPeaks.GetNumberRows()):
4059                        if r in Ind:
4060                            MapPeaks.SelectRow(r,addToSelected=True)
4061                        else:
4062                            MapPeaks.DeselectRow(r)
4063                finally:
4064                    wx.EndBusyCursor()
4065                G2plt.PlotStructure(G2frame,data)
4066
4067    def OnShowBonds(event):
4068        generalData = data['General']
4069        if generalData['Map']['Show bonds']:
4070            generalData['Map']['Show bonds'] = False
4071            G2frame.dataFrame.MapPeaksEdit.SetLabel(G2gd.wxID_SHOWBONDS,'Show bonds')
4072        else:
4073            generalData['Map']['Show bonds'] = True
4074            G2frame.dataFrame.MapPeaksEdit.SetLabel(G2gd.wxID_SHOWBONDS,'Hide bonds')
4075        FillMapPeaksGrid()
4076        G2plt.PlotStructure(G2frame,data)
4077               
4078    def OnPeaksUnique(event):
4079        if 'Map Peaks' in data:
4080            mapPeaks = data['Map Peaks']
4081            Ind = MapPeaks.GetSelectedRows()
4082            if Ind:
4083                wx.BeginBusyCursor()
4084                try:
4085                    Ind = G2mth.PeaksUnique(data,Ind)
4086                    for r in range(MapPeaks.GetNumberRows()):
4087                        if r in Ind:
4088                            MapPeaks.SelectRow(r,addToSelected=True)
4089                        else:
4090                            MapPeaks.DeselectRow(r)
4091                finally:
4092                    wx.EndBusyCursor()
4093                G2plt.PlotStructure(G2frame,data)
4094               
4095    def OnPeaksViewPoint(event):
4096        # set view point
4097        indx = MapPeaks.GetSelectedRows()
4098        if not indx:
4099            print '***** ERROR - no peaks selected'
4100            return
4101        mapPeaks = data['Map Peaks']
4102        drawingData = data['Drawing']
4103        drawingData['viewPoint'][0] = mapPeaks[indx[0]][1:4]
4104        G2plt.PlotStructure(G2frame,data)
4105   
4106    def OnPeaksDistVP(event):
4107        # distance to view point
4108        indx = MapPeaks.GetSelectedRows()
4109        if not indx:
4110            print '***** ERROR - no peaks selected'
4111            return
4112        generalData = data['General']
4113        Amat,Bmat = G2lat.cell2AB(generalData['Cell'][1:7])           
4114        mapPeaks = data['Map Peaks']
4115        drawingData = data['Drawing']
4116        viewPt = np.array(drawingData['viewPoint'][0])
4117        print ' Distance from view point at %.3f %.3f %.3f to:'%(viewPt[0],viewPt[1],viewPt[2])
4118        colLabels = [MapPeaks.GetColLabelValue(c) for c in range(MapPeaks.GetNumberCols())]
4119        cx = colLabels.index('x')
4120        cm = colLabels.index('mag')
4121        for i in indx:
4122            peak = mapPeaks[i]
4123            Dx = np.array(peak[cx:cx+3])-viewPt
4124            dist = np.sqrt(np.sum(np.inner(Amat,Dx)**2,axis=0))
4125            print 'Peak: %5d mag= %8.2f distance = %.3f'%(i,peak[cm],dist)
4126
4127    def OnPeaksDA(event):
4128        #distance, angle
4129        indx = MapPeaks.GetSelectedRows()
4130        if len(indx) not in [2,3]:
4131            print '**** ERROR - wrong number of atoms for distance or angle calculation'
4132            return
4133        generalData = data['General']
4134        Amat,Bmat = G2lat.cell2AB(generalData['Cell'][1:7])           
4135        mapPeaks = data['Map Peaks']
4136        xyz = []
4137        for i in indx:
4138            xyz.append(mapPeaks[i][1:4])
4139        if len(indx) == 2:
4140            print ' distance for atoms %s = %.3f'%(str(indx),G2mth.getRestDist(xyz,Amat))
4141        else:
4142            print ' angle for atoms %s = %.2f'%(str(indx),G2mth.getRestAngle(xyz,Amat))
4143