source: trunk/GSASIIphsGUI.py @ 1076

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

again fix MC/SA window scroll behavior & small start on dummy histograms

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