source: trunk/GSASIIphsGUI.py @ 1147

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

Complete initial ISODISPLACE implementation; mod. phase initialization; change atom pointer init.; rework parameter display window

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