source: trunk/GSASIIphsGUI.py @ 855

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

RB input mostly finished; now has thermal motion models

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