source: trunk/GSASIIphsGUI.py @ 1160

Last change on this file since 1160 was 1160, checked in by toby, 8 years ago

finish ISODISPLACE fixes; improve show var window; improve help window; add refine checkbox for newvars in constraints display

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