source: trunk/GSASIIphsGUI.py @ 1486

Last change on this file since 1486 was 1486, checked in by toby, 9 years ago

minor bugs

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