source: trunk/GSASIIphsGUI.py @ 953

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

fixes to RB refinement & MC/SA

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