source: trunk/GSASIIphsGUI.py @ 949

Last change on this file since 949 was 949, checked in by vondreele, 10 years ago

changes to MC/SA stuff

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