source: trunk/GSASIIphsGUI.py @ 1142

Last change on this file since 1142 was 1142, checked in by vondreele, 12 years ago

add 2*Fo-Fc omit to Fourier map collection

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 248.4 KB
Line 
1# -*- coding: utf-8 -*-
2#GSASII - phase data display routines
3########### SVN repository information ###################
4# $Date: 2013-11-07 21:47:59 +0000 (Thu, 07 Nov 2013) $
5# $Author: vondreele $
6# $Revision: 1142 $
7# $URL: trunk/GSASIIphsGUI.py $
8# $Id: GSASIIphsGUI.py 1142 2013-11-07 21:47:59Z 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: 1142 $")
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','2Fo-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        generalData = data['General']
1629        cx,ct,cs,cia = generalData['AtomPtrs']
1630        reqrdr = G2frame.dataFrame.ReImportMenuId.get(event.GetId())
1631        rdlist = G2frame.OnImportGeneric(reqrdr,
1632            G2frame.ImportPhaseReaderlist,'phase')
1633        if len(rdlist) == 0: return
1634        # rdlist is only expected to have one element
1635        rd = rdlist[0]
1636        G2frame.OnFileSave(event)
1637        # rd contains all info for a phase
1638        PhaseName = rd.Phase['General']['Name']
1639        print 'Read phase '+str(PhaseName)+' from file '+str(G2frame.lastimport)
1640        atomData = data['Atoms']
1641        atomNames = []
1642        for atom in atomData:
1643            atomNames.append(atom[:ct+1])
1644        for atom in rd.Phase['Atoms']:
1645            try:
1646                idx = atomNames.index(atom[:ct+1])
1647                atomData[idx][:-1] = atom[:-1]
1648            except ValueError:
1649                print atom[:ct+1], 'not in Atom array; not updated'
1650        wx.CallAfter(FillAtomsGrid,Atoms)
1651         
1652                       
1653################################################################################
1654#Structure drawing GUI stuff               
1655################################################################################
1656
1657    def SetupDrawingData():
1658        generalData = data['General']
1659        Amat,Bmat = G2lat.cell2AB(generalData['Cell'][1:7])
1660        atomData = data['Atoms']
1661        AA3letter = ['ALA','ARG','ASN','ASP','CYS','GLN','GLU','GLY','HIS','ILE',
1662            'LEU','LYS','MET','PHE','PRO','SER','THR','TRP','TYR','VAL','MSE','HOH','WAT','UNK']
1663        AA1letter = ['A','R','N','D','C','Q','E','G','H','I',
1664            'L','K','M','F','P','S','T','W','Y','V','M',' ',' ',' ']
1665        defaultDrawing = {'Atoms':[],'viewPoint':[[0.5,0.5,0.5],[]],'showHydrogen':True,
1666            'backColor':[0,0,0],'depthFog':False,'Zclip':50.0,'cameraPos':50.,'Zstep':0.5,
1667            'radiusFactor':0.85,'contourLevel':1.,'bondRadius':0.1,'ballScale':0.33,
1668            'vdwScale':0.67,'ellipseProb':50,'sizeH':0.50,'unitCellBox':True,
1669            'showABC':True,'selectedAtoms':[],'Atoms':[],'oldxy':[],
1670            'bondList':{},'viewDir':[1,0,0]}
1671        V0 = np.array([0,0,1])
1672        V = np.inner(Amat,V0)
1673        V /= np.sqrt(np.sum(V**2))
1674        A = np.arccos(np.sum(V*V0))
1675        defaultDrawing['Quaternion'] = G2mth.AV2Q(A,[0,1,0])
1676        try:
1677            drawingData = data['Drawing']
1678        except KeyError:
1679            data['Drawing'] = {}
1680            drawingData = data['Drawing']
1681        if not drawingData:                 #fill with defaults if empty
1682            drawingData.update(defaultDrawing)
1683        if 'Zstep' not in drawingData:
1684            drawingData['Zstep'] = 0.5
1685        if 'contourLevel' not in drawingData:
1686            drawingData['contourLevel'] = 1.
1687        if 'viewDir' not in drawingData:
1688            drawingData['viewDir'] = [0,0,1]
1689        if 'Quaternion' not in drawingData:
1690            drawingData['Quaternion'] = G2mth.AV2Q(2*np.pi,np.inner(Amat,[0,0,1]))
1691        if 'showRigidBodies' not in drawingData:
1692            drawingData['showRigidBodies'] = True
1693        cx,ct,cs,ci = [0,0,0,0]
1694        if generalData['Type'] == 'nuclear':
1695            cx,ct,cs,ci = [2,1,6,17]         #x, type, style & index
1696        elif generalData['Type'] == 'macromolecular':
1697            cx,ct,cs,ci = [5,4,9,20]         #x, type, style & index
1698        elif generalData['Type'] == 'magnetic':
1699            cx,ct,cs,ci = [2,1,6,20]         #x, type, style & index
1700#        elif generalData['Type'] == 'modulated':
1701#           ?????   for future
1702        drawingData['atomPtrs'] = [cx,ct,cs,ci]
1703        if not drawingData.get('Atoms'):
1704            for atom in atomData:
1705                DrawAtomAdd(drawingData,atom)
1706            data['Drawing'] = drawingData
1707           
1708    def DrawAtomAdd(drawingData,atom):
1709        drawingData['Atoms'].append(MakeDrawAtom(atom))
1710       
1711    def OnRestraint(event):       
1712        indx = drawAtoms.GetSelectedRows()
1713        restData = G2frame.PatternTree.GetItemPyData(   
1714            G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Restraints'))
1715        drawingData = data['Drawing']
1716        generalData = data['General']
1717        Amat,Bmat = G2lat.cell2AB(generalData['Cell'][1:7])           
1718        cx,ct,cs,ci = drawingData['atomPtrs']
1719        atomData = drawingData['Atoms']
1720        atNames = []
1721        atXYZ = []
1722        atSymOp = []
1723        atIndx = []
1724        for item in indx:
1725            atXYZ.append(np.array(atomData[item][cx:cx+3]))
1726            atSymOp.append(atomData[item][cs-1])
1727            atIndx.append(atomData[item][ci])
1728        if event.GetId() == G2gd.wxID_DRAWRESTRBOND and len(indx) == 2:
1729            try:
1730                bondData = restData[PhaseName]['Bond']
1731            except KeyError:
1732                bondData = {'wtFactor':1.0,'Bonds':[],'Use':True}
1733                restData[PhaseName] = {}
1734                restData[PhaseName]['Bond'] = bondData
1735            dist = G2mth.getRestDist(atXYZ,Amat)
1736            bondData['Bonds'].append([atIndx,atSymOp,1.54,0.01])
1737        elif event.GetId() == G2gd.wxID_DRAWRESTRANGLE and len(indx) == 3:
1738            try:
1739                angleData = restData[PhaseName]['Angle']
1740            except KeyError:
1741                angleData = {'wtFactor':1.0,'Angles':[],'Use':True}
1742                restData[PhaseName] = {}
1743                restData[PhaseName]['Angle'] = angleData
1744            angle = G2mth.getRestAngle(atXYZ,Amat)
1745            angleData['Angles'].append([atIndx,atSymOp,109.5,1.0])           
1746        elif event.GetId() == G2gd.wxID_DRAWRESTRPLANE and len(indx) > 3:
1747            try:
1748                planeData = restData[PhaseName]['Plane']
1749            except KeyError:
1750                planeData = {'wtFactor':1.0,'Planes':[],'Use':True}
1751                restData[PhaseName] = {}
1752                restData[PhaseName]['Plane'] = planeData
1753            plane = G2mth.getRestPlane(atXYZ,Amat)
1754            planeData['Planes'].append([atIndx,atSymOp,0.0,0.01])           
1755        elif event.GetId() == G2gd.wxID_DRAWRESTRCHIRAL and len(indx) == 4:
1756            try:
1757                chiralData = restData[PhaseName]['Chiral']
1758            except KeyError:
1759                chiralData = {'wtFactor':1.0,'Volumes':[],'Use':True}
1760                restData[PhaseName] = {}
1761                restData[PhaseName]['Chiral'] = chiralData
1762            volume = G2mth.getRestChiral(atXYZ,Amat)
1763            chiralData['Volumes'].append([atIndx,atSymOp,2.5,0.1])           
1764        else:
1765            print '**** ERROR wrong number of atoms selected for this restraint'
1766            return
1767        G2frame.PatternTree.SetItemPyData(   
1768            G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Restraints'),restData)
1769
1770    def OnDefineRB(event):
1771        indx = drawAtoms.GetSelectedRows()
1772        indx.sort()
1773        RBData = G2frame.PatternTree.GetItemPyData(   
1774            G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Rigid bodies'))
1775        drawingData = data['Drawing']
1776        generalData = data['General']
1777        Amat,Bmat = G2lat.cell2AB(generalData['Cell'][1:7])           
1778        cx,ct,cs,ci = drawingData['atomPtrs']
1779        atomData = drawingData['Atoms']
1780        rbXYZ = []
1781        rbType = []
1782        atNames = []
1783        AtInfo = RBData['Residue']['AtInfo']
1784        for i,item in enumerate(indx):
1785            rbtype = atomData[item][ct]
1786            atNames.append(rbtype+str(i))
1787            rbType.append(rbtype)
1788            if rbtype not in AtInfo:
1789                Info = G2elem.GetAtomInfo(rbtype)
1790                AtInfo[rbtype] = [Info['Drad'],Info['Color']]
1791            rbXYZ.append(np.inner(np.array(atomData[item][cx:cx+3]),Amat))
1792        rbXYZ = np.array(rbXYZ)
1793        rbXYZ -= rbXYZ[0]
1794        rbId = ran.randint(0,sys.maxint)
1795        rbName = 'UNKRB'
1796        dlg = wx.TextEntryDialog(G2frame,'Enter the name for the new rigid body',
1797            'Edit rigid body name',rbName ,style=wx.OK)
1798        if dlg.ShowModal() == wx.ID_OK:
1799            rbName = dlg.GetValue()
1800        dlg.Destroy()
1801        RBData['Residue'][rbId] = {'RBname':rbName,'rbXYZ':rbXYZ,'rbTypes':rbType,
1802            'atNames':atNames,'rbRef':[0,1,2,False],'rbSeq':[],'SelSeq':[0,0],'useCount':0}
1803        RBData['RBIds']['Residue'].append(rbId)
1804        G2frame.dataFrame.SetStatusText('New rigid body UNKRB added to set of Residue rigid bodies')
1805
1806################################################################################
1807##### Atom draw routines
1808################################################################################
1809           
1810    def UpdateDrawAtoms(atomStyle=''):
1811        def RefreshAtomGrid(event):
1812            def SetChoice(name,c,n=0):
1813                choice = []
1814                for r in range(len(atomData)):
1815                    if n:
1816                        srchStr = str(atomData[r][c][:n])
1817                    else:
1818                        srchStr = str(atomData[r][c])
1819                    if srchStr not in choice:
1820                        if n:
1821                            choice.append(str(atomData[r][c][:n]))
1822                        else:
1823                            choice.append(str(atomData[r][c]))
1824                choice.sort()
1825
1826                dlg = wx.MultiChoiceDialog(G2frame,'Select',name,choice)
1827                if dlg.ShowModal() == wx.ID_OK:
1828                    sel = dlg.GetSelections()
1829                    parms = []
1830                    for x in sel:
1831                        parms.append(choice[x])
1832                    noSkip = False
1833                    drawAtoms.ClearSelection()
1834                    drawingData['selectedAtoms'] = []
1835                    for row in range(len(atomData)):
1836                        test = atomData[row][c]
1837                        if n:
1838                            test = test[:n]
1839                        if  test in parms:
1840                            drawAtoms.SelectRow(row,True)
1841                            drawingData['selectedAtoms'].append(row)
1842                    G2plt.PlotStructure(G2frame,data)                   
1843                dlg.Destroy()
1844               
1845            r,c =  event.GetRow(),event.GetCol()
1846            if r < 0 and c < 0:
1847                for row in range(drawAtoms.GetNumberRows()):
1848                    drawingData['selectedAtoms'].append(row)
1849                    drawAtoms.SelectRow(row,True)                   
1850            elif r < 0:                          #dclick on col label
1851                sel = -1
1852                Parms = False
1853                noSkip = True
1854                if drawAtoms.GetColLabelValue(c) == 'Style':
1855                    dlg = wx.SingleChoiceDialog(G2frame,'Select','Atom drawing style',styleChoice)
1856                    if dlg.ShowModal() == wx.ID_OK:
1857                        sel = dlg.GetSelection()
1858                        parms = styleChoice[sel]
1859                        for r in range(len(atomData)):
1860                            atomData[r][c] = parms
1861                            drawAtoms.SetCellValue(r,c,parms)
1862                        FindBondsDraw()
1863                        G2plt.PlotStructure(G2frame,data)
1864                    dlg.Destroy()
1865                elif drawAtoms.GetColLabelValue(c) == 'Label':
1866                    dlg = wx.SingleChoiceDialog(G2frame,'Select','Atom labelling style',labelChoice)
1867                    if dlg.ShowModal() == wx.ID_OK:
1868                        sel = dlg.GetSelection()
1869                        parms = labelChoice[sel]
1870                        for r in range(len(atomData)):
1871                            atomData[r][c] = parms
1872                            drawAtoms.SetCellValue(r,c,parms)
1873                    dlg.Destroy()                   
1874                elif drawAtoms.GetColLabelValue(c) == 'Color':
1875                    dlg = wx.ColourDialog(G2frame)
1876                    if dlg.ShowModal() == wx.ID_OK:
1877                        color = dlg.GetColourData().GetColour()
1878                        attr = wg.GridCellAttr()                #needs to be here - gets lost if outside loop!
1879                        attr.SetReadOnly(True)
1880                        attr.SetBackgroundColour(color)
1881                        for r in range(len(atomData)):
1882                            atomData[r][c] = color
1883                            drawingData['Atoms'][r][c] = color
1884                            drawAtoms.SetAttr(r,c,attr)
1885                        UpdateDrawAtoms()
1886                    dlg.Destroy()
1887                elif drawAtoms.GetColLabelValue(c) == 'Residue':
1888                    SetChoice('Residue',c,3)
1889                elif drawAtoms.GetColLabelValue(c) == '1-letter':
1890                    SetChoice('1-letter',c,1)
1891                elif drawAtoms.GetColLabelValue(c) == 'Chain':
1892                    SetChoice('Chain',c)
1893                elif drawAtoms.GetColLabelValue(c) == 'Name':
1894                    SetChoice('Name',c)
1895                elif drawAtoms.GetColLabelValue(c) == 'Sym Op':
1896                    SetChoice('Name',c)
1897                elif drawAtoms.GetColLabelValue(c) == 'Type':
1898                    SetChoice('Type',c)
1899                elif drawAtoms.GetColLabelValue(c) in ['x','y','z','I/A']:
1900                    drawAtoms.ClearSelection()
1901            else:
1902                if drawAtoms.GetColLabelValue(c) in ['Style','Label']:
1903                    atomData[r][c] = drawAtoms.GetCellValue(r,c)
1904                    FindBondsDraw()
1905                elif drawAtoms.GetColLabelValue(c) == 'Color':
1906                    dlg = wx.ColourDialog(G2frame)
1907                    if dlg.ShowModal() == wx.ID_OK:
1908                        color = dlg.GetColourData().GetColour()
1909                        attr = wg.GridCellAttr()                #needs to be here - gets lost if outside loop!
1910                        attr.SetReadOnly(True)
1911                        attr.SetBackgroundColour(color)
1912                        atomData[r][c] = color
1913                        drawingData['Atoms'][r][c] = color
1914                        drawAtoms.SetAttr(i,cs+2,attr)
1915                    dlg.Destroy()
1916                    UpdateDrawAtoms()
1917            G2plt.PlotStructure(G2frame,data)
1918                   
1919        def RowSelect(event):
1920            r,c =  event.GetRow(),event.GetCol()
1921            if r < 0 and c < 0:
1922                if drawAtoms.IsSelection():
1923                    drawAtoms.ClearSelection()
1924            elif c < 0:                   #only row clicks
1925                if event.ControlDown():                   
1926                    if r in drawAtoms.GetSelectedRows():
1927                        drawAtoms.DeselectRow(r)
1928                    else:
1929                        drawAtoms.SelectRow(r,True)
1930                elif event.ShiftDown():
1931                    indxs = drawAtoms.GetSelectedRows()
1932                    drawAtoms.ClearSelection()
1933                    ibeg = 0
1934                    if indxs:
1935                        ibeg = indxs[-1]
1936                    for row in range(ibeg,r+1):
1937                        drawAtoms.SelectRow(row,True)
1938                else:
1939                    drawAtoms.ClearSelection()
1940                    drawAtoms.SelectRow(r,True)               
1941            drawingData['selectedAtoms'] = []
1942            drawingData['selectedAtoms'] = drawAtoms.GetSelectedRows()
1943            G2plt.PlotStructure(G2frame,data)                   
1944
1945        # UpdateDrawAtoms executable code starts here
1946        G2frame.dataFrame.SetStatusText('')
1947        generalData = data['General']
1948        SetupDrawingData()
1949        drawingData = data['Drawing']
1950        cx,ct,cs,ci = drawingData['atomPtrs']
1951        atomData = drawingData['Atoms']
1952        if atomStyle:
1953            for atom in atomData:
1954                atom[cs] = atomStyle
1955        Types = [wg.GRID_VALUE_STRING,wg.GRID_VALUE_STRING,]+3*[wg.GRID_VALUE_FLOAT+':10,5',]+ \
1956            [wg.GRID_VALUE_STRING,wg.GRID_VALUE_CHOICE+": ,lines,vdW balls,sticks,balls & sticks,ellipsoids,polyhedra",
1957            wg.GRID_VALUE_CHOICE+": ,type,name,number",wg.GRID_VALUE_STRING,wg.GRID_VALUE_STRING,]
1958        styleChoice = [' ','lines','vdW balls','sticks','balls & sticks','ellipsoids','polyhedra']
1959        labelChoice = [' ','type','name','number']
1960        colLabels = ['Name','Type','x','y','z','Sym Op','Style','Label','Color','I/A']
1961        if generalData['Type'] == 'macromolecular':
1962            colLabels = ['Residue','1-letter','Chain'] + colLabels
1963            Types = 3*[wg.GRID_VALUE_STRING,]+Types
1964            Types[8] = wg.GRID_VALUE_CHOICE+": ,lines,vdW balls,sticks,balls & sticks,ellipsoids,backbone,ribbons,schematic"
1965            styleChoice = [' ','lines','vdW balls','sticks','balls & sticks','ellipsoids','backbone','ribbons','schematic']
1966            labelChoice = [' ','type','name','number','residue','1-letter','chain']
1967            Types[9] = wg.GRID_VALUE_CHOICE+": ,type,name,number,residue,1-letter,chain"
1968#        elif generalData['Type'] == 'modulated':
1969#            Types += []
1970#            colLabels += []
1971        table = []
1972        rowLabels = []
1973        for i,atom in enumerate(drawingData['Atoms']):
1974            table.append(atom[:colLabels.index('I/A')+1])
1975            rowLabels.append(str(i))
1976
1977        atomTable = G2gd.Table(table,rowLabels=rowLabels,colLabels=colLabels,types=Types)
1978        drawAtoms.SetTable(atomTable, True)
1979        drawAtoms.SetMargins(0,0)
1980        drawAtoms.AutoSizeColumns(True)
1981        drawAtoms.SetColSize(colLabels.index('Style'),80)
1982        drawAtoms.SetColSize(colLabels.index('Color'),50)
1983        drawAtoms.Bind(wg.EVT_GRID_CELL_CHANGE, RefreshAtomGrid)
1984        drawAtoms.Bind(wg.EVT_GRID_LABEL_LEFT_DCLICK, RefreshAtomGrid)
1985        drawAtoms.Bind(wg.EVT_GRID_CELL_LEFT_DCLICK, RefreshAtomGrid)
1986        drawAtoms.Bind(wg.EVT_GRID_LABEL_LEFT_CLICK, RowSelect)
1987        for i,atom in enumerate(drawingData['Atoms']):
1988            attr = wg.GridCellAttr()                #needs to be here - gets lost if outside loop!
1989            attr.SetReadOnly(True)
1990            attr.SetBackgroundColour(atom[cs+2])
1991            drawAtoms.SetAttr(i,cs+2,attr)
1992            drawAtoms.SetCellValue(i,cs+2,'')
1993        indx = drawingData['selectedAtoms']
1994        if indx:
1995            for r in range(len(atomData)):
1996                if r in indx:
1997                    drawAtoms.SelectRow(r)
1998        for c in range(len(colLabels)):
1999           attr = wg.GridCellAttr()                #needs to be here - gets lost if outside loop!
2000           attr.SetReadOnly(True)
2001           attr.SetBackgroundColour(VERY_LIGHT_GREY)
2002           if colLabels[c] not in ['Style','Label','Color']:
2003                drawAtoms.SetColAttr(c,attr)
2004        G2frame.dataFrame.setSizePosLeft([600,300])
2005
2006        FindBondsDraw()
2007        drawAtoms.ClearSelection()
2008#        G2plt.PlotStructure(G2frame,data)
2009
2010    def DrawAtomStyle(event):
2011        indx = drawAtoms.GetSelectedRows()
2012        if indx:
2013            generalData = data['General']
2014            atomData = data['Drawing']['Atoms']
2015            cx,ct,cs,ci = data['Drawing']['atomPtrs']
2016            styleChoice = [' ','lines','vdW balls','sticks','balls & sticks','ellipsoids','polyhedra']
2017            if generalData['Type'] == 'macromolecular':
2018                styleChoice = [' ','lines','vdW balls','sticks','balls & sticks','ellipsoids',
2019                'backbone','ribbons','schematic']
2020            dlg = wx.SingleChoiceDialog(G2frame,'Select','Atom drawing style',styleChoice)
2021            if dlg.ShowModal() == wx.ID_OK:
2022                sel = dlg.GetSelection()
2023                parms = styleChoice[sel]
2024                for r in indx:
2025                    atomData[r][cs] = parms
2026                    drawAtoms.SetCellValue(r,cs,parms)
2027            dlg.Destroy()
2028            FindBondsDraw()
2029            drawAtoms.ClearSelection()
2030            G2plt.PlotStructure(G2frame,data)
2031
2032    def DrawAtomLabel(event):
2033        indx = drawAtoms.GetSelectedRows()
2034        if indx:
2035            generalData = data['General']
2036            atomData = data['Drawing']['Atoms']
2037            cx,ct,cs,ci = data['Drawing']['atomPtrs']
2038            styleChoice = [' ','type','name','number']
2039            if generalData['Type'] == 'macromolecular':
2040                styleChoice = [' ','type','name','number','residue','1-letter','chain']
2041            dlg = wx.SingleChoiceDialog(G2frame,'Select','Atom label style',styleChoice)
2042            if dlg.ShowModal() == wx.ID_OK:
2043                sel = dlg.GetSelection()
2044                parms = styleChoice[sel]
2045                for r in indx:
2046                    atomData[r][cs+1] = parms
2047                    drawAtoms.SetCellValue(r,cs+1,parms)
2048            dlg.Destroy()
2049            drawAtoms.ClearSelection()
2050            G2plt.PlotStructure(G2frame,data)
2051           
2052    def DrawAtomColor(event):
2053
2054        indx = drawAtoms.GetSelectedRows()
2055        if indx:
2056            if len(indx) > 1:
2057                G2frame.dataFrame.SetStatusText('Select Custom Color, change color, Add to Custom Colors, then OK')
2058            else:
2059                G2frame.dataFrame.SetStatusText('Change color, Add to Custom Colors, then OK')
2060            generalData = data['General']
2061            atomData = data['Drawing']['Atoms']
2062            cx,ct,cs,ci = data['Drawing']['atomPtrs']
2063            atmColors = []
2064            atmTypes = []
2065            for r in indx:
2066                if atomData[r][cs+2] not in atmColors:
2067                    atmColors.append(atomData[r][cs+2])
2068                    atmTypes.append(atomData[r][ct])
2069                    if len(atmColors) > 16:
2070                        break
2071            colors = wx.ColourData()
2072            colors.SetChooseFull(True)
2073            dlg = wx.ColourDialog(G2frame)
2074            if dlg.ShowModal() == wx.ID_OK:
2075                for i in range(len(atmColors)):                   
2076                    atmColors[i] = dlg.GetColourData().GetColour()
2077                colorDict = dict(zip(atmTypes,atmColors))
2078                for r in indx:
2079                    color = colorDict[atomData[r][ct]]
2080                    atomData[r][cs+2] = color
2081                    attr = wg.GridCellAttr()                #needs to be here - gets lost if outside loop!
2082                    attr.SetBackgroundColour(color)
2083                    drawAtoms.SetAttr(r,cs+2,attr)
2084                    data['Drawing']['Atoms'][r][cs+2] = color
2085            drawAtoms.ClearSelection()
2086            dlg.Destroy()
2087            G2frame.dataFrame.SetStatusText('')
2088            G2plt.PlotStructure(G2frame,data)
2089           
2090    def ResetAtomColors(event):
2091        generalData = data['General']
2092        atomData = data['Drawing']['Atoms']
2093        cx,ct,cs,ci = data['Drawing']['atomPtrs']
2094        for atom in atomData:           
2095            atNum = generalData['AtomTypes'].index(atom[ct])
2096            atom[cs+2] = list(generalData['Color'][atNum])
2097        UpdateDrawAtoms()
2098        drawAtoms.ClearSelection()
2099        G2plt.PlotStructure(G2frame,data)       
2100       
2101    def SetViewPoint(event):
2102        indx = drawAtoms.GetSelectedRows()
2103        if indx:
2104            atomData = data['Drawing']['Atoms']
2105            cx = data['Drawing']['atomPtrs'][0]
2106            data['Drawing']['viewPoint'] = [atomData[indx[0]][cx:cx+3],[indx[0],0]]
2107            drawAtoms.ClearSelection()                                  #do I really want to do this?
2108            G2plt.PlotStructure(G2frame,data)
2109           
2110    def noDuplicate(xyz,atomData):                  #be careful where this is used - it's slow
2111        cx = data['Drawing']['atomPtrs'][0]
2112        if True in [np.allclose(np.array(xyz),np.array(atom[cx:cx+3]),atol=0.0002) for atom in atomData]:
2113            return False
2114        else:
2115            return True
2116               
2117    def AddSymEquiv(event):
2118        indx = drawAtoms.GetSelectedRows()
2119        indx.sort()
2120        if indx:
2121            colLabels = [drawAtoms.GetColLabelValue(c) for c in range(drawAtoms.GetNumberCols())]
2122            cx = colLabels.index('x')
2123            cuia = colLabels.index('I/A')
2124            cuij = cuia+2
2125            atomData = data['Drawing']['Atoms']
2126            generalData = data['General']
2127            SGData = generalData['SGData']
2128            dlg = G2gd.SymOpDialog(G2frame,SGData,False,True)
2129            try:
2130                if dlg.ShowModal() == wx.ID_OK:
2131                    Inv,Cent,Opr,Cell,New,Force = dlg.GetSelection()
2132                    Cell = np.array(Cell)
2133                    cent = SGData['SGCen'][Cent]
2134                    M,T = SGData['SGOps'][Opr]
2135                    for ind in indx:
2136                        XYZ = np.array(atomData[ind][cx:cx+3])
2137                        XYZ = np.inner(M,XYZ)+T
2138                        if Inv:
2139                            XYZ = -XYZ
2140                        XYZ = XYZ+cent+Cell
2141                        if Force:
2142                            XYZ = G2spc.MoveToUnitCell(XYZ)
2143                        if noDuplicate(XYZ,atomData):
2144                            atom = copy.copy(atomData[ind])
2145                            atom[cx:cx+3] = XYZ
2146                            atomOp = atom[cx+3]
2147                            newOp = str(((Opr+1)+100*Cent)*(1-2*Inv))+'+'+ \
2148                                str(int(Cell[0]))+','+str(int(Cell[1]))+','+str(int(Cell[2]))                           
2149                            atom[cx+3] = G2spc.StringOpsProd(atomOp,newOp,SGData)
2150                            if atom[cuia] == 'A':
2151                                Uij = atom[cuij:cuij+6]
2152                                U = G2spc.Uij2U(Uij)
2153                                U = np.inner(np.inner(M,U),M)
2154                                Uij = G2spc.U2Uij(U)
2155                                atom[cuij:cuij+6] = Uij
2156                            atomData.append(atom)
2157            finally:
2158                dlg.Destroy()
2159            UpdateDrawAtoms()
2160            drawAtoms.ClearSelection()
2161            G2plt.PlotStructure(G2frame,data)
2162           
2163    def TransformSymEquiv(event):
2164        indx = drawAtoms.GetSelectedRows()
2165        indx.sort()
2166        if indx:
2167            atomData = data['Drawing']['Atoms']
2168            colLabels = [drawAtoms.GetColLabelValue(c) for c in range(drawAtoms.GetNumberCols())]
2169            cx = colLabels.index('x')
2170            cuia = colLabels.index('I/A')
2171            cuij = cuia+2
2172            atomData = data['Drawing']['Atoms']
2173            generalData = data['General']
2174            SGData = generalData['SGData']
2175            dlg = G2gd.SymOpDialog(G2frame,SGData,False,True)
2176            try:
2177                if dlg.ShowModal() == wx.ID_OK:
2178                    Inv,Cent,Opr,Cell,New,Force = dlg.GetSelection()
2179                    Cell = np.array(Cell)
2180                    cent = SGData['SGCen'][Cent]
2181                    M,T = SGData['SGOps'][Opr]
2182                    for ind in indx:
2183                        XYZ = np.array(atomData[ind][cx:cx+3])
2184                        XYZ = np.inner(M,XYZ)+T
2185                        if Inv:
2186                            XYZ = -XYZ
2187                        XYZ = XYZ+cent+Cell
2188                        if Force:
2189                            XYZ = G2spc.MoveToUnitCell(XYZ)
2190                        atom = atomData[ind]
2191                        atom[cx:cx+3] = XYZ
2192                        atomOp = atom[cx+3]
2193                        newOp = str(((Opr+1)+100*Cent)*(1-2*Inv))+'+'+ \
2194                            str(int(Cell[0]))+','+str(int(Cell[1]))+','+str(int(Cell[2]))
2195                        atom[cx+3] = G2spc.StringOpsProd(atomOp,newOp,SGData)
2196                        if atom[cuia] == 'A':
2197                            Uij = atom[cuij:cuij+6]
2198                            U = G2spc.Uij2U(Uij)
2199                            U = np.inner(np.inner(M,U),M)
2200                            Uij = G2spc.U2Uij(U)
2201                            atom[cuij:cuij+6] = Uij
2202                    data['Drawing']['Atoms'] = atomData
2203            finally:
2204                dlg.Destroy()
2205            UpdateDrawAtoms()
2206            drawAtoms.ClearSelection()
2207            G2plt.PlotStructure(G2frame,data)
2208           
2209    def FillCoordSphere(event):
2210        generalData = data['General']
2211        Amat,Bmat = G2lat.cell2AB(generalData['Cell'][1:7])
2212        radii = generalData['BondRadii']
2213        atomTypes = generalData['AtomTypes']
2214        try:
2215            indH = atomTypes.index('H')
2216            radii[indH] = 0.5
2217        except:
2218            pass           
2219        indx = drawAtoms.GetSelectedRows()
2220        if indx:
2221            indx.sort()
2222            atomData = data['Drawing']['Atoms']
2223            numAtoms = len(atomData)
2224            cx,ct,cs,ci = data['Drawing']['atomPtrs']
2225            generalData = data['General']
2226            SGData = generalData['SGData']
2227            cellArray = G2lat.CellBlock(1)
2228            wx.BeginBusyCursor()
2229            try:
2230                for ind in indx:
2231                    atomA = atomData[ind]
2232                    xyzA = np.array(atomA[cx:cx+3])
2233                    indA = atomTypes.index(atomA[ct])
2234                    for atomB in atomData[:numAtoms]:
2235                        indB = atomTypes.index(atomB[ct])
2236                        sumR = radii[indA]+radii[indB]
2237                        xyzB = np.array(atomB[cx:cx+3])
2238                        for xyz in cellArray+xyzB:
2239                            dist = np.sqrt(np.sum(np.inner(Amat,xyz-xyzA)**2))
2240                            if 0 < dist <= data['Drawing']['radiusFactor']*sumR:
2241                                if noDuplicate(xyz,atomData):
2242                                    oprB = atomB[cx+3]
2243                                    C = xyz-xyzB
2244                                    newOp = '1+'+str(int(round(C[0])))+','+str(int(round(C[1])))+','+str(int(round(C[2])))
2245                                    newAtom = atomB[:]
2246                                    newAtom[cx:cx+3] = xyz
2247                                    newAtom[cx+3] = G2spc.StringOpsProd(oprB,newOp,SGData)
2248                                    atomData.append(newAtom)
2249            finally:
2250                wx.EndBusyCursor()
2251            data['Drawing']['Atoms'] = atomData
2252            UpdateDrawAtoms()
2253            drawAtoms.ClearSelection()
2254            G2plt.PlotStructure(G2frame,data)
2255           
2256    def FillUnitCell(event):
2257        indx = drawAtoms.GetSelectedRows()
2258        indx.sort()
2259        if indx:
2260            atomData = data['Drawing']['Atoms']
2261            colLabels = [drawAtoms.GetColLabelValue(c) for c in range(drawAtoms.GetNumberCols())]
2262            cx = colLabels.index('x')
2263            cuia = colLabels.index('I/A')
2264            cuij = cuia+2
2265            generalData = data['General']
2266            SGData = generalData['SGData']
2267            wx.BeginBusyCursor()
2268            try:
2269                for ind in indx:
2270                    atom = atomData[ind]
2271                    XYZ = np.array(atom[cx:cx+3])
2272                    if atom[cuia] == 'A':
2273                        Uij = atom[cuij:cuij+6]
2274                        result = G2spc.GenAtom(XYZ,SGData,False,Uij,False)
2275                        for item in result:
2276                            atom = copy.copy(atomData[ind])
2277                            atom[cx:cx+3] = item[0]
2278                            atom[cx+3] = str(item[2])+'+' \
2279                                +str(item[3][0])+','+str(item[3][1])+','+str(item[3][2])
2280                            atom[cuij:cuij+6] = item[1]
2281                            Opp = G2spc.Opposite(item[0])
2282                            for xyz in Opp:
2283                                if noDuplicate(xyz,atomData):
2284                                    cell = np.asarray(np.rint(xyz-atom[cx:cx+3]),dtype=np.int32)
2285                                    cell = '1'+'+'+ \
2286                                        str(cell[0])+','+str(cell[1])+','+str(cell[2])
2287                                    atom[cx:cx+3] = xyz
2288                                    atom[cx+3] = G2spc.StringOpsProd(cell,atom[cx+3],SGData)
2289                                    atomData.append(atom[:])
2290                    else:
2291                        result = G2spc.GenAtom(XYZ,SGData,False,Move=False)
2292                        for item in result:
2293                            atom = copy.copy(atomData[ind])
2294                            atom[cx:cx+3] = item[0]
2295                            atom[cx+3] = str(item[1])+'+' \
2296                                +str(item[2][0])+','+str(item[2][1])+','+str(item[2][2])
2297                            Opp = G2spc.Opposite(item[0])
2298                            for xyz in Opp:
2299                                if noDuplicate(xyz,atomData):
2300                                    cell = np.asarray(np.rint(xyz-atom[cx:cx+3]),dtype=np.int32)
2301                                    cell = '1'+'+'+ \
2302                                        str(cell[0])+','+str(cell[1])+','+str(cell[2])
2303                                    atom[cx:cx+3] = xyz
2304                                    atom[cx+3] = G2spc.StringOpsProd(cell,atom[cx+3],SGData)
2305                                    atomData.append(atom[:])               
2306                    data['Drawing']['Atoms'] = atomData
2307            finally:
2308                wx.EndBusyCursor()
2309            UpdateDrawAtoms()
2310            drawAtoms.ClearSelection()
2311            G2plt.PlotStructure(G2frame,data)
2312           
2313    def FindBondsToo():                         #works but slow for large structures - keep as reference
2314        cx,ct,cs,ci = data['Drawing']['atomPtrs']
2315        atomData = data['Drawing']['Atoms']
2316        generalData = data['General']
2317        Amat,Bmat = G2lat.cell2AB(generalData['Cell'][1:7])
2318        radii = generalData['BondRadii']
2319        atomTypes = generalData['AtomTypes']
2320        try:
2321            indH = atomTypes.index('H')
2322            radii[indH] = 0.5
2323        except:
2324            pass           
2325        for atom in atomData:
2326            atom[-1] = []
2327        Atoms = []
2328        for i,atom in enumerate(atomData):
2329            Atoms.append([i,np.array(atom[cx:cx+3]),atom[cs],radii[atomTypes.index(atom[ct])]])
2330        for atomA in Atoms:
2331            if atomA[2] in ['lines','sticks','ellipsoids','balls & sticks','polyhedra']:
2332                for atomB in Atoms:                   
2333                    Dx = atomB[1]-atomA[1]
2334                    DX = np.inner(Amat,Dx)
2335                    dist = np.sqrt(np.sum(DX**2))
2336                    sumR = atomA[3]+atomB[3]
2337                    if 0.5 < dist <= 0.85*sumR:
2338                        i = atomA[0]
2339                        if atomA[2] == 'polyhedra':
2340                            atomData[i][-1].append(DX)
2341                        elif atomB[1] != 'polyhedra':
2342                            j = atomB[0]
2343                            atomData[i][-1].append(Dx*atomA[3]/sumR)
2344                            atomData[j][-1].append(-Dx*atomB[3]/sumR)
2345                   
2346    def FindBondsDraw():                    #uses numpy & masks - very fast even for proteins!
2347        import numpy.ma as ma
2348        cx,ct,cs,ci = data['Drawing']['atomPtrs']
2349        hydro = data['Drawing']['showHydrogen']
2350        atomData = data['Drawing']['Atoms']
2351        generalData = data['General']
2352        Amat,Bmat = G2lat.cell2AB(generalData['Cell'][1:7])
2353        radii = generalData['BondRadii']
2354        atomTypes = generalData['AtomTypes']
2355        try:
2356            indH = atomTypes.index('H')
2357            radii[indH] = 0.5
2358        except:
2359            pass           
2360        for atom in atomData:
2361            atom[-2] = []               #clear out old bonds/polyhedra
2362            atom[-1] = []
2363        Indx = range(len(atomData))
2364        Atoms = []
2365        Styles = []
2366        Radii = []
2367        for atom in atomData:
2368            Atoms.append(np.array(atom[cx:cx+3]))
2369            Styles.append(atom[cs])
2370            try:
2371                if not hydro and atom[ct] == 'H':
2372                    Radii.append(0.0)
2373                else:
2374                    Radii.append(radii[atomTypes.index(atom[ct])])
2375            except ValueError:          #changed atom type!
2376                Radii.append(0.20)
2377        Atoms = np.array(Atoms)
2378        Radii = np.array(Radii)
2379        IASR = zip(Indx,Atoms,Styles,Radii)
2380        for atomA in IASR:
2381            if atomA[2] in ['lines','sticks','ellipsoids','balls & sticks','polyhedra']:
2382                Dx = Atoms-atomA[1]
2383                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
2384                sumR = atomA[3]+Radii
2385                IndB = ma.nonzero(ma.masked_greater(dist-data['Drawing']['radiusFactor']*sumR,0.))                 #get indices of bonded atoms
2386                i = atomA[0]
2387                for j in IndB[0]:
2388                    if Styles[i] == 'polyhedra':
2389                        atomData[i][-2].append(np.inner(Amat,Dx[j]))
2390                    elif Styles[j] != 'polyhedra' and j > i:
2391                        atomData[i][-2].append(Dx[j]*Radii[i]/sumR[j])
2392                        atomData[j][-2].append(-Dx[j]*Radii[j]/sumR[j])
2393                if Styles[i] == 'polyhedra':
2394                    Bonds = atomData[i][-2]
2395                    Faces = []
2396                    if len(Bonds) > 2:
2397                        FaceGen = G2lat.uniqueCombinations(Bonds,3)     #N.B. this is a generator
2398                        for face in FaceGen:
2399                            vol = nl.det(face)
2400                            if abs(vol) > 1. or len(Bonds) == 3:
2401                                if vol < 0.:
2402                                    face = [face[0],face[2],face[1]]
2403                                face = np.array(face)
2404                                if not np.array([np.array(nl.det(face-bond))+0.0001 < 0 for bond in Bonds]).any():
2405                                    norm = np.cross(face[1]-face[0],face[2]-face[0])
2406                                    norm /= np.sqrt(np.sum(norm**2))
2407                                    Faces.append([face,norm])
2408                        atomData[i][-1] = Faces
2409                       
2410    def DrawAtomsDelete(event):   
2411        indx = drawAtoms.GetSelectedRows()
2412        indx.sort()
2413        if indx:
2414            atomData = data['Drawing']['Atoms']
2415            indx.reverse()
2416            for ind in indx:
2417                del atomData[ind]
2418            UpdateDrawAtoms()
2419            drawAtoms.ClearSelection()
2420            G2plt.PlotStructure(G2frame,data)
2421        event.StopPropagation()
2422       
2423    def OnReloadDrawAtoms(event):
2424        data['Drawing']['Atoms'] = []
2425        UpdateDrawAtoms()
2426        drawAtoms.ClearSelection()
2427        G2plt.PlotStructure(G2frame,data)
2428        event.StopPropagation()
2429       
2430    def DrawAtomsDeleteByIDs(IDs):
2431        atomData = data['Drawing']['Atoms']
2432        indx = G2mth.FindAtomIndexByIDs(atomData,IDs)
2433        indx.reverse()
2434        for ind in indx:
2435            del atomData[ind]
2436           
2437    def ChangeDrawAtomsByIDs(colName,IDs,value):
2438        atomData = data['Drawing']['Atoms']
2439        cx,ct,cs,ci = data['Drawing']['atomPtrs']
2440        if colName == 'Name':
2441            col = ct-1
2442        elif colName == 'Type':
2443            col = ct
2444        elif colName == 'I/A':
2445            col = cs
2446        indx = G2mth.FindAtomIndexByIDs(atomData,IDs)
2447        for ind in indx:
2448            atomData[ind][col] = value
2449               
2450    def OnDrawPlane(event):
2451        indx = drawAtoms.GetSelectedRows()
2452        if len(indx) < 4:
2453            print '**** ERROR - need 4+ atoms for plane calculation'
2454            return
2455        PlaneData = {}
2456        drawingData = data['Drawing']
2457        atomData = drawingData['Atoms']
2458        colLabels = [drawAtoms.GetColLabelValue(c) for c in range(drawAtoms.GetNumberCols())]
2459        cx = colLabels.index('x')
2460        cn = colLabels.index('Name')
2461        xyz = []
2462        for i,atom in enumerate(atomData):
2463            if i in indx:
2464                xyz.append([i,]+atom[cn:cn+2]+atom[cx:cx+3])
2465        generalData = data['General']
2466        PlaneData['Name'] = generalData['Name']
2467        PlaneData['Atoms'] = xyz
2468        PlaneData['Cell'] = generalData['Cell'][1:] #+ volume
2469        G2stMn.BestPlane(PlaneData)
2470       
2471    def OnDrawDistVP(event):
2472        # distance to view point
2473        indx = drawAtoms.GetSelectedRows()
2474        if not indx:
2475            print '***** ERROR - no atoms selected'
2476            return
2477        generalData = data['General']
2478        Amat,Bmat = G2lat.cell2AB(generalData['Cell'][1:7])           
2479        drawingData = data['Drawing']
2480        viewPt = np.array(drawingData['viewPoint'][0])
2481        print ' Distance from view point at %.3f %.3f %.3f to:'%(viewPt[0],viewPt[1],viewPt[2])
2482        atomDData = drawingData['Atoms']
2483        colLabels = [drawAtoms.GetColLabelValue(c) for c in range(drawAtoms.GetNumberCols())]
2484        cx = colLabels.index('x')
2485        cn = colLabels.index('Name')
2486        for i in indx:
2487            atom = atomDData[i]
2488            Dx = np.array(atom[cx:cx+3])-viewPt
2489            dist = np.sqrt(np.sum(np.inner(Amat,Dx)**2,axis=0))
2490            print 'Atom: %8s (%12s) distance = %.3f'%(atom[cn],atom[cx+3],dist)
2491   
2492    def OnDrawDAT(event):
2493        #distance, angle, torsion
2494        indx = drawAtoms.GetSelectedRows()
2495        if len(indx) not in [2,3,4]:
2496            print '**** ERROR - wrong number of atoms for distance, angle or torsion calculation'
2497            return
2498        DATData = {}
2499        ocx,oct,ocs,cia = data['General']['AtomPtrs']
2500        drawingData = data['Drawing']
2501        atomData = data['Atoms']
2502        atomDData = drawingData['Atoms']
2503        colLabels = [drawAtoms.GetColLabelValue(c) for c in range(drawAtoms.GetNumberCols())]
2504        cx = colLabels.index('x')
2505        cn = colLabels.index('Name')
2506        cid = colLabels.index('I/A')+8
2507        xyz = []
2508        Oxyz = []
2509        DATData['Natoms'] = len(indx)
2510        for i in indx:
2511            atom = atomDData[i]
2512            xyz.append([i,]+atom[cn:cn+2]+atom[cx:cx+4]) #also gets Sym Op
2513            id = G2mth.FindAtomIndexByIDs(atomData,[atom[cid],],False)[0]
2514            Oxyz.append([id,]+atomData[id][cx+1:cx+4])
2515        DATData['Datoms'] = xyz
2516        DATData['Oatoms'] = Oxyz
2517        generalData = data['General']
2518        DATData['Name'] = generalData['Name']
2519        DATData['SGData'] = generalData['SGData']
2520        DATData['Cell'] = generalData['Cell'][1:] #+ volume
2521        if 'pId' in data:
2522            DATData['pId'] = data['pId']
2523            DATData['covData'] = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.root, 'Covariance'))
2524        G2stMn.DisAglTor(DATData)
2525               
2526################################################################################
2527#### Draw Options page
2528################################################################################
2529
2530    def UpdateDrawOptions():
2531        import copy
2532        import wx.lib.colourselect as wcs
2533        def SlopSizer():           
2534            def OnCameraPos(event):
2535                drawingData['cameraPos'] = cameraPos.GetValue()
2536                cameraPosTxt.SetLabel(' Camera Distance: '+'%.2f'%(drawingData['cameraPos']))
2537                ZclipTxt.SetLabel(' Z clipping: '+'%.2fA'%(drawingData['Zclip']*drawingData['cameraPos']/100.))
2538                G2plt.PlotStructure(G2frame,data)
2539
2540            def OnZclip(event):
2541                drawingData['Zclip'] = Zclip.GetValue()
2542                ZclipTxt.SetLabel(' Z clipping: '+'%.2fA'%(drawingData['Zclip']*drawingData['cameraPos']/100.))
2543                G2plt.PlotStructure(G2frame,data)
2544               
2545            def OnZstep(event):
2546                try:
2547                    step = float(Zstep.GetValue())
2548                    if not (0.01 <= step <= 1.0):
2549                        raise ValueError
2550                except ValueError:
2551                    step = drawingData['Zstep']
2552                drawingData['Zstep'] = step
2553                Zstep.SetValue('%.2fA'%(drawingData['Zstep']))
2554               
2555            def OnMoveZ(event):
2556                move = MoveZ.GetValue()*drawingData['Zstep']
2557                MoveZ.SetValue(0)
2558                VP = np.inner(Amat,np.array(drawingData['viewPoint'][0]))
2559                VD = np.inner(Amat,np.array(drawingData['viewDir']))
2560                VD /= np.sqrt(np.sum(VD**2))
2561                VP += move*VD
2562                VP = np.inner(Bmat,VP)
2563                drawingData['viewPoint'][0] = VP
2564                panel = drawOptions.GetChildren()
2565                names = [child.GetName() for child in panel]
2566                panel[names.index('viewPoint')].SetValue('%.3f %.3f %.3f'%(VP[0],VP[1],VP[2]))               
2567                G2plt.PlotStructure(G2frame,data)
2568               
2569            def OnVdWScale(event):
2570                drawingData['vdwScale'] = vdwScale.GetValue()/100.
2571                vdwScaleTxt.SetLabel(' van der Waals scale: '+'%.2f'%(drawingData['vdwScale']))
2572                G2plt.PlotStructure(G2frame,data)
2573   
2574            def OnEllipseProb(event):
2575                drawingData['ellipseProb'] = ellipseProb.GetValue()
2576                ellipseProbTxt.SetLabel(' Ellipsoid probability: '+'%d%%'%(drawingData['ellipseProb']))
2577                G2plt.PlotStructure(G2frame,data)
2578   
2579            def OnBallScale(event):
2580                drawingData['ballScale'] = ballScale.GetValue()/100.
2581                ballScaleTxt.SetLabel(' Ball scale: '+'%.2f'%(drawingData['ballScale']))
2582                G2plt.PlotStructure(G2frame,data)
2583
2584            def OnBondRadius(event):
2585                drawingData['bondRadius'] = bondRadius.GetValue()/100.
2586                bondRadiusTxt.SetLabel(' Bond radius, A: '+'%.2f'%(drawingData['bondRadius']))
2587                G2plt.PlotStructure(G2frame,data)
2588               
2589            def OnContourLevel(event):
2590                drawingData['contourLevel'] = contourLevel.GetValue()/100.
2591                contourLevelTxt.SetLabel(' Contour level: '+'%.2f'%(drawingData['contourLevel']*generalData['Map']['rhoMax']))
2592                G2plt.PlotStructure(G2frame,data)
2593
2594            def OnMapSize(event):
2595                drawingData['mapSize'] = mapSize.GetValue()/10.
2596                mapSizeTxt.SetLabel(' Map radius, A: '+'%.1f'%(drawingData['mapSize']))
2597                G2plt.PlotStructure(G2frame,data)
2598
2599           
2600            slopSizer = wx.BoxSizer(wx.HORIZONTAL)
2601            slideSizer = wx.FlexGridSizer(7,2)
2602            slideSizer.AddGrowableCol(1,1)
2603   
2604            cameraPosTxt = wx.StaticText(drawOptions,-1,
2605                ' Camera Distance: '+'%.2f'%(drawingData['cameraPos']),name='cameraPos')
2606            G2frame.dataDisplay.cameraPosTxt = cameraPosTxt
2607            slideSizer.Add(cameraPosTxt,0,wx.ALIGN_CENTER_VERTICAL)
2608            cameraPos = wx.Slider(drawOptions,style=wx.SL_HORIZONTAL,value=drawingData['cameraPos'],name='cameraSlider')
2609            cameraPos.SetRange(10,500)
2610            cameraPos.Bind(wx.EVT_SLIDER, OnCameraPos)
2611            G2frame.dataDisplay.cameraSlider = cameraPos
2612            slideSizer.Add(cameraPos,1,wx.EXPAND|wx.RIGHT)
2613           
2614            ZclipTxt = wx.StaticText(drawOptions,-1,' Z clipping: '+'%.2fA'%(drawingData['Zclip']*drawingData['cameraPos']/100.))
2615            slideSizer.Add(ZclipTxt,0,wx.ALIGN_CENTER_VERTICAL)
2616            Zclip = wx.Slider(drawOptions,style=wx.SL_HORIZONTAL,value=drawingData['Zclip'])
2617            Zclip.SetRange(1,99)
2618            Zclip.Bind(wx.EVT_SLIDER, OnZclip)
2619            slideSizer.Add(Zclip,1,wx.EXPAND|wx.RIGHT)
2620           
2621            ZstepSizer = wx.BoxSizer(wx.HORIZONTAL)
2622            ZstepSizer.Add(wx.StaticText(drawOptions,-1,' Z step:'),0,wx.ALIGN_CENTER_VERTICAL)
2623            Zstep = wx.TextCtrl(drawOptions,value='%.2f'%(drawingData['Zstep']),
2624                style=wx.TE_PROCESS_ENTER)
2625            Zstep.Bind(wx.EVT_TEXT_ENTER,OnZstep)
2626            Zstep.Bind(wx.EVT_KILL_FOCUS,OnZstep)
2627            ZstepSizer.Add(Zstep,0,wx.ALIGN_CENTER_VERTICAL)
2628            slideSizer.Add(ZstepSizer)
2629            MoveSizer = wx.BoxSizer(wx.HORIZONTAL)
2630            MoveSizer.Add(wx.StaticText(drawOptions,-1,'   Press to step:'),0,wx.ALIGN_CENTER_VERTICAL)
2631            MoveZ = wx.SpinButton(drawOptions,style=wx.SP_HORIZONTAL,size=wx.Size(100,20))
2632            MoveZ.SetValue(0)
2633            MoveZ.SetRange(-1,1)
2634            MoveZ.Bind(wx.EVT_SPIN, OnMoveZ)
2635            MoveSizer.Add(MoveZ)
2636            slideSizer.Add(MoveSizer,1,wx.EXPAND|wx.RIGHT)
2637           
2638            vdwScaleTxt = wx.StaticText(drawOptions,-1,' van der Waals scale: '+'%.2f'%(drawingData['vdwScale']))
2639            slideSizer.Add(vdwScaleTxt,0,wx.ALIGN_CENTER_VERTICAL)
2640            vdwScale = wx.Slider(drawOptions,style=wx.SL_HORIZONTAL,value=int(100*drawingData['vdwScale']))
2641            vdwScale.Bind(wx.EVT_SLIDER, OnVdWScale)
2642            slideSizer.Add(vdwScale,1,wx.EXPAND|wx.RIGHT)
2643   
2644            ellipseProbTxt = wx.StaticText(drawOptions,-1,' Ellipsoid probability: '+'%d%%'%(drawingData['ellipseProb']))
2645            slideSizer.Add(ellipseProbTxt,0,wx.ALIGN_CENTER_VERTICAL)
2646            ellipseProb = wx.Slider(drawOptions,style=wx.SL_HORIZONTAL,value=drawingData['ellipseProb'])
2647            ellipseProb.SetRange(1,99)
2648            ellipseProb.Bind(wx.EVT_SLIDER, OnEllipseProb)
2649            slideSizer.Add(ellipseProb,1,wx.EXPAND|wx.RIGHT)
2650   
2651            ballScaleTxt = wx.StaticText(drawOptions,-1,' Ball scale: '+'%.2f'%(drawingData['ballScale']))
2652            slideSizer.Add(ballScaleTxt,0,wx.ALIGN_CENTER_VERTICAL)
2653            ballScale = wx.Slider(drawOptions,style=wx.SL_HORIZONTAL,value=int(100*drawingData['ballScale']))
2654            ballScale.Bind(wx.EVT_SLIDER, OnBallScale)
2655            slideSizer.Add(ballScale,1,wx.EXPAND|wx.RIGHT)
2656   
2657            bondRadiusTxt = wx.StaticText(drawOptions,-1,' Bond radius, A: '+'%.2f'%(drawingData['bondRadius']))
2658            slideSizer.Add(bondRadiusTxt,0,wx.ALIGN_CENTER_VERTICAL)
2659            bondRadius = wx.Slider(drawOptions,style=wx.SL_HORIZONTAL,value=int(100*drawingData['bondRadius']))
2660            bondRadius.SetRange(1,25)
2661            bondRadius.Bind(wx.EVT_SLIDER, OnBondRadius)
2662            slideSizer.Add(bondRadius,1,wx.EXPAND|wx.RIGHT)
2663           
2664            if generalData['Map']['rhoMax']:
2665                contourLevelTxt = wx.StaticText(drawOptions,-1,' Contour level: '+'%.2f'%(drawingData['contourLevel']*generalData['Map']['rhoMax']))
2666                slideSizer.Add(contourLevelTxt,0,wx.ALIGN_CENTER_VERTICAL)
2667                contourLevel = wx.Slider(drawOptions,style=wx.SL_HORIZONTAL,value=int(100*drawingData['contourLevel']))
2668                contourLevel.SetRange(1,100)
2669                contourLevel.Bind(wx.EVT_SLIDER, OnContourLevel)
2670                slideSizer.Add(contourLevel,1,wx.EXPAND|wx.RIGHT)
2671                mapSizeTxt = wx.StaticText(drawOptions,-1,' Map radius, A: '+'%.1f'%(drawingData['mapSize']))
2672                slideSizer.Add(mapSizeTxt,0,wx.ALIGN_CENTER_VERTICAL)
2673                mapSize = wx.Slider(drawOptions,style=wx.SL_HORIZONTAL,value=int(10*drawingData['mapSize']))
2674                mapSize.SetRange(1,100)
2675                mapSize.Bind(wx.EVT_SLIDER, OnMapSize)
2676                slideSizer.Add(mapSize,1,wx.EXPAND|wx.RIGHT)
2677           
2678            slopSizer.Add(slideSizer,1,wx.EXPAND|wx.RIGHT)
2679            slopSizer.Add((10,5),0)
2680            slopSizer.SetMinSize(wx.Size(350,10))
2681            return slopSizer
2682           
2683        def ShowSizer():
2684           
2685            def OnBackColor(event):
2686                drawingData['backColor'] = event.GetValue()
2687                G2plt.PlotStructure(G2frame,data)
2688   
2689            def OnShowABC(event):
2690                drawingData['showABC'] = showABC.GetValue()
2691                G2plt.PlotStructure(G2frame,data)
2692   
2693            def OnShowUnitCell(event):
2694                drawingData['unitCellBox'] = unitCellBox.GetValue()
2695                G2plt.PlotStructure(G2frame,data)
2696   
2697            def OnShowHyd(event):
2698                drawingData['showHydrogen'] = showHydrogen.GetValue()
2699                FindBondsDraw()
2700                G2plt.PlotStructure(G2frame,data)
2701               
2702            def OnShowRB(event):
2703                drawingData['showRigidBodies'] = showRB.GetValue()
2704                FindBondsDraw()
2705                G2plt.PlotStructure(G2frame,data)
2706               
2707            def OnViewPoint(event):
2708                Obj = event.GetEventObject()
2709                viewPt = Obj.GetValue().split()
2710                try:
2711                    VP = [float(viewPt[i]) for i in range(3)]
2712                except (ValueError,IndexError):
2713                    VP = drawingData['viewPoint'][0]
2714                Obj.SetValue('%.3f %.3f %.3f'%(VP[0],VP[1],VP[2]))
2715                drawingData['viewPoint'][0] = VP
2716                G2plt.PlotStructure(G2frame,data)
2717               
2718            def OnViewDir(event):
2719                Obj = event.GetEventObject()
2720                viewDir = Obj.GetValue().split()
2721                try:
2722                    Amat,Bmat = G2lat.cell2AB(generalData['Cell'][1:7])
2723                    VD = np.array([float(viewDir[i]) for i in range(3)])
2724                    VC = np.inner(Amat,VD)
2725                    VC /= np.sqrt(np.sum(VC**2))
2726                    V = np.array(drawingData['viewDir'])
2727                    VB = np.inner(Amat,V)
2728                    VB /= np.sqrt(np.sum(VB**2))
2729                    VX = np.cross(VC,VB)
2730                    A = acosd(max((2.-np.sum((VB-VC)**2))/2.,-1.))
2731                    QV = G2mth.AVdeg2Q(A,VX)
2732                    Q = drawingData['Quaternion']
2733                    drawingData['Quaternion'] = G2mth.prodQQ(Q,QV)
2734                except (ValueError,IndexError):
2735                    VD = drawingData['viewDir']
2736                Obj.SetValue('%.3f %.3f %.3f'%(VD[0],VD[1],VD[2]))
2737                drawingData['viewDir'] = VD
2738                G2plt.PlotStructure(G2frame,data)
2739                               
2740            showSizer = wx.BoxSizer(wx.VERTICAL)           
2741            lineSizer = wx.BoxSizer(wx.HORIZONTAL)
2742            lineSizer.Add(wx.StaticText(drawOptions,-1,' Background color:'),0,wx.ALIGN_CENTER_VERTICAL)
2743            backColor = wcs.ColourSelect(drawOptions, -1,colour=drawingData['backColor'],size=wx.Size(25,25))
2744            backColor.Bind(wcs.EVT_COLOURSELECT, OnBackColor)
2745            lineSizer.Add(backColor,0,wx.ALIGN_CENTER_VERTICAL)
2746            lineSizer.Add(wx.StaticText(drawOptions,-1,' View Dir.:'),0,wx.ALIGN_CENTER_VERTICAL)
2747            VD = drawingData['viewDir']
2748            viewDir = wx.TextCtrl(drawOptions,value='%.3f %.3f %.3f'%(VD[0],VD[1],VD[2]),
2749                style=wx.TE_PROCESS_ENTER,size=wx.Size(140,20),name='viewDir')
2750            viewDir.Bind(wx.EVT_TEXT_ENTER,OnViewDir)
2751            viewDir.Bind(wx.EVT_KILL_FOCUS,OnViewDir)
2752            G2frame.dataDisplay.viewDir = viewDir
2753            lineSizer.Add(viewDir,0,wx.ALIGN_CENTER_VERTICAL)
2754            showSizer.Add(lineSizer)
2755            showSizer.Add((0,5),0)
2756           
2757            lineSizer = wx.BoxSizer(wx.HORIZONTAL)
2758            showABC = wx.CheckBox(drawOptions,-1,label=' Show view point?')
2759            showABC.Bind(wx.EVT_CHECKBOX, OnShowABC)
2760            showABC.SetValue(drawingData['showABC'])
2761            lineSizer.Add(showABC,0,wx.ALIGN_CENTER_VERTICAL)
2762            lineSizer.Add(wx.StaticText(drawOptions,-1,' View Point:'),0,wx.ALIGN_CENTER_VERTICAL)
2763            VP = drawingData['viewPoint'][0]
2764            viewPoint = wx.TextCtrl(drawOptions,value='%.3f %.3f %.3f'%(VP[0],VP[1],VP[2]),
2765                style=wx.TE_PROCESS_ENTER,size=wx.Size(140,20),name='viewPoint')
2766            G2frame.dataDisplay.viewPoint = viewPoint
2767            viewPoint.Bind(wx.EVT_TEXT_ENTER,OnViewPoint)
2768            viewPoint.Bind(wx.EVT_KILL_FOCUS,OnViewPoint)
2769            lineSizer.Add(viewPoint,0,wx.ALIGN_CENTER_VERTICAL)
2770            showSizer.Add(lineSizer)
2771            showSizer.Add((0,5),0)
2772           
2773            line2Sizer = wx.BoxSizer(wx.HORIZONTAL)
2774   
2775            unitCellBox = wx.CheckBox(drawOptions,-1,label=' Show unit cell?')
2776            unitCellBox.Bind(wx.EVT_CHECKBOX, OnShowUnitCell)
2777            unitCellBox.SetValue(drawingData['unitCellBox'])
2778            line2Sizer.Add(unitCellBox,0,wx.ALIGN_CENTER_VERTICAL)
2779   
2780            showHydrogen = wx.CheckBox(drawOptions,-1,label=' Show hydrogens?')
2781            showHydrogen.Bind(wx.EVT_CHECKBOX, OnShowHyd)
2782            showHydrogen.SetValue(drawingData['showHydrogen'])
2783            line2Sizer.Add(showHydrogen,0,wx.ALIGN_CENTER_VERTICAL)
2784           
2785            showRB = wx.CheckBox(drawOptions,-1,label=' Show rigid Bodies?')
2786            showRB.Bind(wx.EVT_CHECKBOX, OnShowRB)
2787            showRB.SetValue(drawingData['showRigidBodies'])
2788            line2Sizer.Add(showRB,0,wx.ALIGN_CENTER_VERTICAL)
2789           
2790            showSizer.Add(line2Sizer)
2791            return showSizer
2792           
2793        def RadSizer():
2794           
2795            def OnSizeHatoms(event):
2796                try:
2797                    value = max(0.1,min(1.2,float(sizeH.GetValue())))
2798                except ValueError:
2799                    value = 0.5
2800                drawingData['sizeH'] = value
2801                sizeH.SetValue("%.2f"%(value))
2802                G2plt.PlotStructure(G2frame,data)
2803               
2804            def OnRadFactor(event):
2805                try:
2806                    value = max(0.1,min(1.2,float(radFactor.GetValue())))
2807                except ValueError:
2808                    value = 0.85
2809                drawingData['radiusFactor'] = value
2810                radFactor.SetValue("%.2f"%(value))
2811                FindBondsDraw()
2812                G2plt.PlotStructure(G2frame,data)
2813           
2814            radSizer = wx.BoxSizer(wx.HORIZONTAL)
2815            radSizer.Add(wx.StaticText(drawOptions,-1,' Hydrogen radius, A:  '),0,wx.ALIGN_CENTER_VERTICAL)
2816            sizeH = wx.TextCtrl(drawOptions,-1,value='%.2f'%(drawingData['sizeH']),size=wx.Size(60,20),style=wx.TE_PROCESS_ENTER)
2817            sizeH.Bind(wx.EVT_TEXT_ENTER,OnSizeHatoms)
2818            sizeH.Bind(wx.EVT_KILL_FOCUS,OnSizeHatoms)
2819            radSizer.Add(sizeH,0,wx.ALIGN_CENTER_VERTICAL)
2820   
2821            radSizer.Add(wx.StaticText(drawOptions,-1,' Bond search factor:  '),0,wx.ALIGN_CENTER_VERTICAL)
2822            radFactor = wx.TextCtrl(drawOptions,value='%.2f'%(drawingData['radiusFactor']),size=wx.Size(60,20),style=wx.TE_PROCESS_ENTER)
2823            radFactor.Bind(wx.EVT_TEXT_ENTER,OnRadFactor)
2824            radFactor.Bind(wx.EVT_KILL_FOCUS,OnRadFactor)
2825            radSizer.Add(radFactor,0,wx.ALIGN_CENTER_VERTICAL)
2826            return radSizer
2827
2828        # UpdateDrawOptions exectable code starts here
2829        generalData = data['General']
2830        Amat,Bmat = G2lat.cell2AB(generalData['Cell'][1:7])
2831        SetupDrawingData()
2832        drawingData = data['Drawing']
2833        if generalData['Type'] == 'nuclear':
2834            pickChoice = ['Atoms','Bonds','Torsions','Planes']
2835        elif generalData['Type'] == 'macromolecular':
2836            pickChoice = ['Atoms','Residues','Chains','Bonds','Torsions','Planes','phi/psi']
2837
2838        G2frame.dataFrame.SetStatusText('')
2839        if drawOptions.GetSizer():
2840            drawOptions.GetSizer().Clear(True)
2841        mainSizer = wx.BoxSizer(wx.VERTICAL)
2842        mainSizer.Add((5,5),0)
2843        mainSizer.Add(wx.StaticText(drawOptions,-1,' Drawing controls:'),0,wx.ALIGN_CENTER_VERTICAL)
2844        mainSizer.Add((5,5),0)       
2845        mainSizer.Add(SlopSizer(),0)
2846        mainSizer.Add((5,5),0)
2847        mainSizer.Add(ShowSizer(),0,)
2848        mainSizer.Add((5,5),0)
2849        mainSizer.Add(RadSizer(),0,)
2850        SetPhaseWindow(G2frame.dataFrame,drawOptions,mainSizer)
2851
2852################################################################################
2853####  Texture routines
2854################################################################################
2855       
2856    def UpdateTexture():       
2857        def SetSHCoef():
2858            cofNames = G2lat.GenSHCoeff(SGData['SGLaue'],SamSym[textureData['Model']],textureData['Order'])
2859            newSHCoef = dict(zip(cofNames,np.zeros(len(cofNames))))
2860            SHCoeff = textureData['SH Coeff'][1]
2861            for cofName in SHCoeff:
2862                if cofName in  cofNames:
2863                    newSHCoef[cofName] = SHCoeff[cofName]
2864            return newSHCoef
2865       
2866        def OnShOrder(event):
2867            Obj = event.GetEventObject()
2868            textureData['Order'] = int(Obj.GetValue())
2869            textureData['SH Coeff'][1] = SetSHCoef()
2870            wx.CallAfter(UpdateTexture)
2871            G2plt.PlotTexture(G2frame,data)
2872                       
2873        def OnShModel(event):
2874            Obj = event.GetEventObject()
2875            textureData['Model'] = Obj.GetValue()
2876            textureData['SH Coeff'][1] = SetSHCoef()
2877            wx.CallAfter(UpdateTexture)
2878            G2plt.PlotTexture(G2frame,data)
2879           
2880        def OnSHRefine(event):
2881            Obj = event.GetEventObject()
2882            textureData['SH Coeff'][0] = Obj.GetValue()
2883           
2884        def OnSHShow(event):
2885            Obj = event.GetEventObject()
2886            textureData['SHShow'] = Obj.GetValue()
2887            wx.CallAfter(UpdateTexture)
2888           
2889        def OnProjSel(event):
2890            Obj = event.GetEventObject()
2891            G2frame.Projection = Obj.GetValue()
2892            G2plt.PlotTexture(G2frame,data)
2893           
2894        def OnColorSel(event):
2895            Obj = event.GetEventObject()
2896            G2frame.ContourColor = Obj.GetValue()
2897            G2plt.PlotTexture(G2frame,data)
2898           
2899        def OnAngRef(event):
2900            Obj = event.GetEventObject()
2901            textureData[angIndx[Obj.GetId()]][0] = Obj.GetValue()
2902           
2903        def OnAngValue(event):
2904            Obj = event.GetEventObject()
2905            try:
2906                value =  float(Obj.GetValue())
2907            except ValueError:
2908                value = textureData[valIndx[Obj.GetId()]][1]
2909            Obj.SetValue('%8.2f'%(value))
2910            textureData[valIndx[Obj.GetId()]][1] = value
2911           
2912        def OnODFValue(event): 
2913            Obj = event.GetEventObject()
2914            try:
2915                value =  float(Obj.GetValue())
2916            except ValueError:
2917                value = textureData['SH Coeff'][1][ODFIndx[Obj.GetId()]]
2918            Obj.SetValue('%8.3f'%(value))
2919            textureData['SH Coeff'][1][ODFIndx[Obj.GetId()]] = value
2920            G2plt.PlotTexture(G2frame,data)
2921           
2922        def OnPfType(event):
2923            Obj = event.GetEventObject()
2924            textureData['PlotType'] = Obj.GetValue()
2925            wx.CallAfter(UpdateTexture)
2926            G2plt.PlotTexture(G2frame,data)
2927           
2928        def OnPFValue(event):
2929            Obj = event.GetEventObject()
2930            Saxis = Obj.GetValue().split()
2931            if textureData['PlotType'] in ['Pole figure','Axial pole distribution']:               
2932                try:
2933                    hkl = [int(Saxis[i]) for i in range(3)]
2934                except (ValueError,IndexError):
2935                    hkl = textureData['PFhkl']
2936                if not np.any(np.array(hkl)):       #can't be all zeros!
2937                    hkl = textureData['PFhkl']
2938                Obj.SetValue('%d %d %d'%(hkl[0],hkl[1],hkl[2]))
2939                textureData['PFhkl'] = hkl
2940            else:
2941                try:
2942                    xyz = [float(Saxis[i]) for i in range(3)]
2943                except (ValueError,IndexError):
2944                    xyz = textureData['PFxyz']
2945                if not np.any(np.array(xyz)):       #can't be all zeros!
2946                    xyz = textureData['PFxyz']
2947                Obj.SetValue('%3.1f %3.1f %3.1f'%(xyz[0],xyz[1],xyz[2]))
2948                textureData['PFxyz'] = xyz
2949            G2plt.PlotTexture(G2frame,data)
2950
2951        # UpdateTexture executable starts here
2952        G2frame.dataFrame.SetStatusText('')
2953        generalData = data['General']       
2954        SGData = generalData['SGData']
2955        try:
2956            textureData = generalData['SH Texture']
2957        except KeyError:            #fix old files!
2958            textureData = generalData['SH Texture'] = {'Order':0,'Model':'cylindrical',
2959                'Sample omega':[False,0.0],'Sample chi':[False,0.0],'Sample phi':[False,0.0],
2960                'SH Coeff':[False,{}],'SHShow':False,'PFhkl':[0,0,1],
2961                'PFxyz':[0,0,1.],'PlotType':'Pole figure'}
2962        if 'SHShow' not in textureData:     #another fix
2963            textureData.update({'SHShow':False,'PFhkl':[0,0,1],'PFxyz':[0,0,1.],'PlotType':'Pole figure'})
2964        try:                        #another fix!
2965            x = textureData['PlotType']
2966        except KeyError:
2967            textureData.update({'PFxyz':[0,0,1.],'PlotType':'Pole figure'})
2968        shModels = ['cylindrical','none','shear - 2/m','rolling - mmm']
2969        SamSym = dict(zip(shModels,['0','-1','2/m','mmm']))
2970        if generalData['doPawley'] and G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Sequental results'):
2971            G2frame.dataFrame.RefineTexture.Enable(True)
2972        shAngles = ['omega','chi','phi']
2973        if Texture.GetSizer():
2974            Texture.GetSizer().Clear(True)
2975        mainSizer = wx.BoxSizer(wx.VERTICAL)
2976        titleSizer = wx.BoxSizer(wx.HORIZONTAL)
2977        titleSizer.Add(wx.StaticText(Texture,-1,'Spherical harmonics texture data for '+PhaseName+':'),0,wx.ALIGN_CENTER_VERTICAL)
2978        titleSizer.Add(wx.StaticText(Texture,-1,
2979            ' Texture Index J = %7.3f'%(G2lat.textureIndex(textureData['SH Coeff'][1]))),
2980            0,wx.ALIGN_CENTER_VERTICAL)
2981        mainSizer.Add(titleSizer,0)
2982        mainSizer.Add((0,5),0)
2983        shSizer = wx.FlexGridSizer(1,6,5,5)
2984        shSizer.Add(wx.StaticText(Texture,-1,'Texture model: '),0,wx.ALIGN_CENTER_VERTICAL)
2985        shModel = wx.ComboBox(Texture,-1,value=textureData['Model'],choices=shModels,
2986            style=wx.CB_READONLY|wx.CB_DROPDOWN)
2987        shModel.Bind(wx.EVT_COMBOBOX,OnShModel)
2988        shSizer.Add(shModel,0,wx.ALIGN_CENTER_VERTICAL)
2989        shSizer.Add(wx.StaticText(Texture,-1,'  Harmonic order: '),0,wx.ALIGN_CENTER_VERTICAL)
2990        shOrder = wx.ComboBox(Texture,-1,value=str(textureData['Order']),choices=[str(2*i) for i in range(18)],
2991            style=wx.CB_READONLY|wx.CB_DROPDOWN)
2992        shOrder.Bind(wx.EVT_COMBOBOX,OnShOrder)
2993        shSizer.Add(shOrder,0,wx.ALIGN_CENTER_VERTICAL)
2994        shRef = wx.CheckBox(Texture,-1,label=' Refine texture?')
2995        shRef.SetValue(textureData['SH Coeff'][0])
2996        shRef.Bind(wx.EVT_CHECKBOX, OnSHRefine)
2997        shSizer.Add(shRef,0,wx.ALIGN_CENTER_VERTICAL)
2998        shShow = wx.CheckBox(Texture,-1,label=' Show coeff.?')
2999        shShow.SetValue(textureData['SHShow'])
3000        shShow.Bind(wx.EVT_CHECKBOX, OnSHShow)
3001        shSizer.Add(shShow,0,wx.ALIGN_CENTER_VERTICAL)
3002        mainSizer.Add(shSizer,0,0)
3003        mainSizer.Add((0,5),0)
3004        PTSizer = wx.FlexGridSizer(2,4,5,5)
3005        PTSizer.Add(wx.StaticText(Texture,-1,' Texture plot type: '),0,wx.ALIGN_CENTER_VERTICAL)
3006        choices = ['Axial pole distribution','Pole figure','Inverse pole figure']           
3007        pfType = wx.ComboBox(Texture,-1,value=str(textureData['PlotType']),choices=choices,
3008            style=wx.CB_READONLY|wx.CB_DROPDOWN)
3009        pfType.Bind(wx.EVT_COMBOBOX,OnPfType)
3010        PTSizer.Add(pfType,0,wx.ALIGN_CENTER_VERTICAL)
3011        if 'Axial' not in textureData['PlotType']:
3012            PTSizer.Add(wx.StaticText(Texture,-1,' Projection type: '),0,wx.ALIGN_CENTER_VERTICAL)
3013            projSel = wx.ComboBox(Texture,-1,value=G2frame.Projection,choices=['equal area','stereographic','3D display'],
3014                style=wx.CB_READONLY|wx.CB_DROPDOWN)
3015            projSel.Bind(wx.EVT_COMBOBOX,OnProjSel)
3016            PTSizer.Add(projSel,0,wx.ALIGN_CENTER_VERTICAL)
3017        if textureData['PlotType'] in ['Pole figure','Axial pole distribution']:
3018            PTSizer.Add(wx.StaticText(Texture,-1,' Pole figure HKL: '),0,wx.ALIGN_CENTER_VERTICAL)
3019            PH = textureData['PFhkl']
3020            pfVal = wx.TextCtrl(Texture,-1,'%d %d %d'%(PH[0],PH[1],PH[2]),style=wx.TE_PROCESS_ENTER)
3021        else:
3022            PTSizer.Add(wx.StaticText(Texture,-1,' Inverse pole figure XYZ: '),0,wx.ALIGN_CENTER_VERTICAL)
3023            PX = textureData['PFxyz']
3024            pfVal = wx.TextCtrl(Texture,-1,'%3.1f %3.1f %3.1f'%(PX[0],PX[1],PX[2]),style=wx.TE_PROCESS_ENTER)
3025        pfVal.Bind(wx.EVT_TEXT_ENTER,OnPFValue)
3026        pfVal.Bind(wx.EVT_KILL_FOCUS,OnPFValue)
3027        PTSizer.Add(pfVal,0,wx.ALIGN_CENTER_VERTICAL)
3028        if 'Axial' not in textureData['PlotType']:
3029            PTSizer.Add(wx.StaticText(Texture,-1,' Color scheme'),0,wx.ALIGN_CENTER_VERTICAL)
3030            choice = [m for m in mpl.cm.datad.keys() if not m.endswith("_r")]
3031            choice.sort()
3032            colorSel = wx.ComboBox(Texture,-1,value=G2frame.ContourColor,choices=choice,
3033                style=wx.CB_READONLY|wx.CB_DROPDOWN)
3034            colorSel.Bind(wx.EVT_COMBOBOX,OnColorSel)
3035            PTSizer.Add(colorSel,0,wx.ALIGN_CENTER_VERTICAL)       
3036        mainSizer.Add(PTSizer,0,wx.ALIGN_CENTER_VERTICAL)
3037        mainSizer.Add((0,5),0)
3038        if textureData['SHShow']:
3039            mainSizer.Add(wx.StaticText(Texture,-1,'Spherical harmonic coefficients: '),0,wx.ALIGN_CENTER_VERTICAL)
3040            mainSizer.Add((0,5),0)
3041            ODFSizer = wx.FlexGridSizer(2,8,2,2)
3042            ODFIndx = {}
3043            ODFkeys = textureData['SH Coeff'][1].keys()
3044            ODFkeys.sort()
3045            for item in ODFkeys:
3046                ODFSizer.Add(wx.StaticText(Texture,-1,item),0,wx.ALIGN_CENTER_VERTICAL)
3047                ODFval = wx.TextCtrl(Texture,wx.ID_ANY,'%8.3f'%(textureData['SH Coeff'][1][item]),style=wx.TE_PROCESS_ENTER)
3048                ODFIndx[ODFval.GetId()] = item
3049                ODFval.Bind(wx.EVT_TEXT_ENTER,OnODFValue)
3050                ODFval.Bind(wx.EVT_KILL_FOCUS,OnODFValue)
3051                ODFSizer.Add(ODFval,0,wx.ALIGN_CENTER_VERTICAL)
3052            mainSizer.Add(ODFSizer,0,wx.ALIGN_CENTER_VERTICAL)
3053            mainSizer.Add((0,5),0)
3054        mainSizer.Add((0,5),0)
3055        mainSizer.Add(wx.StaticText(Texture,-1,'Sample orientation angles: '),0,wx.ALIGN_CENTER_VERTICAL)
3056        mainSizer.Add((0,5),0)
3057        angSizer = wx.BoxSizer(wx.HORIZONTAL)
3058        angIndx = {}
3059        valIndx = {}
3060        for item in ['Sample omega','Sample chi','Sample phi']:
3061            angRef = wx.CheckBox(Texture,-1,label=item+': ')
3062            angRef.SetValue(textureData[item][0])
3063            angIndx[angRef.GetId()] = item
3064            angRef.Bind(wx.EVT_CHECKBOX, OnAngRef)
3065            angSizer.Add(angRef,0,wx.ALIGN_CENTER_VERTICAL)
3066            angVal = wx.TextCtrl(Texture,wx.ID_ANY,'%8.2f'%(textureData[item][1]),style=wx.TE_PROCESS_ENTER)
3067            valIndx[angVal.GetId()] = item
3068            angVal.Bind(wx.EVT_TEXT_ENTER,OnAngValue)
3069            angVal.Bind(wx.EVT_KILL_FOCUS,OnAngValue)
3070            angSizer.Add(angVal,0,wx.ALIGN_CENTER_VERTICAL)
3071            angSizer.Add((5,0),0)
3072        mainSizer.Add(angSizer,0,wx.ALIGN_CENTER_VERTICAL)
3073        SetPhaseWindow(G2frame.dataFrame,Texture,mainSizer)
3074
3075################################################################################
3076##### DData routines - GUI stuff in GSASIIddataGUI.py
3077################################################################################
3078       
3079    def OnHklfAdd(event):
3080        UseList = data['Histograms']
3081        keyList = UseList.keys()
3082        TextList = []
3083        if G2frame.PatternTree.GetCount():
3084            item, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)
3085            while item:
3086                name = G2frame.PatternTree.GetItemText(item)
3087                if name not in keyList and 'HKLF' in name:
3088                    TextList.append(name)
3089                item, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)                       
3090            dlg = wx.MultiChoiceDialog(G2frame, 'Which new data to use?', 'Use data', TextList, wx.CHOICEDLG_STYLE)
3091            try:
3092                if dlg.ShowModal() == wx.ID_OK:
3093                    result = dlg.GetSelections()
3094                    for i in result:
3095                        histoName = TextList[i]
3096                        UseList[histoName] = {'Histogram':histoName,'Show':False,'Scale':[1.0,True],
3097                            'Babinet':{'BabA':[0.0,False],'BabU':[0.0,False]},
3098                            'Extinction':['Lorentzian','None',
3099                            {'Tbar':0.1,'Cos2TM':0.955,'Eg':[1.e-10,False],'Es':[1.e-10,False],'Ep':[1.e-10,False]},]}                       
3100                        wx.BeginBusyCursor()
3101                        UpdateHKLFdata(histoName)
3102                        wx.EndBusyCursor()
3103                    data['Histograms'] = UseList
3104                    wx.CallAfter(G2ddG.UpdateDData,G2frame,DData,data)
3105            finally:
3106                dlg.Destroy()
3107               
3108    def UpdateHKLFdata(histoName):
3109        generalData = data['General']
3110        Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,histoName)
3111        refDict,reflData = G2frame.PatternTree.GetItemPyData(Id)
3112        SGData = generalData['SGData']
3113        Cell = generalData['Cell'][1:7]
3114        G,g = G2lat.cell2Gmat(Cell)
3115        for iref,ref in enumerate(reflData['RefList']):
3116            H = list(ref[:3])
3117            ref[4] = np.sqrt(1./G2lat.calc_rDsq2(H,G))
3118            iabsnt,ref[3],Uniq,phi = G2spc.GenHKLf(H,SGData)
3119        G2frame.PatternTree.SetItemPyData(Id,[refDict,reflData])
3120       
3121    def OnPwdrAdd(event):
3122        generalData = data['General']
3123        SGData = generalData['SGData']
3124        UseList = data['Histograms']
3125        newList = []
3126        NShkl = len(G2spc.MustrainNames(SGData))
3127        NDij = len(G2spc.HStrainNames(SGData))
3128        keyList = UseList.keys()
3129        TextList = ['All PWDR']
3130        if G2frame.PatternTree.GetCount():
3131            item, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)
3132            while item:
3133                name = G2frame.PatternTree.GetItemText(item)
3134                if name not in keyList and 'PWDR' in name:
3135                    TextList.append(name)
3136                item, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)
3137            dlg = wx.MultiChoiceDialog(G2frame, 'Which new data to use?', 'Use data', TextList, wx.CHOICEDLG_STYLE)
3138            try:
3139                if dlg.ShowModal() == wx.ID_OK:
3140                    result = dlg.GetSelections()
3141                    for i in result: newList.append(TextList[i])
3142                    if 'All PWDR' in newList:
3143                        newList = TextList[1:]
3144                    for histoName in newList:
3145                        pId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,histoName)
3146                        UseList[histoName] = {'Histogram':histoName,'Show':False,
3147                            'Scale':[1.0,False],'Pref.Ori.':['MD',1.0,False,[0,0,1],0,{}],
3148                            'Size':['isotropic',[1.,1.,1.],[False,False,False],[0,0,1],
3149                                [1.,1.,1.,0.,0.,0.],6*[False,]],
3150                            'Mustrain':['isotropic',[1000.0,1000.0,1.0],[False,False,False],[0,0,1],
3151                                NShkl*[0.01,],NShkl*[False,]],
3152                            'HStrain':[NDij*[0.0,],NDij*[False,]],                         
3153                            'Extinction':[0.0,False],'Babinet':{'BabA':[0.0,False],'BabU':[0.0,False]}}
3154                        refList = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,pId,'Reflection Lists'))
3155                        refList[generalData['Name']] = []                       
3156                    data['Histograms'] = UseList
3157                    wx.CallAfter(G2ddG.UpdateDData,G2frame,DData,data)
3158            finally:
3159                dlg.Destroy()
3160       
3161    def OnDataDelete(event):
3162        UseList = data['Histograms']
3163        keyList = ['All',]+UseList.keys()
3164        keyList.sort()
3165        DelList = []
3166        if UseList:
3167            DelList = []
3168            dlg = wx.MultiChoiceDialog(G2frame, 
3169                'Which histogram to delete from this phase?', 'Delete histogram', 
3170                keyList, wx.CHOICEDLG_STYLE)
3171            try:
3172                if dlg.ShowModal() == wx.ID_OK:
3173                    result = dlg.GetSelections()
3174                    for i in result: 
3175                        DelList.append(keyList[i])
3176                    if 'All' in DelList:
3177                        DelList = keyList[1:]
3178                    for i in DelList:
3179                        del UseList[i]
3180                    wx.CallAfter(G2ddG.UpdateDData,G2frame,DData,data)
3181            finally:
3182                dlg.Destroy()
3183               
3184################################################################################
3185##### Rigid bodies
3186################################################################################
3187
3188    def FillRigidBodyGrid(refresh=True):
3189        '''Fill the Rigid Body Phase information tab page.
3190        Note that the page is a ScrolledWindow, not a Grid
3191        '''
3192        def OnThermSel(event):       #needs to be seen by VecRbSizer!
3193            Obj = event.GetEventObject()
3194            RBObj = Indx[Obj.GetId()]
3195            val = Obj.GetValue()
3196            Ttype = 'A'
3197            if val == 'Uiso':
3198                Ttype = 'I'
3199                RBObj['ThermalMotion'][0] = 'Uiso'
3200            elif val == 'T':
3201                RBObj['ThermalMotion'][0] = 'T'
3202            elif val == 'TL':
3203                RBObj['ThermalMotion'][0] = 'TL'
3204            elif val == 'TLS':
3205                RBObj['ThermalMotion'][0] = 'TLS'
3206            wx.CallAfter(FillRigidBodyGrid,True)
3207            if val != 'None':
3208                cia = data['General']['AtomPtrs'][3]
3209                for i,id in enumerate(RBObj['Ids']):
3210                    data['Atoms'][AtLookUp[id]][cia] = Ttype
3211            G2plt.PlotStructure(G2frame,data)
3212           
3213        def ThermDataSizer(RBObj,rbType):
3214           
3215            def OnThermval(event):
3216                Obj = event.GetEventObject()
3217                item = Indx[Obj.GetId()]
3218                try:
3219                    val = float(Obj.GetValue())
3220                    RBObj['ThermalMotion'][1][item] = val
3221                except ValueError:
3222                    pass
3223                Obj.SetValue('%8.4f'%(RBObj['ThermalMotion'][1][item]))
3224                Cart = G2mth.UpdateRBXYZ(Bmat,RBObj,RBData,rbType)[1]
3225                Uout = G2mth.UpdateRBUIJ(Bmat,Cart,RBObj)
3226                cia = data['General']['AtomPtrs'][3]
3227                for i,id in enumerate(RBObj['Ids']):
3228                    if Uout[i][0] == 'I':
3229                        data['Atoms'][AtLookUp[id]][cia+1] = Uout[i][1]
3230                    else:
3231                        data['Atoms'][AtLookUp[id]][cia+2:cia+8] = Uout[i][2:8]
3232                G2plt.PlotStructure(G2frame,data)
3233               
3234            def OnTLSRef(event):
3235                Obj = event.GetEventObject()
3236                item = Indx[Obj.GetId()]
3237                RBObj['ThermalMotion'][2][item] = Obj.GetValue()
3238           
3239            thermSizer = wx.FlexGridSizer(1,9,5,5)
3240            model = RBObj['ThermalMotion']
3241            if model[0] == 'Uiso':
3242                names = ['Uiso',]
3243            elif 'T' in model[0]:
3244                names = ['T11','T22','T33','T12','T13','T23']
3245            if 'L' in model[0]:
3246                names += ['L11','L22','L33','L12','L13','L23']
3247            if 'S' in model[0]:
3248                names += ['S12','S13','S21','S23','S31','S32','SAA','SBB']
3249            for i,name in enumerate(names):
3250                thermSizer.Add(wx.StaticText(RigidBodies,-1,name+': '),0,wx.ALIGN_CENTER_VERTICAL)
3251                thermVal = wx.TextCtrl(RigidBodies,-1,value='%8.4f'%(model[1][i]),
3252                    style=wx.TE_PROCESS_ENTER)
3253                thermVal.Bind(wx.EVT_TEXT_ENTER,OnThermval)
3254                thermVal.Bind(wx.EVT_KILL_FOCUS,OnThermval)
3255                Indx[thermVal.GetId()] = i
3256                thermSizer.Add(thermVal)
3257                Tcheck = wx.CheckBox(RigidBodies,-1,'Refine?')
3258                Tcheck.Bind(wx.EVT_CHECKBOX,OnTLSRef)
3259                Tcheck.SetValue(model[2][i])
3260                Indx[Tcheck.GetId()] = i
3261                thermSizer.Add(Tcheck,0,wx.ALIGN_CENTER_VERTICAL)
3262            return thermSizer
3263           
3264        def LocationSizer(RBObj,rbType):
3265           
3266            def OnOrigRef(event):
3267                RBObj['Orig'][1] = Ocheck.GetValue()
3268             
3269            def OnOrienRef(event):
3270                RBObj['Orient'][1] = Qcheck.GetValue()
3271               
3272            def OnOrigX(event):
3273                Obj = event.GetEventObject()
3274                item = Indx[Obj.GetId()]
3275                try:
3276                    val = float(Obj.GetValue())
3277                    RBObj['Orig'][0][item] = val
3278                    Obj.SetValue('%8.5f'%(val))
3279                    newXYZ = G2mth.UpdateRBXYZ(Bmat,RBObj,RBData,rbType)[0]
3280                    for i,id in enumerate(RBObj['Ids']):
3281                        data['Atoms'][AtLookUp[id]][cx:cx+3] = newXYZ[i]
3282                    data['Drawing']['Atoms'] = []
3283                    UpdateDrawAtoms(atomStyle)
3284                    G2plt.PlotStructure(G2frame,data)
3285                except ValueError:
3286                    pass
3287               
3288            def OnOrien(event):
3289                Obj = event.GetEventObject()
3290                item = Indx[Obj.GetId()]
3291                A,V = G2mth.Q2AVdeg(RBObj['Orient'][0])
3292                V = np.inner(Bmat,V)
3293                try:
3294                    val = float(Obj.GetValue())
3295                    if item:
3296                        V[item-1] = val
3297                    else:
3298                        A = val
3299                    Obj.SetValue('%8.5f'%(val))
3300                    V = np.inner(Amat,V)
3301                    Q = G2mth.AVdeg2Q(A,V)
3302                    if not any(Q):
3303                        raise ValueError
3304                    RBObj['Orient'][0] = Q
3305                    newXYZ = G2mth.UpdateRBXYZ(Bmat,RBObj,RBData,rbType)[0]
3306                    for i,id in enumerate(RBObj['Ids']):
3307                        data['Atoms'][AtLookUp[id]][cx:cx+3] = newXYZ[i]
3308                    data['Drawing']['Atoms'] = []
3309                    UpdateDrawAtoms(atomStyle)
3310                    G2plt.PlotStructure(G2frame,data)
3311                except ValueError:
3312                    pass
3313               
3314            topSizer = wx.FlexGridSizer(2,6,5,5)
3315            Orig = RBObj['Orig'][0]
3316            Orien,OrienV = G2mth.Q2AVdeg(RBObj['Orient'][0])
3317            Orien = [Orien,]
3318            Orien.extend(OrienV/nl.norm(OrienV))
3319            topSizer.Add(wx.StaticText(RigidBodies,-1,'Origin x,y,z:'),0,wx.ALIGN_CENTER_VERTICAL)
3320            for ix,x in enumerate(Orig):
3321                origX = wx.TextCtrl(RigidBodies,-1,value='%8.5f'%(x),style=wx.TE_PROCESS_ENTER)
3322                origX.Bind(wx.EVT_TEXT_ENTER,OnOrigX)
3323                origX.Bind(wx.EVT_KILL_FOCUS,OnOrigX)
3324                Indx[origX.GetId()] = ix
3325                topSizer.Add(origX,0,wx.ALIGN_CENTER_VERTICAL)
3326            topSizer.Add((5,0),)
3327            Ocheck = wx.CheckBox(RigidBodies,-1,'Refine?')
3328            Ocheck.Bind(wx.EVT_CHECKBOX,OnOrigRef)
3329            Ocheck.SetValue(RBObj['Orig'][1])
3330            topSizer.Add(Ocheck,0,wx.ALIGN_CENTER_VERTICAL)
3331            topSizer.Add(wx.StaticText(RigidBodies,-1,'Rotation angle, vector:'),0,wx.ALIGN_CENTER_VERTICAL)
3332            for ix,x in enumerate(Orien):
3333                orien = wx.TextCtrl(RigidBodies,-1,value='%8.4f'%(x),style=wx.TE_PROCESS_ENTER)
3334                orien.Bind(wx.EVT_TEXT_ENTER,OnOrien)
3335                orien.Bind(wx.EVT_KILL_FOCUS,OnOrien)
3336                Indx[orien.GetId()] = ix
3337                topSizer.Add(orien,0,wx.ALIGN_CENTER_VERTICAL)
3338            Qcheck = wx.ComboBox(RigidBodies,-1,value='',choices=[' ','A','AV'],
3339                style=wx.CB_READONLY|wx.CB_DROPDOWN)
3340            Qcheck.Bind(wx.EVT_COMBOBOX,OnOrienRef)
3341            Qcheck.SetValue(RBObj['Orient'][1])
3342            topSizer.Add(Qcheck)
3343            return topSizer
3344                         
3345        def ResrbSizer(RBObj):
3346            G2frame.dataFrame.SetStatusText('NB: Rotation vector is in crystallographic space')
3347             
3348            def OnTorsionRef(event):
3349                Obj = event.GetEventObject()
3350                item = Indx[Obj.GetId()]
3351                RBObj['Torsions'][item][1] = Obj.GetValue()               
3352               
3353            def OnTorsion(event):
3354                Obj = event.GetEventObject()
3355                item = Indx[Obj.GetId()]
3356                try:
3357                    val = float(Obj.GetValue())
3358                    RBObj['Torsions'][item][0] = val
3359                    newXYZ = G2mth.UpdateRBXYZ(Bmat,RBObj,RBData,'Residue')[0]
3360                    for i,id in enumerate(RBObj['Ids']):
3361                        data['Atoms'][AtLookUp[id]][cx:cx+3] = newXYZ[i]
3362                except ValueError:
3363                    pass
3364                Obj.SetValue("%10.3f"%(RBObj['Torsions'][item][0]))               
3365                data['Drawing']['Atoms'] = []
3366                UpdateDrawAtoms(atomStyle)
3367                drawAtoms.ClearSelection()
3368                G2plt.PlotStructure(G2frame,data)
3369               
3370            def OnDelResRB(event):
3371                Obj = event.GetEventObject()
3372                RBId = Indx[Obj.GetId()]
3373                RBData['Residue'][RBId]['useCount'] -= 1
3374                RBObjs = data['RBModels']['Residue']
3375                for rbObj in RBObjs:
3376                    if RBId == rbObj['RBId']:
3377                       data['RBModels']['Residue'].remove(rbObj)                 
3378                G2plt.PlotStructure(G2frame,data)
3379                wx.CallAfter(FillRigidBodyGrid,True)
3380               
3381            resrbSizer = wx.BoxSizer(wx.VERTICAL)
3382            resrbSizer.Add(wx.StaticText(RigidBodies,-1,120*'-'))
3383            topLine = wx.BoxSizer(wx.HORIZONTAL)
3384            topLine.Add(wx.StaticText(RigidBodies,-1,
3385                'Name: '+RBObj['RBname']+RBObj['numChain']+'   '),0,wx.ALIGN_CENTER_VERTICAL)
3386            rbId = RBObj['RBId']
3387            delRB = wx.CheckBox(RigidBodies,-1,'Delete?')
3388            delRB.Bind(wx.EVT_CHECKBOX,OnDelResRB)
3389            Indx[delRB.GetId()] = rbId
3390            topLine.Add(delRB,0,wx.ALIGN_CENTER_VERTICAL)
3391            resrbSizer.Add(topLine)
3392            resrbSizer.Add(LocationSizer(RBObj,'Residue'))
3393            resrbSizer.Add(wx.StaticText(RigidBodies,-1,'Torsions:'),0,wx.ALIGN_CENTER_VERTICAL)
3394            torSizer = wx.FlexGridSizer(1,6,5,5)
3395            for itors,tors in enumerate(RBObj['Torsions']):
3396                torSizer.Add(wx.StaticText(RigidBodies,-1,'Torsion '+'%d'%(itors)),0,wx.ALIGN_CENTER_VERTICAL)
3397                torsTxt = wx.TextCtrl(RigidBodies,-1,value='%.3f'%(tors[0]),style=wx.TE_PROCESS_ENTER)
3398                torsTxt.Bind(wx.EVT_TEXT_ENTER,OnTorsion)
3399                torsTxt.Bind(wx.EVT_KILL_FOCUS,OnTorsion)
3400                Indx[torsTxt.GetId()] = itors
3401                torSizer.Add(torsTxt)
3402                torCheck = wx.CheckBox(RigidBodies,-1,'Refine?')
3403                torCheck.Bind(wx.EVT_CHECKBOX,OnTorsionRef)
3404                torCheck.SetValue(tors[1])
3405                Indx[torCheck.GetId()] = itors
3406                torSizer.Add(torCheck,0,wx.ALIGN_CENTER_VERTICAL)
3407            resrbSizer.Add(torSizer)
3408            tchoice = ['None','Uiso','T','TL','TLS']
3409            thermSizer = wx.BoxSizer(wx.HORIZONTAL)
3410            thermSizer.Add(wx.StaticText(RigidBodies,-1,'Rigid body thermal motion model: '),0,wx.ALIGN_CENTER_VERTICAL)
3411            thermSel = wx.ComboBox(RigidBodies,-1,value=RBObj['ThermalMotion'][0],choices=tchoice,
3412                style=wx.CB_READONLY|wx.CB_DROPDOWN)
3413            Indx[thermSel.GetId()] = RBObj
3414            thermSel.Bind(wx.EVT_COMBOBOX,OnThermSel)
3415            thermSizer.Add(thermSel,0,wx.ALIGN_CENTER_VERTICAL)
3416            thermSizer.Add(wx.StaticText(RigidBodies,-1,' Units: T A^2, L deg^2, S deg-A'),0,wx.ALIGN_CENTER_VERTICAL)
3417            resrbSizer.Add(thermSizer)
3418            if RBObj['ThermalMotion'][0] != 'None':
3419                resrbSizer.Add(ThermDataSizer(RBObj,'Residue'))
3420            return resrbSizer
3421           
3422        def VecrbSizer(RBObj):
3423            G2frame.dataFrame.SetStatusText('NB: Rotation vector is in crystallographic space')
3424                   
3425            def OnDelVecRB(event):
3426                Obj = event.GetEventObject()
3427                RBId = Indx[Obj.GetId()]
3428                RBData['Vector'][RBId]['useCount'] -= 1               
3429                RBObjs = data['RBModels']['Vector']
3430                for rbObj in RBObjs:
3431                    if RBId == rbObj['RBId']:
3432                       data['RBModels']['Vector'].remove(rbObj)                 
3433                G2plt.PlotStructure(G2frame,data)
3434                wx.CallAfter(FillRigidBodyGrid,True)
3435             
3436            vecrbSizer = wx.BoxSizer(wx.VERTICAL)
3437            vecrbSizer.Add(wx.StaticText(RigidBodies,-1,120*'-'))
3438            topLine = wx.BoxSizer(wx.HORIZONTAL)
3439            topLine.Add(wx.StaticText(RigidBodies,-1,
3440                'Name: '+RBObj['RBname']+'   '),0,wx.ALIGN_CENTER_VERTICAL)
3441            rbId = RBObj['RBId']
3442            delRB = wx.CheckBox(RigidBodies,-1,'Delete?')
3443            delRB.Bind(wx.EVT_CHECKBOX,OnDelVecRB)
3444            Indx[delRB.GetId()] = rbId
3445            topLine.Add(delRB,0,wx.ALIGN_CENTER_VERTICAL)
3446            vecrbSizer.Add(topLine)
3447            vecrbSizer.Add(LocationSizer(RBObj,'Vector'))
3448            tchoice = ['None','Uiso','T','TL','TLS']
3449            thermSizer = wx.BoxSizer(wx.HORIZONTAL)
3450            thermSizer.Add(wx.StaticText(RigidBodies,-1,'Rigid body thermal motion model: '),0,wx.ALIGN_CENTER_VERTICAL)
3451            thermSel = wx.ComboBox(RigidBodies,-1,value=RBObj['ThermalMotion'][0],choices=tchoice,
3452                style=wx.CB_READONLY|wx.CB_DROPDOWN)
3453            Indx[thermSel.GetId()] = RBObj
3454            thermSel.Bind(wx.EVT_COMBOBOX,OnThermSel)
3455            thermSizer.Add(thermSel,0,wx.ALIGN_CENTER_VERTICAL)
3456            thermSizer.Add(wx.StaticText(RigidBodies,-1,' Units: T A^2, L deg^2, S deg-A'),0,wx.ALIGN_CENTER_VERTICAL)
3457            vecrbSizer.Add(thermSizer)
3458            if RBObj['ThermalMotion'][0] != 'None':
3459                vecrbSizer.Add(ThermDataSizer(RBObj,'Vector'))
3460            return vecrbSizer               
3461       
3462        # FillRigidBodyGrid executable code starts here
3463        if refresh:
3464            RigidBodies.DestroyChildren()
3465        AtLookUp = G2mth.FillAtomLookUp(data['Atoms'])
3466        general = data['General']
3467        cx = general['AtomPtrs'][0]
3468        Amat,Bmat = G2lat.cell2AB(general['Cell'][1:7])
3469        RBData = G2frame.PatternTree.GetItemPyData(   
3470            G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Rigid bodies'))
3471        Indx = {}
3472        atomStyle = 'balls & sticks'
3473        if 'macro' in general['Type']:
3474            atomStyle = 'sticks'
3475        G2frame.dataFrame.SetStatusText('')
3476        mainSizer = wx.BoxSizer(wx.VERTICAL)
3477        if not data['RBModels']:
3478            mainSizer.Add((5,5),0)
3479            mainSizer.Add(wx.StaticText(RigidBodies,-1,'No rigid body models:'),0,wx.ALIGN_CENTER_VERTICAL)
3480            mainSizer.Add((5,5),0)
3481        if 'Residue' in data['RBModels']:
3482            mainSizer.Add((5,5),0)
3483            mainSizer.Add(wx.StaticText(RigidBodies,-1,'Residue rigid bodies:'),0,wx.ALIGN_CENTER_VERTICAL)
3484            mainSizer.Add((5,5),0)
3485            for RBObj in data['RBModels']['Residue']:
3486                mainSizer.Add(ResrbSizer(RBObj))
3487        if 'Vector' in data['RBModels']:
3488            mainSizer.Add((5,5),0)
3489            mainSizer.Add(wx.StaticText(RigidBodies,-1,'Vector rigid bodies:'),0,wx.ALIGN_CENTER_VERTICAL)
3490            mainSizer.Add((5,5),0)
3491            for RBObj in data['RBModels']['Vector']:
3492                mainSizer.Add(VecrbSizer(RBObj))
3493
3494        SetPhaseWindow(G2frame.dataFrame,RigidBodies,mainSizer)
3495
3496    def OnRBCopyParms(event):
3497        RBObjs = []
3498        for rbType in ['Vector','Residue']:           
3499            RBObjs += data['RBModels'].get(rbType,[])
3500        if not len(RBObjs):
3501            print '**** ERROR - no rigid bodies defined ****'
3502            return
3503        if len(RBObjs) == 1:
3504            print '**** INFO - only one rigid body defined; nothing to copy to ****'
3505            return
3506        Source = []
3507        sourceRB = {}
3508        for RBObj in RBObjs:
3509            Source.append(RBObj['RBname'])
3510        dlg = wx.SingleChoiceDialog(G2frame,'Select source','Copy rigid body parameters',Source)
3511        if dlg.ShowModal() == wx.ID_OK:
3512            sel = dlg.GetSelection()
3513            name = Source[sel]
3514            for item in ['Orig','Orient','ThermalMotion']: 
3515                sourceRB.update({item:RBObjs[sel][item],})
3516        dlg.Destroy()
3517        if not sourceRB:
3518            return
3519        dlg = wx.MultiChoiceDialog(G2frame,'Select targets','Copy rigid body parameters',Source)
3520        if dlg.ShowModal() == wx.ID_OK:
3521            sel = dlg.GetSelections()
3522            for x in sel:
3523                RBObjs[x].update(copy.copy(sourceRB))
3524        G2plt.PlotStructure(G2frame,data)
3525        wx.CallAfter(FillRigidBodyGrid(True))
3526               
3527    def OnRBAssign(event):
3528       
3529        G2frame.dataFrame.SetStatusText('')
3530        RBData = G2frame.PatternTree.GetItemPyData(   
3531            G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Rigid bodies'))
3532        rbNames = {}
3533        for rbVec in RBData['Vector']:
3534            if rbVec != 'AtInfo':
3535                rbNames[RBData['Vector'][rbVec]['RBname']] =['Vector',rbVec]
3536        for rbRes in RBData['Residue']:
3537            if rbRes != 'AtInfo':
3538                rbNames[RBData['Residue'][rbRes]['RBname']] = ['Residue',rbRes]
3539        if not rbNames:
3540            print '**** ERROR - no rigid bodies defined ****'
3541            return
3542        general = data['General']
3543        Amat,Bmat = G2lat.cell2AB(general['Cell'][1:7])
3544        cx,ct = general['AtomPtrs'][:2]
3545        atomData = data['Atoms']
3546        Indx = {}
3547        atInd = [-1,-1,-1]
3548        data['testRBObj'] = {}
3549           
3550        def Draw():
3551           
3552            def OnOk(event):
3553                rbType = data['testRBObj']['rbType']
3554                RBObjs = data['RBModels'].get(rbType,[])
3555                rbObj = data['testRBObj']['rbObj']
3556                rbId = rbObj['RBId']
3557                newXYZ = G2mth.UpdateRBXYZ(Bmat,rbObj,RBData,rbType)[0]
3558                Ids = []
3559                dmax = 0.0
3560                oldXYZ = G2mth.getAtomXYZ(atomData,cx)
3561                for xyz in newXYZ:
3562                    dist = G2mth.GetXYZDist(xyz,oldXYZ,Amat)
3563                    dmax = max(dmax,np.min(dist))
3564                    id = np.argmin(dist)
3565                    Ids.append(atomData[id][-1])
3566                    atomData[id][cx:cx+3] = xyz
3567                if dmax > 1.0:
3568                    print '**** WARNING - some atoms not found or misidentified ****'
3569                    print '****           check torsion angles & try again      ****'
3570                    OkBtn.SetLabel('Not Ready')
3571                    OkBtn.Enable(False)
3572                    return
3573                rbObj['Ids'] = Ids
3574                rbObj['ThermalMotion'] = ['None',[0. for i in range(21)],[False for i in range(21)]] #type,values,flags
3575                rbObj['RBname'] += ':'+str(RBData[rbType][rbId]['useCount'])
3576                RBObjs.append(rbObj)
3577                data['RBModels'][rbType] = RBObjs
3578                RBData[rbType][rbId]['useCount'] += 1
3579                del data['testRBObj']
3580                G2plt.PlotStructure(G2frame,data)
3581                FillRigidBodyGrid(True)
3582               
3583            def OnCancel(event):
3584                del data['testRBObj']
3585                FillRigidBodyGrid(True)
3586               
3587            def OnRBSel(event):
3588                selection = rbSel.GetValue()
3589                rbType,rbId = rbNames[selection]
3590                data['testRBObj']['rbAtTypes'] = RBData[rbType][rbId]['rbTypes']
3591                data['testRBObj']['AtInfo'] = RBData[rbType]['AtInfo']
3592                data['testRBObj']['rbType'] = rbType
3593                data['testRBObj']['rbData'] = RBData
3594                data['testRBObj']['Sizers'] = {}
3595                rbRef = RBData[rbType][rbId]['rbRef']
3596                data['testRBObj']['rbRef'] = rbRef
3597                refType = []
3598                refName = []
3599                for ref in rbRef[:3]:
3600                    reftype = data['testRBObj']['rbAtTypes'][ref]
3601                    refType.append(reftype)
3602                    refName.append(reftype+' '+str(rbRef[0]))
3603                atNames,AtNames = fillAtNames(refType,atomData,ct)
3604                data['testRBObj']['atNames'] = atNames
3605                data['testRBObj']['AtNames'] = AtNames
3606                data['testRBObj']['rbObj'] = {'Orig':[[0,0,0],False],
3607                    'Orient':[[0.,0.,0.,1.],' '],'Ids':[],'RBId':rbId,'Torsions':[],
3608                    'numChain':'','RBname':RBData[rbType][rbId]['RBname']}
3609                data['testRBObj']['torAtms'] = []               
3610                for item in RBData[rbType][rbId].get('rbSeq',[]):
3611                    data['testRBObj']['rbObj']['Torsions'].append([item[2],False])
3612                    data['testRBObj']['torAtms'].append([-1,-1,-1])
3613                Draw()
3614               
3615            def fillAtNames(refType,atomData,ct):
3616                atNames = [{},{},{}]
3617                AtNames = {}
3618                for iatm,atom in enumerate(atomData):
3619                    AtNames[atom[ct-1]] = iatm
3620                    for i,reftype in enumerate(refType):
3621                        if atom[ct] == reftype:
3622                            atNames[i][atom[ct-1]] = iatm
3623                return atNames,AtNames
3624               
3625            def OnAtOrigPick(event):
3626                Obj = event.GetEventObject()
3627                item = Indx[Obj.GetId()]
3628                atName = Obj.GetValue()
3629                rbType = data['testRBObj']['rbType']
3630                atInd[0] = atNames[item][atName]
3631                if 'Vector' in rbType:
3632                    rbObj = data['testRBObj']['rbObj']
3633                    rbId = rbObj['RBId']
3634                    rbRef = data['testRBObj']['rbRef']
3635                    rbXYZ = -RBData[rbType][rbId]['rbXYZ']
3636                    nref = atNames[item][atName]
3637                    Oxyz = np.inner(Bmat,np.array(rbXYZ[rbRef[0]]))
3638                    Nxyz = np.array(atomData[nref][cx:cx+3])
3639                    Orig = Nxyz-Oxyz
3640                    data['testRBObj']['rbObj']['Orig'][0] = Orig   
3641                else:
3642                    Orig = atomData[atNames[item][atName]][cx:cx+3]
3643                    data['testRBObj']['rbObj']['Orig'][0] = Orig
3644                for x,item in zip(Orig,Xsizers):
3645                    item.SetLabel('%10.5f'%(x))
3646                G2plt.PlotStructure(G2frame,data)
3647               
3648            def OnAtQPick(event):
3649                Obj = event.GetEventObject()
3650                item = Indx[Obj.GetId()]
3651                atName = Obj.GetValue()
3652                atInd[item] = atNames[item][atName]
3653                if any([x<0 for x in atInd]):
3654                    return
3655                OkBtn.SetLabel('OK')
3656                OkBtn.Enable(True)
3657                rbType = data['testRBObj']['rbType']
3658                rbObj = data['testRBObj']['rbObj']
3659                rbId = rbObj['RBId']
3660                rbRef = data['testRBObj']['rbRef']
3661                rbXYZ = RBData[rbType][rbId]['rbXYZ']
3662                rbOrig = rbXYZ[rbRef[0]]
3663                VAR = rbXYZ[rbRef[1]]-rbOrig
3664                VBR = rbXYZ[rbRef[2]]-rbOrig
3665                if rbType == 'Vector':
3666                    Orig = np.array(atomData[atInd[0]][cx:cx+3])
3667                else:
3668                    Orig = np.array(data['testRBObj']['rbObj']['Orig'][0])               
3669                VAC = np.inner(Amat,np.array(atomData[atInd[1]][cx:cx+3])-Orig)
3670                VBC = np.inner(Amat,np.array(atomData[atInd[2]][cx:cx+3])-Orig)
3671                VCC = np.cross(VAR,VAC)
3672                QuatA = G2mth.makeQuat(VAR,VAC,VCC)[0]
3673                VAR = G2mth.prodQVQ(QuatA,VAR)
3674                VBR = G2mth.prodQVQ(QuatA,VBR)
3675                QuatB = G2mth.makeQuat(VBR,VBC,VAR)[0]
3676                QuatC = G2mth.prodQQ(QuatB,QuatA)
3677                data['testRBObj']['rbObj']['Orient'] = [QuatC,' ']
3678                for x,item in zip(QuatC,Osizers):
3679                    item.SetLabel('%10.4f'%(x))               
3680                if rbType == 'Vector':
3681                    Oxyz = np.inner(Bmat,G2mth.prodQVQ(QuatC,rbOrig))
3682                    Nxyz = np.array(atomData[atInd[0]][cx:cx+3])
3683                    Orig = Nxyz-Oxyz
3684                    data['testRBObj']['rbObj']['Orig'][0] = Orig
3685                    for x,item in zip(Orig,Xsizers):
3686                        item.SetLabel('%10.5f'%(x))
3687                G2plt.PlotStructure(G2frame,data)
3688               
3689            def OnTorAngle(event):
3690                OkBtn.SetLabel('OK')
3691                OkBtn.Enable(True)
3692                Obj = event.GetEventObject()
3693                [tor,torSlide] = Indx[Obj.GetId()]
3694                Tors = data['testRBObj']['rbObj']['Torsions'][tor]
3695                try:
3696                    value = float(Obj.GetValue())
3697                except ValueError:
3698                    value = Tors[0]
3699                Tors[0] = value
3700                Obj.SetValue('%8.3f'%(value))
3701                torSlide.SetValue(int(value*10))
3702                G2plt.PlotStructure(G2frame,data)
3703               
3704            def OnTorSlide(event):
3705                OkBtn.SetLabel('OK')
3706                OkBtn.Enable(True)
3707                Obj = event.GetEventObject()
3708                tor,ang = Indx[Obj.GetId()]
3709                Tors = data['testRBObj']['rbObj']['Torsions'][tor]
3710                val = float(Obj.GetValue())/10.
3711                Tors[0] = val
3712                ang.SetValue('%8.3f'%(val))
3713                G2plt.PlotStructure(G2frame,data)
3714
3715            if len(data['testRBObj']):
3716                G2plt.PlotStructure(G2frame,data)
3717                   
3718            RigidBodies.DestroyChildren()
3719            mainSizer = wx.BoxSizer(wx.VERTICAL)
3720            mainSizer.Add((5,5),0)
3721            if data['testRBObj']:
3722                Xsizers = []
3723                Osizers = []
3724                rbObj = data['testRBObj']['rbObj']
3725                rbName = rbObj['RBname']
3726                rbId = rbObj['RBId']
3727                Orig = rbObj['Orig'][0]
3728                Orien = rbObj['Orient'][0]
3729                rbRef = data['testRBObj']['rbRef']
3730                Torsions = rbObj['Torsions']
3731                refName = []
3732                for ref in rbRef:
3733                    refName.append(data['testRBObj']['rbAtTypes'][ref]+str(ref))
3734                atNames = data['testRBObj']['atNames']
3735                mainSizer.Add(wx.StaticText(RigidBodies,-1,'Locate rigid body : '+rbName),
3736                    0,wx.ALIGN_CENTER_VERTICAL)
3737                mainSizer.Add((5,5),0)
3738                OriSizer = wx.FlexGridSizer(1,5,5,5)
3739                OriSizer.Add(wx.StaticText(RigidBodies,-1,'Origin x,y,z: '),0,wx.ALIGN_CENTER_VERTICAL)
3740                for ix,x in enumerate(Orig):
3741                    origX = wx.StaticText(RigidBodies,-1,'%10.5f'%(x))
3742                    OriSizer.Add(origX,0,wx.ALIGN_CENTER_VERTICAL)
3743                    Xsizers.append(origX)
3744                OriSizer.Add((5,0),)
3745                if len(atomData):
3746                    choice = atNames[0].keys()
3747                    choice.sort()
3748                    data['testRBObj']['Sizers']['Xsizers'] = Xsizers
3749                OriSizer.Add(wx.StaticText(RigidBodies,-1,'Orientation quaternion: '),0,wx.ALIGN_CENTER_VERTICAL)
3750                for ix,x in enumerate(Orien):
3751                    orien = wx.StaticText(RigidBodies,-1,'%10.4f'%(x))
3752                    OriSizer.Add(orien,0,wx.ALIGN_CENTER_VERTICAL)
3753                    Osizers.append(orien)
3754                data['testRBObj']['Sizers']['Osizers'] = Osizers
3755                mainSizer.Add(OriSizer)
3756                mainSizer.Add((5,5),0)
3757                RefSizer = wx.FlexGridSizer(1,7,5,5)
3758                if len(atomData):
3759                    RefSizer.Add(wx.StaticText(RigidBodies,-1,'Location setting: Select match to'),0,wx.ALIGN_CENTER_VERTICAL)
3760                    for i in [0,1,2]:
3761                        choice = ['',]+atNames[i].keys()
3762                        choice.sort()
3763                        RefSizer.Add(wx.StaticText(RigidBodies,-1,' '+refName[i]+': '),0,wx.ALIGN_CENTER_VERTICAL)
3764                        atPick = wx.ComboBox(RigidBodies,-1,value='',
3765                            choices=choice[1:],style=wx.CB_READONLY|wx.CB_DROPDOWN)
3766                        if i:
3767                            atPick.Bind(wx.EVT_COMBOBOX, OnAtQPick)
3768                        else:
3769                            atPick.Bind(wx.EVT_COMBOBOX, OnAtOrigPick)                           
3770                        Indx[atPick.GetId()] = i
3771                        RefSizer.Add(atPick,0,wx.ALIGN_CENTER_VERTICAL)
3772                mainSizer.Add(RefSizer)
3773                mainSizer.Add((5,5),0)
3774                if Torsions:                   
3775                    AtNames = data['testRBObj']['AtNames']
3776                    rbAtTypes = data['testRBObj']['rbAtTypes']
3777                    rbSeq = RBData['Residue'][rbId]['rbSeq']
3778                    TorSizer = wx.FlexGridSizer(1,4)
3779                    TorSizer.AddGrowableCol(1,1)
3780                    for t,[torsion,seq] in enumerate(zip(Torsions,rbSeq)):
3781                        torName = ''
3782                        for item in [seq[0],seq[1],seq[3][0]]:
3783                            torName += data['testRBObj']['rbAtTypes'][item]+str(item)+' '
3784                        TorSizer.Add(wx.StaticText(RigidBodies,-1,'Side chain torsion for rb seq: '+torName),0,wx.ALIGN_CENTER_VERTICAL)
3785                        torSlide = wx.Slider(RigidBodies,style=wx.SL_HORIZONTAL)
3786                        torSlide.SetRange(0,3600)
3787                        torSlide.SetValue(int(torsion[0]*10.))
3788                        torSlide.Bind(wx.EVT_SLIDER, OnTorSlide)
3789                        TorSizer.Add(torSlide,1,wx.EXPAND|wx.RIGHT)
3790                        TorSizer.Add(wx.StaticText(RigidBodies,-1,' Angle: '),0,wx.ALIGN_CENTER_VERTICAL)
3791                        ang = wx.TextCtrl(RigidBodies,-1,value='%8.3f'%(torsion[0]),style=wx.TE_PROCESS_ENTER)
3792                        ang.Bind(wx.EVT_TEXT_ENTER,OnTorAngle)
3793                        ang.Bind(wx.EVT_KILL_FOCUS,OnTorAngle)
3794                        Indx[torSlide.GetId()] = [t,ang]
3795                        Indx[ang.GetId()] = [t,torSlide]
3796                        TorSizer.Add(ang,0,wx.ALIGN_CENTER_VERTICAL)                           
3797                    mainSizer.Add(TorSizer,1,wx.EXPAND|wx.RIGHT)
3798                else:
3799                    mainSizer.Add(wx.StaticText(RigidBodies,-1,'No side chain torsions'),0,wx.ALIGN_CENTER_VERTICAL)
3800            else:
3801                mainSizer.Add(wx.StaticText(RigidBodies,-1,'Assign rigid body:'),0,wx.ALIGN_CENTER_VERTICAL)
3802                mainSizer.Add((5,5),0)
3803                topSizer = wx.BoxSizer(wx.HORIZONTAL)
3804                topSizer.Add(wx.StaticText(RigidBodies,-1,'Select rigid body model'),0,wx.ALIGN_CENTER_VERTICAL)
3805                rbSel = wx.ComboBox(RigidBodies,-1,value='',choices=rbNames.keys(),
3806                    style=wx.CB_READONLY|wx.CB_DROPDOWN)
3807                rbSel.Bind(wx.EVT_COMBOBOX, OnRBSel)
3808                topSizer.Add((5,5),0)
3809                topSizer.Add(rbSel,0,wx.ALIGN_CENTER_VERTICAL)
3810                mainSizer.Add(topSizer)               
3811               
3812            OkBtn = wx.Button(RigidBodies,-1,"Not ready")
3813            OkBtn.Bind(wx.EVT_BUTTON, OnOk)
3814            OkBtn.Enable(False)
3815            CancelBtn = wx.Button(RigidBodies,-1,'Cancel')
3816            CancelBtn.Bind(wx.EVT_BUTTON, OnCancel)
3817            btnSizer = wx.BoxSizer(wx.HORIZONTAL)
3818            btnSizer.Add((20,20),1)
3819            btnSizer.Add(OkBtn)
3820            btnSizer.Add(CancelBtn)
3821            btnSizer.Add((20,20),1)
3822            mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
3823            SetPhaseWindow(G2frame.dataFrame,RigidBodies,mainSizer)
3824        Draw()
3825       
3826    def OnAutoFindResRB(event):
3827        RBData = G2frame.PatternTree.GetItemPyData(   
3828            G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Rigid bodies'))
3829        rbKeys = RBData['Residue'].keys()
3830        rbKeys.remove('AtInfo')
3831        if not len(rbKeys):
3832            print '**** ERROR - no residue rigid bodies are defined ****'
3833            return
3834        RBNames = [RBData['Residue'][k]['RBname'] for k in rbKeys]
3835        RBIds = dict(zip(RBNames,rbKeys))
3836        general = data['General']
3837        Amat,Bmat = G2lat.cell2AB(general['Cell'][1:7])
3838        Atoms = data['Atoms']
3839        AtLookUp = G2mth.FillAtomLookUp(Atoms)
3840        if 'macro' not in general['Type']:
3841            print '**** ERROR - this phase is not a macromolecule ****'
3842            return
3843        if not len(Atoms):
3844            print '**** ERROR - this phase has no atoms ****'
3845            return
3846        RBObjs = []
3847        cx,ct = general['AtomPtrs'][:2]
3848        iatm = 0
3849        wx.BeginBusyCursor()
3850        try:
3851            while iatm < len(Atoms):
3852                atom = Atoms[iatm]
3853                res = atom[1].strip()
3854                numChain = ' %s %s'%(atom[0],atom[2])
3855                if res not in RBIds or atom[ct-1] == 'OXT':
3856                    iatm += 1
3857                    continue        #skip for OXT, water molecules, etc.
3858                rbRes = RBData['Residue'][RBIds[res]]
3859                rbRef = rbRes['rbRef']
3860                VAR = rbRes['rbXYZ'][rbRef[1]]-rbRes['rbXYZ'][rbRef[0]]
3861                VBR = rbRes['rbXYZ'][rbRef[2]]-rbRes['rbXYZ'][rbRef[0]]
3862                rbObj = {'RBname':rbRes['RBname']+':'+str(rbRes['useCount']),'numChain':numChain}
3863                rbAtoms = []
3864                rbIds = []
3865                for iratm in range(len(rbRes['atNames'])):
3866                    rbAtoms.append(np.array(Atoms[iatm][cx:cx+3]))
3867                    rbIds.append(Atoms[iatm][20])
3868                    iatm += 1    #puts this at beginning of next residue?
3869                Orig = rbAtoms[rbRef[0]]
3870                rbObj['RBId'] = RBIds[res]
3871                rbObj['Ids'] = rbIds
3872                rbObj['Orig'] = [Orig,False]
3873#                print ' residue '+rbRes['RBname']+str(atom[0]).strip()+ \
3874#                    ' origin at: ','%.5f %.5f %.5f'%(Orig[0],Orig[1],Orig[2])
3875                VAC = np.inner(Amat,rbAtoms[rbRef[1]]-Orig)
3876                VBC = np.inner(Amat,rbAtoms[rbRef[2]]-Orig)
3877                VCC = np.cross(VAR,VAC)
3878                QuatA = G2mth.makeQuat(VAR,VAC,VCC)[0]
3879                VAR = G2mth.prodQVQ(QuatA,VAR)
3880                VBR = G2mth.prodQVQ(QuatA,VBR)
3881                QuatB = G2mth.makeQuat(VBR,VBC,VAR)[0]
3882                QuatC = G2mth.prodQQ(QuatB,QuatA)
3883                rbObj['Orient'] = [QuatC,' ']
3884                rbObj['ThermalMotion'] = ['None',[0. for i in range(21)],[False for i in range(21)]] #type,values,flags
3885                SXYZ = []
3886                TXYZ = []
3887                rbObj['Torsions'] = []
3888                for i,xyz in enumerate(rbRes['rbXYZ']):
3889                    SXYZ.append(G2mth.prodQVQ(QuatC,xyz))               
3890                    TXYZ.append(np.inner(Amat,rbAtoms[i]-Orig))
3891                for Oatm,Patm,x,Riders in rbRes['rbSeq']:
3892                    VBR = SXYZ[Oatm]-SXYZ[Patm]
3893                    VAR = SXYZ[Riders[0]]-SXYZ[Patm]
3894                    VAC = TXYZ[Riders[0]]-TXYZ[Patm]
3895                    QuatA,D = G2mth.makeQuat(VAR,VAC,VBR)
3896                    ang = 180.*D/np.pi
3897                    rbObj['Torsions'].append([ang,False])
3898                    for ride in Riders:
3899                        SXYZ[ride] = G2mth.prodQVQ(QuatA,SXYZ[ride]-SXYZ[Patm])+SXYZ[Patm]
3900                rbRes['useCount'] += 1
3901                RBObjs.append(rbObj)
3902            data['RBModels']['Residue'] = RBObjs
3903            for RBObj in RBObjs:
3904                newXYZ = G2mth.UpdateRBXYZ(Bmat,RBObj,RBData,'Residue')[0]
3905                for i,id in enumerate(RBObj['Ids']):
3906                    data['Atoms'][AtLookUp[id]][cx:cx+3] = newXYZ[i]
3907        finally:
3908            wx.EndBusyCursor()
3909        wx.CallAfter(FillRigidBodyGrid,True)
3910       
3911    def OnRBRemoveAll(event):
3912        data['RBModels']['Residue'] = []
3913        data['RBModels']['Vector'] = []
3914        RBData = G2frame.PatternTree.GetItemPyData(   
3915            G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Rigid bodies'))
3916        for RBType in ['Vector','Residue']:
3917            for rbId in RBData[RBType]:
3918                RBData[RBType][rbId]['useCount'] = 0       
3919        FillRigidBodyGrid(True)
3920       
3921    def OnGlobalResRBTherm(event):
3922        AtLookUp = G2mth.FillAtomLookUp(data['Atoms'])
3923        RBObjs = data['RBModels']['Residue']
3924        names = ['None','Uiso','T','TL','TLS']
3925        cia = data['General']['AtomPtrs'][3]
3926        dlg = wx.SingleChoiceDialog(G2frame,'Select','Residue thermal motion model',names)
3927        if dlg.ShowModal() == wx.ID_OK:
3928            sel = dlg.GetSelection()
3929            parm = names[sel]
3930            Ttype = 'A'
3931            if parm == 'Uiso':
3932                Ttype = 'I'       
3933            for rbObj in RBObjs:
3934                rbObj['ThermalMotion'][0] = parm
3935                if parm != 'None':
3936                    for i,id in enumerate(rbObj['Ids']):
3937                        data['Atoms'][AtLookUp[id]][cia] = Ttype
3938        dlg.Destroy()
3939        wx.CallAfter(FillRigidBodyGrid,True)
3940
3941    def OnGlobalResRBRef(event):
3942        RBObjs = data['RBModels']['Residue']
3943        names = ['Origin','Orient. angle','Full Orient.']
3944        nTor = 0
3945        for rbObj in RBObjs:
3946            nTor = max(nTor,len(rbObj['Torsions']))
3947        names += ['Torsion '+str(i) for i in range(nTor)]
3948        if np.any([rbObj['ThermalMotion'][0] == 'Uiso' for rbObj in RBObjs]):
3949           names += ['Uiso',]
3950        if np.any([rbObj['ThermalMotion'][0] == 'TLS' for rbObj in RBObjs]):
3951           names += ['Tii','Tij','Lii','Lij','Sij']
3952        elif np.any([rbObj['ThermalMotion'][0] == 'TL' for rbObj in RBObjs]):
3953           names += ['Tii','Tij','Lii','Lij']
3954        elif np.any([rbObj['ThermalMotion'][0] == 'T' for rbObj in RBObjs]):
3955           names += ['Tii','Tij']
3956
3957        dlg = wx.MultiChoiceDialog(G2frame,'Select','Refinement controls',names)
3958        if dlg.ShowModal() == wx.ID_OK:
3959            sel = dlg.GetSelections()
3960            parms = []
3961            for x in sel:
3962                parms.append(names[x])
3963            wx.BeginBusyCursor()
3964            try:
3965                for rbObj in RBObjs:
3966                    if 'Origin' in parms:
3967                        rbObj['Orig'][1] = True
3968                    else:
3969                        rbObj['Orig'][1] = False
3970                    if 'Full Orient.' in parms:
3971                        rbObj['Orient'][1] = 'AV'
3972                    elif 'Orient. angle' in parms:
3973                        rbObj['Orient'][1] = 'A'
3974                    else:
3975                        rbObj['Orient'][1] = ' '
3976                    for i in range(len(rbObj['Torsions'])):
3977                        if 'Torsion '+str(i) in parms:
3978                            rbObj['Torsions'][i][1] = True
3979                        else:
3980                            rbObj['Torsions'][i][1] = False
3981                    if rbObj['ThermalMotion'][0] == 'Uiso':
3982                        if 'Uiso' in parms:
3983                           rbObj['ThermalMotion'][2][0] = True
3984                        else:
3985                           rbObj['ThermalMotion'][2][0] = False
3986                    elif 'T' in rbObj['ThermalMotion'][0]:
3987                        if 'Tii' in parms:
3988                            rbObj['ThermalMotion'][2][0:2] = [True,True,True]
3989                        else:
3990                            rbObj['ThermalMotion'][2][0:2] = [False,False,False]
3991                        if 'Tij' in parms:
3992                            rbObj['ThermalMotion'][2][3:6] = [True,True,True]
3993                        else:
3994                            rbObj['ThermalMotion'][2][3:6] = [False,False,False]
3995                    elif 'L' in rbObj['ThermalMotion'][0]:
3996                        if 'Lii' in parms:
3997                            rbObj['ThermalMotion'][2][6:9] = [True,True,True]
3998                        else:
3999                            rbObj['ThermalMotion'][2][6:9] = [False,False,False]
4000                        if 'Lij' in parms:
4001                            rbObj['ThermalMotion'][2][9:12] = [True,True,True]
4002                        else:
4003                            rbObj['ThermalMotion'][2][9:12] = [False,False,False]
4004                    elif 'S' in rbObj['ThermalMotion'][0]:
4005                        if 'Sij' in parms:
4006                            rbObj['ThermalMotion'][2][12:20] = [True,True,True,True,True,True,True,True]
4007                        else:
4008                            rbObj['ThermalMotion'][2][12:20] = [False,False,False,False,False,False,False,False]
4009            finally:
4010                wx.EndBusyCursor()
4011            FillRigidBodyGrid()
4012           
4013################################################################################
4014##### MC/SA routines
4015################################################################################
4016
4017    def UpdateMCSA(Scroll=0):
4018        Indx = {}
4019       
4020        def OnPosRef(event):
4021            Obj = event.GetEventObject()
4022            model,item,ix = Indx[Obj.GetId()]
4023            model[item][1][ix] = Obj.GetValue()
4024           
4025        def OnPosVal(event):
4026            Obj = event.GetEventObject()
4027            model,item,ix = Indx[Obj.GetId()]
4028            try:
4029                model[item][0][ix] = float(Obj.GetValue())
4030            except ValueError:
4031                pass
4032            Obj.SetValue("%.4f"%(model[item][0][ix]))
4033            G2plt.PlotStructure(G2frame,data)
4034           
4035        def OnPosRange(event):
4036            Obj = event.GetEventObject()
4037            model,item,ix = Indx[Obj.GetId()]
4038            Range = Obj.GetValue().split()
4039            try:
4040                rmin,rmax = [float(Range[i]) for i in range(2)]
4041                if rmin >= rmax:
4042                    raise ValueError
4043            except (ValueError,IndexError):
4044                rmin,rmax = model[item][2][ix]
4045            model[item][2][ix] = [rmin,rmax]
4046            Obj.SetValue('%.3f %.3f'%(rmin,rmax))                 
4047               
4048        def atomSizer(model):
4049           
4050            atomsizer = wx.FlexGridSizer(1,7,5,5)
4051            atomsizer.Add(wx.StaticText(MCSA,-1,' Atom: '+model['name']+': '),0,wx.ALIGN_CENTER_VERTICAL)
4052            for ix,item in enumerate(['x','y','z']):
4053                posRef = wx.CheckBox(MCSA,-1,label=item+': ')
4054                posRef.SetValue(model['Pos'][1][ix])
4055                posRef.Bind(wx.EVT_CHECKBOX,OnPosRef)
4056                Indx[posRef.GetId()] = [model,'Pos',ix]
4057                atomsizer.Add(posRef,0,wx.ALIGN_CENTER_VERTICAL)
4058                posVal = wx.TextCtrl(MCSA,-1,'%.4f'%(model['Pos'][0][ix]),style=wx.TE_PROCESS_ENTER)
4059                posVal.Bind(wx.EVT_TEXT_ENTER,OnPosVal)
4060                posVal.Bind(wx.EVT_KILL_FOCUS,OnPosVal)
4061                Indx[posVal.GetId()] = [model,'Pos',ix]
4062                atomsizer.Add(posVal,0,wx.ALIGN_CENTER_VERTICAL)
4063            atomsizer.Add((5,5),0)
4064            for ix,item in enumerate(['x','y','z']):
4065                atomsizer.Add(wx.StaticText(MCSA,-1,' Range: '),0,wx.ALIGN_CENTER_VERTICAL)
4066                rmin,rmax = model['Pos'][2][ix]
4067                posRange = wx.TextCtrl(MCSA,-1,'%.3f %.3f'%(rmin,rmax),style=wx.TE_PROCESS_ENTER)
4068                Indx[posRange.GetId()] = [model,'Pos',ix]
4069                posRange.Bind(wx.EVT_TEXT_ENTER,OnPosRange)
4070                posRange.Bind(wx.EVT_KILL_FOCUS,OnPosRange)
4071                atomsizer.Add(posRange,0,wx.ALIGN_CENTER_VERTICAL)
4072            return atomsizer
4073           
4074        def rbSizer(model):
4075           
4076            def OnOrVar(event):
4077                Obj = event.GetEventObject()
4078                model = Indx[Obj.GetId()]
4079                model['Ovar'] = Obj.GetValue()
4080           
4081            def OnOriVal(event):
4082                Obj = event.GetEventObject()
4083                model,ix,ObjA,ObjV = Indx[Obj.GetId()]
4084                A = model['Ori'][0][0]
4085                V = model['Ori'][0][1:]
4086                if ix:
4087                    Anew = A
4088                    Vec = ObjV.GetValue().split()
4089                    try:
4090                        Vnew = [float(Vec[i]) for i in range(3)]
4091                    except ValueError:
4092                        Vnew = V
4093                else:
4094                    Vnew = V
4095                    try:
4096                        Anew = float(ObjA.GetValue())
4097                        if not Anew:    #==0.0!
4098                            Anew = 360.
4099                    except ValueError:
4100                        Anew = A
4101                Q = G2mth.AVdeg2Q(Anew,Vnew)
4102                A,V = G2mth.Q2AVdeg(Q)
4103                model['Ori'][0][0] = A
4104                model['Ori'][0][1:] = V
4105                if ix:
4106                    ObjV.SetValue('%.3f %.3f %.3f'%(V[0],V[1],V[2]))
4107                else:
4108                    ObjA.SetValue('%.5f'%(A))
4109                    ObjV.SetValue('%.3f %.3f %.3f'%(V[0],V[1],V[2]))
4110                G2plt.PlotStructure(G2frame,data)
4111#                UpdateMCSA()
4112
4113            def OnMolCent(event):
4114                Obj = event.GetEventObject()
4115                model = Indx[Obj.GetId()]
4116                model['MolCent'][1] = Obj.GetValue()
4117                if model['MolCent'][1]:
4118                    G2mth.SetMolCent(model,RBData)               
4119                G2plt.PlotStructure(G2frame,data)
4120           
4121            rbsizer = wx.BoxSizer(wx.VERTICAL)
4122            rbsizer1 = wx.FlexGridSizer(1,7,5,5)
4123            rbsizer1.Add(wx.StaticText(MCSA,-1,model['Type']+': '+model['name']+': '),0,wx.ALIGN_CENTER_VERTICAL)
4124            for ix,item in enumerate(['x','y','z']):
4125                posRef = wx.CheckBox(MCSA,-1,label=item+': ')
4126                posRef.SetValue(model['Pos'][1][ix])
4127                posRef.Bind(wx.EVT_CHECKBOX,OnPosRef)
4128                Indx[posRef.GetId()] = [model,'Pos',ix]
4129                rbsizer1.Add(posRef,0,wx.ALIGN_CENTER_VERTICAL)
4130                posVal = wx.TextCtrl(MCSA,-1,'%.4f'%(model['Pos'][0][ix]),style=wx.TE_PROCESS_ENTER)
4131                posVal.Bind(wx.EVT_TEXT_ENTER,OnPosVal)
4132                posVal.Bind(wx.EVT_KILL_FOCUS,OnPosVal)
4133                Indx[posVal.GetId()] = [model,'Pos',ix]
4134                rbsizer1.Add(posVal,0,wx.ALIGN_CENTER_VERTICAL)
4135            molcent = wx.CheckBox(MCSA,-1,label=' Use mol. center? ')
4136            molcent.SetValue(model['MolCent'][1])
4137            molcent.Bind(wx.EVT_CHECKBOX,OnMolCent)
4138            Indx[molcent.GetId()] = model
4139            rbsizer1.Add(molcent,0,wx.ALIGN_CENTER_VERTICAL)
4140            for ix,item in enumerate(['x','y','z']):
4141                rbsizer1.Add(wx.StaticText(MCSA,-1,' Range: '),0,wx.ALIGN_CENTER_VERTICAL)
4142                rmin,rmax = model['Pos'][2][ix]
4143                posRange = wx.TextCtrl(MCSA,-1,'%.3f %.3f'%(rmin,rmax),style=wx.TE_PROCESS_ENTER)
4144                Indx[posRange.GetId()] = [model,'Pos',ix]
4145                posRange.Bind(wx.EVT_TEXT_ENTER,OnPosRange)
4146                posRange.Bind(wx.EVT_KILL_FOCUS,OnPosRange)
4147                rbsizer1.Add(posRange,0,wx.ALIGN_CENTER_VERTICAL)
4148               
4149            rbsizer2 = wx.FlexGridSizer(1,6,5,5)
4150            Ori = model['Ori'][0]
4151            rbsizer2.Add(wx.StaticText(MCSA,-1,'Oa: '),0,wx.ALIGN_CENTER_VERTICAL)
4152            angVal = wx.TextCtrl(MCSA,-1,'%.5f'%(Ori[0]),style=wx.TE_PROCESS_ENTER)
4153            angVal.Bind(wx.EVT_TEXT_ENTER,OnOriVal)
4154            angVal.Bind(wx.EVT_KILL_FOCUS,OnOriVal)
4155            rbsizer2.Add(angVal,0,wx.ALIGN_CENTER_VERTICAL)
4156            rbsizer2.Add(wx.StaticText(MCSA,-1,'Oi,Oj,Ok: '),0,wx.ALIGN_CENTER_VERTICAL)
4157            vecVal = wx.TextCtrl(MCSA,-1,'%.3f %.3f %.3f'%(Ori[1],Ori[2],Ori[3]),style=wx.TE_PROCESS_ENTER)
4158            vecVal.Bind(wx.EVT_TEXT_ENTER,OnOriVal)
4159            vecVal.Bind(wx.EVT_KILL_FOCUS,OnOriVal)
4160            Indx[angVal.GetId()] = [model,0,angVal,vecVal]
4161            Indx[vecVal.GetId()] = [model,1,angVal,vecVal]
4162            rbsizer2.Add(vecVal,0,wx.ALIGN_CENTER_VERTICAL)
4163            rbsizer2.Add(wx.StaticText(MCSA,-1,' Vary? '),0,wx.ALIGN_CENTER_VERTICAL)
4164            choice = [' ','A','AV']
4165            orvar = wx.ComboBox(MCSA,-1,value=model['Ovar'],choices=choice,
4166                style=wx.CB_READONLY|wx.CB_DROPDOWN)
4167            orvar.Bind(wx.EVT_COMBOBOX, OnOrVar)
4168            Indx[orvar.GetId()] = model
4169            rbsizer2.Add(orvar,0,wx.ALIGN_CENTER_VERTICAL)
4170            rbsizer2.Add(wx.StaticText(MCSA,-1,' Range: Oa: '),0,wx.ALIGN_CENTER_VERTICAL)
4171            Rge = model['Ori'][2]
4172            angRange = wx.TextCtrl(MCSA,-1,'%.3f %.3f'%(Rge[0][0],Rge[0][1]),style=wx.TE_PROCESS_ENTER)
4173            Indx[angRange.GetId()] = [model,'Ori',0]
4174            angRange.Bind(wx.EVT_TEXT_ENTER,OnPosRange)
4175            angRange.Bind(wx.EVT_KILL_FOCUS,OnPosRange)
4176            rbsizer2.Add(angRange,0,wx.ALIGN_CENTER_VERTICAL)
4177            rbsizer2.Add(wx.StaticText(MCSA,-1,'Oi,Oj,Ok: '),0,wx.ALIGN_CENTER_VERTICAL)
4178            for io,item in enumerate(['Oi','Oj','Ok']):
4179                rmin,rmax = Rge[io+1]
4180                vecRange = wx.TextCtrl(MCSA,-1,'%.3f %.3f '%(rmin,rmax),style=wx.TE_PROCESS_ENTER)
4181                Indx[vecRange.GetId()] = [model,'Ori',io+1]
4182                vecRange.Bind(wx.EVT_TEXT_ENTER,OnPosRange)
4183                vecRange.Bind(wx.EVT_KILL_FOCUS,OnPosRange)
4184                rbsizer2.Add(vecRange,0,wx.ALIGN_CENTER_VERTICAL)
4185            rbsizer.Add(rbsizer1)   
4186            rbsizer.Add(rbsizer2)   
4187            if model['Type'] == 'Residue':
4188                atNames = RBData['Residue'][model['RBId']]['atNames']
4189                rbsizer.Add(wx.StaticText(MCSA,-1,'Torsions:'),0,wx.ALIGN_CENTER_VERTICAL)
4190                rbsizer3 = wx.FlexGridSizer(1,8,5,5)
4191                for it,tor in enumerate(model['Tor'][0]):
4192                    iBeg,iFin = RBData['Residue'][model['RBId']]['rbSeq'][it][:2]
4193                    name = atNames[iBeg]+'-'+atNames[iFin]
4194                    torRef = wx.CheckBox(MCSA,-1,label=' %s: '%(name))
4195                    torRef.SetValue(model['Tor'][1][it])
4196                    torRef.Bind(wx.EVT_CHECKBOX,OnPosRef)
4197                    Indx[torRef.GetId()] = [model,'Tor',it]
4198                    rbsizer3.Add(torRef,0,wx.ALIGN_CENTER_VERTICAL)
4199                    torVal = wx.TextCtrl(MCSA,-1,'%.4f'%(tor),style=wx.TE_PROCESS_ENTER)
4200                    torVal.Bind(wx.EVT_TEXT_ENTER,OnPosVal)
4201                    torVal.Bind(wx.EVT_KILL_FOCUS,OnPosVal)
4202                    Indx[torVal.GetId()] = [model,'Tor',it]
4203                    rbsizer3.Add(torVal,0,wx.ALIGN_CENTER_VERTICAL)
4204                    rbsizer3.Add(wx.StaticText(MCSA,-1,' Range: '),0,wx.ALIGN_CENTER_VERTICAL)
4205                    rmin,rmax = model['Tor'][2][it]
4206                    torRange = wx.TextCtrl(MCSA,-1,'%.3f %.3f'%(rmin,rmax),style=wx.TE_PROCESS_ENTER)
4207                    Indx[torRange.GetId()] = [model,'Tor',it]
4208                    torRange.Bind(wx.EVT_TEXT_ENTER,OnPosRange)
4209                    torRange.Bind(wx.EVT_KILL_FOCUS,OnPosRange)
4210                    rbsizer3.Add(torRange,0,wx.ALIGN_CENTER_VERTICAL)
4211                rbsizer.Add(rbsizer3)
4212               
4213            return rbsizer
4214           
4215        def MDSizer(POData):
4216           
4217            def OnPORef(event):
4218                POData['Coef'][1] = poRef.GetValue()
4219               
4220            def OnPOVal(event):
4221                try:
4222                    mdVal = float(poVal.GetValue())
4223                    if mdVal > 0:
4224                        POData['Coef'][0] = mdVal
4225                except ValueError:
4226                    pass
4227                poVal.SetValue("%.3f"%(POData['Coef'][0]))
4228               
4229            def OnPORange(event):
4230                Range = poRange.GetValue().split()
4231                try:
4232                    rmin,rmax = [float(Range[i]) for i in range(2)]
4233                    if 0. < rmin < rmax:
4234                        pass
4235                    else:
4236                        raise ValueError
4237                except (ValueError,IndexError):
4238                    rmin,rmax = POData['Coef'][2]
4239                POData['Coef'][2] = [rmin,rmax]
4240                poRange.SetValue('%.3f %.3f'%(rmin,rmax))                 
4241               
4242            def OnPOAxis(event):
4243                Saxis = poAxis.GetValue().split()
4244                try:
4245                    hkl = [int(Saxis[i]) for i in range(3)]
4246                except (ValueError,IndexError):
4247                    hkl = POData['axis']
4248                if not np.any(np.array(hkl)):
4249                    hkl = POData['axis']
4250                POData['axis'] = hkl
4251                h,k,l = hkl
4252                poAxis.SetValue('%3d %3d %3d'%(h,k,l))                 
4253               
4254            poSizer = wx.BoxSizer(wx.HORIZONTAL)
4255            poRef = wx.CheckBox(MCSA,-1,label=' March-Dollase ratio: ')
4256            poRef.SetValue(POData['Coef'][1])
4257            poRef.Bind(wx.EVT_CHECKBOX,OnPORef)
4258            poSizer.Add(poRef,0,wx.ALIGN_CENTER_VERTICAL)
4259            poVal = wx.TextCtrl(MCSA,-1,'%.3f'%(POData['Coef'][0]),style=wx.TE_PROCESS_ENTER)
4260            poVal.Bind(wx.EVT_TEXT_ENTER,OnPOVal)
4261            poVal.Bind(wx.EVT_KILL_FOCUS,OnPOVal)
4262            poSizer.Add(poVal,0,wx.ALIGN_CENTER_VERTICAL)
4263            poSizer.Add(wx.StaticText(MCSA,-1,' Range: '),0,wx.ALIGN_CENTER_VERTICAL)
4264            rmin,rmax = POData['Coef'][2]
4265            poRange = wx.TextCtrl(MCSA,-1,'%.3f %.3f'%(rmin,rmax),style=wx.TE_PROCESS_ENTER)
4266            poRange.Bind(wx.EVT_TEXT_ENTER,OnPORange)
4267            poRange.Bind(wx.EVT_KILL_FOCUS,OnPORange)
4268            poSizer.Add(poRange,0,wx.ALIGN_CENTER_VERTICAL)                       
4269            poSizer.Add(wx.StaticText(MCSA,-1,' Unique axis, H K L: '),0,wx.ALIGN_CENTER_VERTICAL)
4270            h,k,l = POData['axis']
4271            poAxis = wx.TextCtrl(MCSA,-1,'%3d %3d %3d'%(h,k,l),style=wx.TE_PROCESS_ENTER)
4272            poAxis.Bind(wx.EVT_TEXT_ENTER,OnPOAxis)
4273            poAxis.Bind(wx.EVT_KILL_FOCUS,OnPOAxis)
4274            poSizer.Add(poAxis,0,wx.ALIGN_CENTER_VERTICAL)
4275            return poSizer
4276           
4277        def ResultsSizer(Results):
4278           
4279            def OnCellChange(event):
4280                r,c = event.GetRow(),event.GetCol()
4281                if c == 0:
4282                    for row in range(resultsGrid.GetNumberRows()):
4283                        resultsTable.SetValue(row,c,False)
4284                        Results[row][0] = False
4285                    result = Results[r]
4286                    Models = data['MCSA']['Models']
4287                    SetSolution(result,Models)
4288                    Results[r][0] = True
4289                    resultsTable.SetValue(r,0,True)
4290                    G2plt.PlotStructure(G2frame,data)
4291                    wx.CallAfter(UpdateMCSA,MCSA.GetScrollPos(wx.VERTICAL))
4292                    resultsGrid.ForceRefresh()
4293                elif c == 1:
4294                    if Results[r][1]:
4295                        Results[r][1] = False
4296                    else:
4297                        Results[r][1] = True
4298                    resultsTable.SetValue(r,c,Results[r][1])
4299                    resultsGrid.ForceRefresh()
4300               
4301            resultsSizer = wx.BoxSizer(wx.VERTICAL)
4302            maxVary = 0
4303            resultVals = []
4304            for result in Results:
4305                maxVary = max(maxVary,len(result[-1]))
4306                resultVals.append(result[:-1])
4307            rowLabels = []
4308            for i in range(len(Results)): rowLabels.append(str(i))
4309            colLabels = ['Select','Keep','Residual','Tmin',]
4310            for item in result[-1]: colLabels.append(item)   #from last result from for loop above
4311            Types = [wg.GRID_VALUE_BOOL,wg.GRID_VALUE_BOOL,wg.GRID_VALUE_FLOAT+':10,4',
4312                wg.GRID_VALUE_FLOAT+':10,4',]+maxVary*[wg.GRID_VALUE_FLOAT+':10,5',]
4313            resultsTable = G2gd.Table(resultVals,rowLabels=rowLabels,colLabels=colLabels,types=Types)
4314            resultsGrid = G2gd.GSGrid(MCSA)
4315            resultsGrid.SetTable(resultsTable, True)
4316            resultsGrid.Bind(wg.EVT_GRID_CELL_LEFT_CLICK, OnCellChange)
4317            resultsGrid.AutoSizeColumns(True)
4318            for r in range(resultsGrid.GetNumberRows()):
4319                for c in range(resultsGrid.GetNumberCols()):
4320                    if c in [0,1]:
4321                        resultsGrid.SetReadOnly(r,c,isReadOnly=False)
4322                    else:
4323                        resultsGrid.SetCellStyle(r,c,VERY_LIGHT_GREY,True)
4324            resultsSizer.Add(resultsGrid)
4325            return resultsSizer
4326       
4327        # UpdateMCSA executable code starts here
4328        MCSA.DestroyChildren()
4329        general = data['General']
4330        Amat,Bmat = G2lat.cell2AB(general['Cell'][1:7])
4331        RBData = G2frame.PatternTree.GetItemPyData(   
4332            G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Rigid bodies'))
4333        Indx = {}
4334        atomStyle = 'balls & sticks'
4335        if 'macro' in general['Type']:
4336            atomStyle = 'sticks'
4337        G2frame.dataFrame.SetStatusText('')
4338        mainSizer = wx.BoxSizer(wx.VERTICAL)
4339        if not data['MCSA']['Models']:
4340            mainSizer.Add((5,5),0)
4341            mainSizer.Add(wx.StaticText(MCSA,-1,'No MC/SA models:'),0,wx.ALIGN_CENTER_VERTICAL)
4342            mainSizer.Add((5,5),0)
4343        else:
4344            mainSizer.Add((5,5),0)
4345            mainSizer.Add(wx.StaticText(MCSA,-1,'MC/SA models:'),0,wx.ALIGN_CENTER_VERTICAL)
4346            mainSizer.Add((5,5),0)
4347            for model in data['MCSA']['Models']:
4348                Xsize = 500
4349                if model['Type'] == 'MD':
4350                    mainSizer.Add(MDSizer(model))
4351                elif model['Type'] == 'Atom':
4352                    Asizer = atomSizer(model)
4353                    mainSizer.Add(Asizer)
4354                    Xsize = max(Asizer.GetMinSize()[0],Xsize)
4355                else:
4356                    Rsizer = rbSizer(model)
4357                    mainSizer.Add(Rsizer)
4358                    Xsize = max(Rsizer.GetMinSize()[0],Xsize)
4359                G2gd.HorizontalLine(mainSizer,MCSA)
4360               
4361        if not data['MCSA']['Results']:
4362            mainSizer.Add((5,5),0)
4363            mainSizer.Add(wx.StaticText(MCSA,-1,'No MC/SA results:'),0,wx.ALIGN_CENTER_VERTICAL)
4364            mainSizer.Add((5,5),0)
4365        else:
4366            mainSizer.Add((5,5),0)
4367            mainSizer.Add(wx.StaticText(MCSA,-1,'MC/SA results:'),0,wx.ALIGN_CENTER_VERTICAL)
4368            mainSizer.Add((5,5),0)
4369            Results = data['MCSA']['Results']
4370            mainSizer.Add(ResultsSizer(Results))
4371           
4372        SetPhaseWindow(G2frame.dataFrame,MCSA,mainSizer)
4373        Size = MCSA.GetSize()
4374        Size[0] = Xsize+40
4375        G2frame.dataFrame.SetSize(Size)
4376        MCSA.Scroll(0,Scroll)
4377       
4378    def SetSolution(result,Models):
4379        for key,val in zip(result[-1],result[4:-1]):
4380            vals = key.split(':')
4381            nObj,name = int(vals[0]),vals[1]
4382            if 'A' in name:
4383                ind = ['Ax','Ay','Az'].index(name)
4384                Models[nObj]['Pos'][0][ind] = val                           
4385            elif 'Q' in name:
4386                ind = ['Qa','Qi','Qj','Qk'].index(name)
4387                Models[nObj]['Ori'][0][ind] = val
4388            elif 'P' in name:
4389                ind = ['Px','Py','Pz'].index(name)
4390                Models[nObj]['Pos'][0][ind] = val                           
4391            elif 'T' in name:
4392                tnum = int(name.split('Tor')[1])
4393                Models[nObj]['Tor'][0][tnum] = val                                                       
4394            else:       #March Dollase
4395                Models[0]['Coef'][0] = val
4396           
4397    def OnRunMultiMCSA(event):
4398        RunMCSA('multi')
4399       
4400    def OnRunSingleMCSA(event):
4401        RunMCSA('single')
4402
4403    def RunMCSA(process):
4404        generalData = data['General']
4405        mcsaControls = generalData['MCSA controls']
4406        reflName = mcsaControls['Data source']
4407        phaseName = generalData['Name']
4408        MCSAdata = data['MCSA']
4409        saveResult = []
4410        for result in MCSAdata['Results']:
4411            if result[1]:       #keep?
4412                saveResult.append(result)
4413        MCSAdata['Results'] = saveResult           
4414        covData = {}
4415        if 'PWDR' in reflName:
4416            PatternId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root, reflName)
4417            reflSets = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId,'Reflection Lists'))
4418            try:        #patch for old reflection data
4419                reflData = reflSets[phaseName]['RefList']
4420            except TypeError:
4421                reflData = reflSets[phaseName]
4422            reflType = 'PWDR'
4423        elif 'HKLF' in reflName:
4424            PatternId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root, reflName)
4425            try:
4426                reflData = G2frame.PatternTree.GetItemPyData(PatternId)[1]['RefList']
4427            except TypeError:
4428                reflData = G2frame.PatternTree.GetItemPyData(PatternId)[1]
4429            reflType = 'HKLF'
4430        elif reflName == 'Pawley reflections':
4431            reflData = data['Pawley ref']
4432            covData = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.root, 'Covariance'))
4433            reflType = 'Pawley'
4434        else:
4435            print '**** ERROR - No data defined for MC/SA run'
4436            return
4437        print 'MC/SA run:'
4438        print 'Reflection type:',reflType,' Total No. reflections: ',len(reflData)
4439        RBdata = G2frame.PatternTree.GetItemPyData(   
4440            G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Rigid bodies'))
4441        MCSAmodels = MCSAdata['Models']
4442        if not len(MCSAmodels):
4443            print '**** ERROR - no models defined for MC/SA run****'
4444            return
4445        time1 = time.time()
4446        if process == 'single':
4447            pgbar = wx.ProgressDialog('MC/SA','Residual Rcf =',101.0, 
4448                style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE|wx.PD_CAN_ABORT)
4449            screenSize = wx.ClientDisplayRect()
4450            Size = pgbar.GetSize()
4451            Size = (int(Size[0]*1.2),Size[1]) # increase size a bit along x
4452            pgbar.SetPosition(wx.Point(screenSize[2]-Size[0]-305,screenSize[1]+5))
4453            pgbar.SetSize(Size)
4454        else:
4455            pgbar = None
4456        try:
4457            tsf = 0.
4458            nCyc = mcsaControls['Cycles']
4459            if process == 'single':
4460                for i in range(nCyc):
4461                    Result,tsum = G2mth.mcsaSearch(data,RBdata,reflType,reflData,covData,pgbar)
4462                    MCSAdata['Results'].append(Result)
4463                    print ' MC/SA run completed: %d residual: %.3f%% SFcalc time: %.2fs'%(i,100*Result[2],tsum)
4464                    tsf += tsum
4465                print ' Structure factor time: %.2f'%(tsf)
4466            else:
4467                MCSAdata['Results'] = G2mth.MPmcsaSearch(nCyc,data,RBdata,reflType,reflData,covData)
4468            print ' MC/SA run time: %.2f'%(time.time()-time1)
4469        finally:
4470            if process == 'single':
4471                pgbar.Destroy()
4472        MCSAdata['Results'] = G2mth.sortArray(MCSAdata['Results'],2,reverse=False)
4473        MCSAdata['Results'][0][0] = True
4474        SetSolution(MCSAdata['Results'][0],data['MCSA']['Models'])
4475        G2frame.dataDisplay.SetFocus()
4476        Page = G2frame.dataDisplay.FindPage('MC/SA')
4477        G2frame.dataDisplay.SetSelection(Page)
4478        G2plt.PlotStructure(G2frame,data)
4479        wx.CallAfter(UpdateMCSA)
4480
4481    def OnMCSAaddAtom(event):
4482        dlg = G2elemGUI.PickElement(G2frame)
4483        if dlg.ShowModal() == wx.ID_OK:
4484            El = dlg.Elem.strip()
4485            Info = G2elem.GetAtomInfo(El)
4486        dlg.Destroy()
4487       
4488        atom = {'Type':'Atom','atType':El,'Pos':[[0.,0.,0.],
4489            [False,False,False],[[0.,1.],[0.,1.],[0.,1.]]],
4490            'name':El+'('+str(len(data['MCSA']['Models']))+')'}     
4491        data['MCSA']['Models'].append(atom)
4492        data['MCSA']['AtInfo'][El] = [Info['Drad'],Info['Color']]
4493        G2plt.PlotStructure(G2frame,data)
4494        UpdateMCSA()
4495       
4496    def OnMCSAaddRB(event):
4497        rbData = G2frame.PatternTree.GetItemPyData(   
4498            G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Rigid bodies'))
4499        rbNames = {}
4500        for rbVec in rbData['Vector']:
4501            if rbVec != 'AtInfo':
4502                rbNames[rbData['Vector'][rbVec]['RBname']] = ['Vector',rbVec]
4503        for rbRes in rbData['Residue']:
4504            if rbRes != 'AtInfo':
4505                rbNames[rbData['Residue'][rbRes]['RBname']] = ['Residue',rbRes]
4506        if not rbNames:
4507            print '**** ERROR - no rigid bodies defined ****'
4508            return
4509        dlg = wx.SingleChoiceDialog(G2frame.dataFrame,'Select','Rigid body',rbNames.keys())
4510        if dlg.ShowModal() == wx.ID_OK:
4511            sel = dlg.GetSelection()
4512            rbname = rbNames.keys()[sel]
4513            rbType,rbId = rbNames[rbname]
4514            RB = rbData[rbType][rbId]
4515        body = {'name':RB['RBname']+'('+str(len(data['MCSA']['Models']))+')','RBId':rbId,'Type':rbType,
4516            'Pos':[[0.,0.,0.],[False,False,False],[[0.,1.],[0.,1.],[0.,1.]]],'Ovar':'','MolCent':[[0.,0.,0.],False],
4517            'Ori':[[180.,0.,0.,1.],[False,False,False,False],[[0.,360.],[-1.,1.],[-1.,1.],[-1.,1.]]]}
4518        if rbType == 'Residue':
4519            body['Tor'] = [[],[],[]]
4520            for i,tor in enumerate(RB['rbSeq']):
4521                body['Tor'][0].append(0.0)
4522                body['Tor'][1].append(False)
4523                body['Tor'][2].append([0.,360.])
4524        data['MCSA']['Models'].append(body)
4525        data['MCSA']['rbData'] = rbData
4526        data['MCSA']['AtInfo'].update(rbData[rbType]['AtInfo'])
4527        G2plt.PlotStructure(G2frame,data)
4528        UpdateMCSA()
4529       
4530    def OnMCSAclear(event):
4531        data['MCSA'] = {'Models':[{'Type':'MD','Coef':[1.0,False,[.8,1.2],],'axis':[0,0,1]}],'Results':[],'AtInfo':{}}
4532        G2plt.PlotStructure(G2frame,data)
4533        UpdateMCSA()
4534       
4535    def OnMCSAmove(event):
4536        general = data['General']
4537        Amat,Bmat = G2lat.cell2AB(general['Cell'][1:7])
4538        xyz,aTypes = G2mth.UpdateMCSAxyz(Bmat,data['MCSA'])
4539        for iat,atype in enumerate(aTypes):
4540            x,y,z = xyz[iat]
4541            AtomAdd(x,y,z,atype,Name=atype+'(%d)'%(iat+1))           
4542        G2plt.PlotStructure(G2frame,data)
4543       
4544    def OnClearResults(event):
4545        data['MCSA']['Results'] = []
4546        UpdateMCSA()
4547                   
4548################################################################################
4549##### Pawley routines
4550################################################################################
4551
4552    def FillPawleyReflectionsGrid():
4553        def KeyEditPawleyGrid(event):
4554            colList = G2frame.PawleyRefl.GetSelectedCols()
4555            rowList = G2frame.PawleyRefl.GetSelectedRows()
4556            PawleyPeaks = data['Pawley ref']
4557            if event.GetKeyCode() == wx.WXK_RETURN:
4558                event.Skip(True)
4559            elif event.GetKeyCode() == wx.WXK_CONTROL:
4560                event.Skip(True)
4561            elif event.GetKeyCode() == wx.WXK_SHIFT:
4562                event.Skip(True)
4563            elif colList:
4564                G2frame.PawleyRefl.ClearSelection()
4565                key = event.GetKeyCode()
4566                for col in colList:
4567                    if PawleyTable.GetTypeName(0,col) == wg.GRID_VALUE_BOOL:
4568                        if key == 89: #'Y'
4569                            for row in range(PawleyTable.GetNumberRows()): PawleyPeaks[row][col]=True
4570                        elif key == 78:  #'N'
4571                            for row in range(PawleyTable.GetNumberRows()): PawleyPeaks[row][col]=False
4572                        FillPawleyReflectionsGrid()
4573            elif rowList:
4574                if event.GetKeyCode() == wx.WXK_DELETE:
4575                    rowList.reverse()
4576                    for row in rowList:
4577                        del(PawleyPeaks[row])
4578                    FillPawleyReflectionsGrid()
4579           
4580        # FillPawleyReflectionsGrid executable starts here
4581        G2frame.dataFrame.SetStatusText('To delete a few Pawley reflections: select rows & press Delete')                       
4582        if 'Pawley ref' in data:
4583            PawleyPeaks = data['Pawley ref']                       
4584            rowLabels = []
4585            for i in range(len(PawleyPeaks)): rowLabels.append(str(i))
4586            colLabels = ['h','k','l','mul','d','refine','Fsq(hkl)','sig(Fsq)']
4587            Types = 4*[wg.GRID_VALUE_LONG,]+[wg.GRID_VALUE_FLOAT+':10,4',wg.GRID_VALUE_BOOL,]+ \
4588                2*[wg.GRID_VALUE_FLOAT+':10,2',]
4589            PawleyTable = G2gd.Table(PawleyPeaks,rowLabels=rowLabels,colLabels=colLabels,types=Types)
4590            G2frame.PawleyRefl.SetTable(PawleyTable, True)
4591            G2frame.PawleyRefl.Bind(wx.EVT_KEY_DOWN, KeyEditPawleyGrid)                 
4592            for r in range(G2frame.PawleyRefl.GetNumberRows()):
4593                for c in range(G2frame.PawleyRefl.GetNumberCols()):
4594                    if c in [5,6]:
4595                        G2frame.PawleyRefl.SetReadOnly(r,c,isReadOnly=False)
4596                    else:
4597                        G2frame.PawleyRefl.SetCellStyle(r,c,VERY_LIGHT_GREY,True)
4598            G2frame.PawleyRefl.SetMargins(0,0)
4599            G2frame.PawleyRefl.AutoSizeColumns(False)
4600            G2frame.dataFrame.setSizePosLeft([450,300])
4601                   
4602    def OnPawleyLoad(event):
4603        generalData = data['General']
4604        dmin = generalData['Pawley dmin']
4605        cell = generalData['Cell'][1:7]
4606        A = G2lat.cell2A(cell)
4607        SGData = generalData['SGData']
4608        HKLd = np.array(G2lat.GenHLaue(dmin,SGData,A))
4609        PawleyPeaks = []
4610        wx.BeginBusyCursor()
4611        try:
4612            for h,k,l,d in HKLd:
4613                ext,mul = G2spc.GenHKLf([h,k,l],SGData)[:2]
4614                if not ext:
4615                    mul *= 2        #for powder multiplicity
4616                    PawleyPeaks.append([h,k,l,mul,d,False,100.0,1.0])
4617        finally:
4618            wx.EndBusyCursor()
4619        data['Pawley ref'] = PawleyPeaks
4620        FillPawleyReflectionsGrid()
4621       
4622    def OnPawleyEstimate(event):
4623        try:
4624            Refs = data['Pawley ref']
4625            Histograms = data['Histograms']
4626        except KeyError:
4627            G2frame.ErrorDialog('Pawley estimate','No histograms defined for this phase')
4628            return
4629        HistoNames = Histograms.keys()
4630        PatternId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,HistoNames[0])
4631        xdata = G2frame.PatternTree.GetItemPyData(PatternId)[1]
4632        Inst = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId,'Instrument Parameters'))[0]
4633        Sample = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId,'Sample Parameters'))
4634        wave = G2mth.getWave(Inst)
4635        posCorr = Inst['Zero'][1]
4636        const = 9.e-2/(np.pi*Sample['Gonio. radius'])                  #shifts in microns
4637       
4638        wx.BeginBusyCursor()
4639        try:
4640            for ref in Refs:
4641                pos = 2.0*asind(wave/(2.0*ref[4]))
4642                if 'Bragg' in Sample['Type']:
4643                    pos -= const*(4.*Sample['Shift'][0]*cosd(pos/2.0)+ \
4644                        Sample['Transparency'][0]*sind(pos)*100.0)            #trans(=1/mueff) in cm
4645                else:               #Debye-Scherrer - simple but maybe not right
4646                    pos -= const*(Sample['DisplaceX'][0]*cosd(pos)+Sample['DisplaceY'][0]*sind(pos))
4647                indx = np.searchsorted(xdata[0],pos)
4648                try:
4649                    FWHM = max(0.001,G2pwd.getFWHM(pos,Inst))/2.
4650                    dx = xdata[0][indx+1]-xdata[0][indx]
4651                    ref[6] = FWHM*(xdata[1][indx]-xdata[4][indx])*cosd(pos/2.)**3/dx
4652                    Lorenz = 1./(2.*sind(xdata[0][indx]/2.)**2*cosd(xdata[0][indx]/2.))           #Lorentz correction
4653                    pola,dIdPola = G2pwd.Polarization(Inst['Polariz.'][1],xdata[0][indx],Inst['Azimuth'][1])
4654                    ref[6] /= (Lorenz*pola*ref[3])
4655                except IndexError:
4656                    pass
4657        finally:
4658            wx.EndBusyCursor()
4659        FillPawleyReflectionsGrid()
4660
4661    def OnPawleyUpdate(event):
4662        '''This is the place for any reflection modification trick
4663        Patterson squared, leBail extraction, etc.
4664        '''
4665        try:
4666            Refs = data['Pawley ref']
4667            Histograms = data['Histograms']
4668        except KeyError:
4669            G2frame.ErrorDialog('Pawley update','No histograms defined for this phase')
4670            return
4671        HistoNames = Histograms.keys()
4672        PatternId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,HistoNames[0])
4673        refData = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId,'Reflection Lists'))[PhaseName]
4674        Inv = data['General']['SGData']['SGInv']
4675        mult = 0.5
4676        if Inv:
4677            mult = 0.3
4678        wx.BeginBusyCursor()
4679        try:
4680            for iref,ref in enumerate(Refs):
4681                try:
4682                    if ref[6] < 0.:
4683                        ref[6] *= -mult
4684                        refData[iref][8] *= -mult
4685                        refData[iref][9] *= -mult
4686                        ref[5] = False
4687                        ref[7] = 1.0
4688                except IndexError:
4689                    print 'skipped',ref
4690                    pass
4691        finally:
4692            wx.EndBusyCursor()
4693        wx.CallAfter(FillPawleyReflectionsGrid)
4694                           
4695################################################################################
4696##### Fourier routines
4697################################################################################
4698
4699    def FillMapPeaksGrid():
4700                       
4701        def RowSelect(event):
4702            r,c =  event.GetRow(),event.GetCol()
4703            if r < 0 and c < 0:
4704                if MapPeaks.IsSelection():
4705                    MapPeaks.ClearSelection()
4706                else:
4707                    for row in range(MapPeaks.GetNumberRows()):
4708                        MapPeaks.SelectRow(row,True)
4709                   
4710            elif c < 0:                   #only row clicks
4711                if event.ControlDown():                   
4712                    if r in MapPeaks.GetSelectedRows():
4713                        MapPeaks.DeselectRow(r)
4714                    else:
4715                        MapPeaks.SelectRow(r,True)
4716                elif event.ShiftDown():
4717                    indxs = MapPeaks.GetSelectedRows()
4718                    MapPeaks.ClearSelection()
4719                    ibeg = 0
4720                    if indxs:
4721                        ibeg = indxs[-1]
4722                    for row in range(ibeg,r+1):
4723                        MapPeaks.SelectRow(row,True)
4724                else:
4725                    MapPeaks.ClearSelection()
4726                    MapPeaks.SelectRow(r,True)
4727            elif r < 0:                 #a column pick
4728                mapPeaks = data['Map Peaks']
4729                c =  event.GetCol()
4730                if colLabels[c] == 'mag':
4731                    mapPeaks = G2mth.sortArray(mapPeaks,c,reverse=True)
4732                elif colLabels[c] in ['x','y','z','dzero']:
4733                    mapPeaks = G2mth.sortArray(mapPeaks,c)
4734                else:
4735                    return
4736                data['Map Peaks'] = mapPeaks
4737                wx.CallAfter(FillMapPeaksGrid)
4738            G2plt.PlotStructure(G2frame,data)                   
4739           
4740        G2frame.dataFrame.setSizePosLeft([450,300])
4741        G2frame.dataFrame.SetStatusText('')
4742        if 'Map Peaks' in data:
4743            G2frame.dataFrame.SetStatusText('Select mag or dzero columns to sort')
4744            mapPeaks = data['Map Peaks']                       
4745            rowLabels = []
4746            for i in range(len(mapPeaks)): rowLabels.append(str(i))
4747            colLabels = ['mag','x','y','z','dzero']
4748            Types = 5*[wg.GRID_VALUE_FLOAT+':10,4',]
4749            G2frame.MapPeaksTable = G2gd.Table(mapPeaks,rowLabels=rowLabels,colLabels=colLabels,types=Types)
4750            MapPeaks.SetTable(G2frame.MapPeaksTable, True)
4751            MapPeaks.Bind(wg.EVT_GRID_LABEL_LEFT_CLICK, RowSelect)
4752            for r in range(MapPeaks.GetNumberRows()):
4753                for c in range(MapPeaks.GetNumberCols()):
4754                    MapPeaks.SetCellStyle(r,c,VERY_LIGHT_GREY,True)
4755            MapPeaks.SetMargins(0,0)
4756            MapPeaks.AutoSizeColumns(False)
4757                   
4758    def OnPeaksMove(event):
4759        if 'Map Peaks' in data:
4760            mapPeaks = np.array(data['Map Peaks'])
4761            peakMax = np.max(mapPeaks.T[0])
4762            Ind = MapPeaks.GetSelectedRows()
4763            for ind in Ind:
4764                mag,x,y,z,d = mapPeaks[ind]
4765                AtomAdd(x,y,z,'H',Name='M '+'%d'%(int(100*mag/peakMax)))
4766            G2plt.PlotStructure(G2frame,data)
4767   
4768    def OnPeaksClear(event):
4769        data['Map Peaks'] = []
4770        FillMapPeaksGrid()
4771        G2plt.PlotStructure(G2frame,data)
4772       
4773    def OnPeaksDelete(event):
4774        if 'Map Peaks' in data:
4775            mapPeaks = data['Map Peaks']
4776            Ind = MapPeaks.GetSelectedRows()
4777            Ind.sort()
4778            Ind.reverse()
4779            for ind in Ind:
4780                mapPeaks = np.delete(mapPeaks,ind,0)
4781            data['Map Peaks'] = mapPeaks
4782        FillMapPeaksGrid()
4783        G2plt.PlotStructure(G2frame,data)
4784       
4785    def OnPeaksEquiv(event):
4786        if 'Map Peaks' in data:
4787            mapPeaks = data['Map Peaks']
4788            Ind = MapPeaks.GetSelectedRows()
4789            if Ind:
4790                wx.BeginBusyCursor()
4791                try:
4792                    Ind = G2mth.PeaksEquiv(data,Ind)
4793                    for r in range(MapPeaks.GetNumberRows()):
4794                        if r in Ind:
4795                            MapPeaks.SelectRow(r,addToSelected=True)
4796                        else:
4797                            MapPeaks.DeselectRow(r)
4798                finally:
4799                    wx.EndBusyCursor()
4800                G2plt.PlotStructure(G2frame,data)
4801
4802    def OnShowBonds(event):
4803        generalData = data['General']
4804        if generalData['Map'].get('Show bonds',False):
4805            generalData['Map']['Show bonds'] = False
4806            G2frame.dataFrame.MapPeaksEdit.SetLabel(G2gd.wxID_SHOWBONDS,'Show bonds')
4807        else:
4808            generalData['Map']['Show bonds'] = True
4809            G2frame.dataFrame.MapPeaksEdit.SetLabel(G2gd.wxID_SHOWBONDS,'Hide bonds')
4810        FillMapPeaksGrid()
4811        G2plt.PlotStructure(G2frame,data)
4812               
4813    def OnPeaksUnique(event):
4814        if 'Map Peaks' in data:
4815            mapPeaks = data['Map Peaks']
4816            Ind = MapPeaks.GetSelectedRows()
4817            if Ind:
4818                wx.BeginBusyCursor()
4819                try:
4820                    Ind = G2mth.PeaksUnique(data,Ind)
4821                    for r in range(MapPeaks.GetNumberRows()):
4822                        if r in Ind:
4823                            MapPeaks.SelectRow(r,addToSelected=True)
4824                        else:
4825                            MapPeaks.DeselectRow(r)
4826                finally:
4827                    wx.EndBusyCursor()
4828                G2plt.PlotStructure(G2frame,data)
4829               
4830    def OnPeaksViewPoint(event):
4831        # set view point
4832        indx = MapPeaks.GetSelectedRows()
4833        if not indx:
4834            G2frame.ErrorDialog('Set viewpoint','No peaks selected')
4835            return
4836        mapPeaks = data['Map Peaks']
4837        drawingData = data['Drawing']
4838        drawingData['viewPoint'][0] = mapPeaks[indx[0]][1:4]
4839        G2plt.PlotStructure(G2frame,data)
4840   
4841    def OnPeaksDistVP(event):
4842        # distance to view point
4843        indx = MapPeaks.GetSelectedRows()
4844        if not indx:
4845            G2frame.ErrorDialog('Peak distance','No peaks selected')
4846            return
4847        generalData = data['General']
4848        Amat,Bmat = G2lat.cell2AB(generalData['Cell'][1:7])           
4849        mapPeaks = data['Map Peaks']
4850        drawingData = data['Drawing']
4851        viewPt = np.array(drawingData['viewPoint'][0])
4852        print ' Distance from view point at %.3f %.3f %.3f to:'%(viewPt[0],viewPt[1],viewPt[2])
4853        colLabels = [MapPeaks.GetColLabelValue(c) for c in range(MapPeaks.GetNumberCols())]
4854        cx = colLabels.index('x')
4855        cm = colLabels.index('mag')
4856        for i in indx:
4857            peak = mapPeaks[i]
4858            Dx = np.array(peak[cx:cx+3])-viewPt
4859            dist = np.sqrt(np.sum(np.inner(Amat,Dx)**2,axis=0))
4860            print 'Peak: %5d mag= %8.2f distance = %.3f'%(i,peak[cm],dist)
4861
4862    def OnPeaksDA(event):
4863        #distance, angle
4864        indx = MapPeaks.GetSelectedRows()
4865        if len(indx) not in [2,3]:
4866            G2frame.ErrorDialog('Peak distance/angle','Wrong number of atoms for distance or angle calculation')
4867            return
4868        generalData = data['General']
4869        Amat,Bmat = G2lat.cell2AB(generalData['Cell'][1:7])           
4870        mapPeaks = data['Map Peaks']
4871        xyz = []
4872        for i in indx:
4873            xyz.append(mapPeaks[i][1:4])
4874        if len(indx) == 2:
4875            print ' distance for atoms %s = %.3f'%(str(indx),G2mth.getRestDist(xyz,Amat))
4876        else:
4877            print ' angle for atoms %s = %.2f'%(str(indx),G2mth.getRestAngle(xyz,Amat))
4878                                   
4879    def OnFourierMaps(event):
4880        generalData = data['General']
4881        mapData = generalData['Map']
4882        reflName = mapData['RefList']
4883        if not reflName:
4884            G2frame.ErrorDialog('Fourier map','No reflections defined for Fourier map')
4885            return
4886        phaseName = generalData['Name']
4887        if 'PWDR' in reflName:
4888            PatternId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root, reflName)
4889            reflSets = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId,'Reflection Lists'))
4890            reflData = reflSets[phaseName]
4891            if isinstance(reflData,list):       #patch for old reflection data
4892                RefData = {'RefList':[],'FF':[]}
4893                for ref in reflData:
4894                    RefData['RefList'].append(ref[:11]+[ref[13],])
4895                    RefData['FF'].append(ref[14])
4896                RefData['RefList'] = np.array(RefData['RefList'])
4897                reflData = RefData
4898        elif 'HKLF' in reflName:
4899            PatternId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root, reflName)
4900            reflData = G2frame.PatternTree.GetItemPyData(PatternId)[1]
4901        if 'Omit' in mapData['MapType']:
4902            pgbar = wx.ProgressDialog('Omit map','Blocks done',65, 
4903            style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE)
4904            mapData.update(G2mth.OmitMap(data,reflData,pgbar))
4905            pgbar.Destroy()
4906        else:
4907            mapData.update(G2mth.FourierMap(data,reflData))
4908        mapData['Flip'] = False
4909        mapSig = np.std(mapData['rho'])
4910        if not data['Drawing']:                 #if new drawing - no drawing data!
4911            SetupDrawingData()
4912        data['Drawing']['contourLevel'] = 1.
4913        data['Drawing']['mapSize'] = 10.
4914        print mapData['MapType']+' computed: rhomax = %.3f rhomin = %.3f sigma = %.3f'%(np.max(mapData['rho']),np.min(mapData['rho']),mapSig)
4915        UpdateDrawAtoms()
4916        G2plt.PlotStructure(G2frame,data)
4917       
4918    def OnFourClear(event):
4919        generalData = data['General']
4920        generalData['Map'] = mapDefault
4921        G2plt.PlotStructure(G2frame,data)
4922       
4923    def printRho(SGLaue,rho,rhoMax):                         
4924# map printing for testing purposes
4925        dim = len(rho.shape)
4926        if dim == 2:
4927            ix,jy = rho.shape
4928            for j in range(jy):
4929                line = ''
4930                if SGLaue in ['3','3m1','31m','6/m','6/mmm']:
4931                    line += (jy-j)*'  '
4932                for i in range(ix):
4933                    r = int(100*rho[i,j]/rhoMax)
4934                    line += '%4d'%(r)
4935                print line+'\n'
4936        else:
4937            ix,jy,kz = rho.shape
4938            for k in range(kz):
4939                print 'k = ',k
4940                for j in range(jy):
4941                    line = ''
4942                    if SGLaue in ['3','3m1','31m','6/m','6/mmm']:
4943                        line += (jy-j)*'  '
4944                    for i in range(ix):
4945                        r = int(100*rho[i,j,k]/rhoMax)
4946                        line += '%4d'%(r)
4947                    print line+'\n'
4948## keep this               
4949   
4950    def OnSearchMaps(event):
4951                                   
4952        peaks = []
4953        mags = []
4954        print ' Begin fourier map search - can take some time'
4955        time0 = time.time()
4956        generalData = data['General']
4957        mapData = generalData['Map']
4958        if len(mapData['rho']):
4959            wx.BeginBusyCursor()
4960            try:
4961                peaks,mags,dzeros = G2mth.SearchMap(data)
4962            finally:
4963                wx.EndBusyCursor()
4964            if len(peaks):
4965                mapPeaks = np.concatenate((mags,peaks,dzeros),axis=1)
4966                data['Map Peaks'] = G2mth.sortArray(mapPeaks,0,reverse=True)           
4967            print ' Map search finished, time = %.2fs'%(time.time()-time0)
4968            print ' No.peaks found:',len(peaks)   
4969            Page = G2frame.dataDisplay.FindPage('Map peaks')
4970            G2frame.dataDisplay.SetSelection(Page)
4971            wx.CallAfter(FillMapPeaksGrid)
4972            UpdateDrawAtoms()
4973        else:
4974            print 'No map available'
4975       
4976    def OnChargeFlip(event):
4977        generalData = data['General']
4978        mapData = generalData['Map']
4979        flipData = generalData['Flip']
4980        reflName = flipData['RefList']
4981        phaseName = generalData['Name']
4982        if 'PWDR' in reflName:
4983            PatternId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root, reflName)
4984            reflSets = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId,'Reflection Lists'))
4985            reflDict = reflSets[phaseName]
4986            if isinstance(reflDict,list):       #patch for old reflection data
4987                RefData = {'RefList':[],'FF':[]}
4988                for ref in reflDict:
4989                    RefData['RefList'].append(ref[:11]+[ref[13],])
4990                    RefData['FF'].append(ref[14])
4991                RefData['RefList'] = np.array(RefData['RefList'])
4992                reflDict = RefData
4993        elif 'HKLF' in reflName:
4994            PatternId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root, reflName)
4995            reflDict = G2frame.PatternTree.GetItemPyData(PatternId)[1]
4996        else:
4997            print '**** ERROR - No data defined for charge flipping'
4998            return
4999        pgbar = wx.ProgressDialog('Charge flipping','Residual Rcf =',101.0, 
5000            style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE|wx.PD_CAN_ABORT)
5001        screenSize = wx.ClientDisplayRect()
5002        Size = pgbar.GetSize()
5003        Size = (int(Size[0]*1.2),Size[1]) # increase size a bit along x
5004        pgbar.SetPosition(wx.Point(screenSize[2]-Size[0]-305,screenSize[1]+5))
5005        pgbar.SetSize(Size)
5006        try:
5007            mapData.update(G2mth.ChargeFlip(data,reflDict,pgbar))
5008        finally:
5009            pgbar.Destroy()
5010        mapData['Flip'] = True       
5011        mapSig = np.std(mapData['rho'])
5012        if not data['Drawing']:                 #if new drawing - no drawing data!
5013            SetupDrawingData()
5014        data['Drawing']['contourLevel'] = 1.
5015        data['Drawing']['mapSize'] = 10.
5016        print ' Charge flip map computed: rhomax = %.3f rhomin = %.3f sigma = %.3f'%(np.max(mapData['rho']),np.min(mapData['rho']),mapSig)
5017        if mapData['Rcf'] < 99.:
5018            OnSearchMaps(event)             #does a plot structure at end
5019        else:
5020            print 'Bad charge flip map - no peak search done'
5021                           
5022    def OnTextureRefine(event):
5023        print 'refine texture?'
5024        event.Skip()       
5025           
5026    def OnTextureClear(event):
5027        print 'clear texture?'
5028        event.Skip()
5029
5030    def FillSelectPageMenu(menuBar):
5031        '''Assign bindings to the menu buttons to switch between phase tabs;
5032        define a dictionary with the page index for each tab
5033        '''
5034        def OnSelectPage(event):
5035            'Called when an item is selected from the Select page menu'
5036            page = Pagedict.get(event.GetId())
5037            if page is not None: G2frame.dataDisplay.SetSelection(page)
5038        mid = menuBar.FindMenu('Select tab')
5039        Pagedict = {}
5040        for ipage,page in enumerate(Pages):
5041            menu = menuBar.GetMenu(mid)
5042            if menu.FindItem(page) < 0:
5043                Id = wx.NewId()
5044                menu.Append(id=Id,kind=wx.ITEM_NORMAL,text=page)
5045                G2frame.Bind(wx.EVT_MENU, OnSelectPage, id=Id)
5046                Pagedict[Id] = ipage
5047
5048       
5049    def OnPageChanged(event):
5050        '''This is called every time that a Notebook tab button is pressed
5051        on a Phase data item window
5052        '''
5053        for page in G2frame.dataDisplay.gridList: # clear out all grids, forcing edits in progress to complete
5054            page.ClearGrid()
5055        wx.Frame.Unbind(G2frame.dataFrame,wx.EVT_SIZE) # ignore size events during this routine
5056        page = event.GetSelection()
5057        ChangePage(page)
5058       
5059    def ChangePage(page):
5060        text = G2frame.dataDisplay.GetPageText(page)
5061#        print 'Select',page,text
5062        if text == 'General':
5063            G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.DataGeneral)
5064            FillSelectPageMenu(G2frame.dataFrame.DataGeneral)
5065            G2frame.dataFrame.Bind(wx.EVT_MENU, OnFourierMaps, id=G2gd.wxID_FOURCALC)
5066            G2frame.dataFrame.Bind(wx.EVT_MENU, OnSearchMaps, id=G2gd.wxID_FOURSEARCH)
5067            G2frame.dataFrame.Bind(wx.EVT_MENU, OnChargeFlip, id=G2gd.wxID_CHARGEFLIP)
5068            G2frame.dataFrame.Bind(wx.EVT_MENU, OnFourClear, id=G2gd.wxID_FOURCLEAR)
5069            G2frame.dataFrame.Bind(wx.EVT_MENU, OnRunSingleMCSA, id=G2gd.wxID_SINGLEMCSA)
5070            G2frame.dataFrame.Bind(wx.EVT_MENU, OnRunMultiMCSA, id=G2gd.wxID_MULTIMCSA)
5071            UpdateGeneral()
5072        elif text == 'Data':
5073            G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.DataMenu)
5074            FillSelectPageMenu(G2frame.dataFrame.DataMenu)
5075            G2frame.dataFrame.Bind(wx.EVT_MENU, OnPwdrAdd, id=G2gd.wxID_PWDRADD)
5076            G2frame.dataFrame.Bind(wx.EVT_MENU, OnHklfAdd, id=G2gd.wxID_HKLFADD)
5077            G2frame.dataFrame.Bind(wx.EVT_MENU, OnDataDelete, id=G2gd.wxID_DATADELETE)
5078            G2ddG.UpdateDData(G2frame,DData,data)
5079            G2plt.PlotSizeStrainPO(G2frame,data,Start=True)           
5080        elif text == 'Atoms':
5081            G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.AtomsMenu)
5082            FillSelectPageMenu(G2frame.dataFrame.AtomsMenu)
5083            G2frame.dataFrame.Bind(wx.EVT_MENU, OnAtomAdd, id=G2gd.wxID_ATOMSEDITADD)
5084            G2frame.dataFrame.Bind(wx.EVT_MENU, OnAtomViewAdd, id=G2gd.wxID_ATOMSVIEWADD)
5085            G2frame.dataFrame.Bind(wx.EVT_MENU, OnAtomInsert, id=G2gd.wxID_ATOMSEDITINSERT)
5086            G2frame.dataFrame.Bind(wx.EVT_MENU, OnAtomViewInsert, id=G2gd.wxID_ATOMVIEWINSERT)
5087            G2frame.dataFrame.Bind(wx.EVT_MENU, OnAtomMove, id=G2gd.wxID_ATOMMOVE)
5088            G2frame.dataFrame.Bind(wx.EVT_MENU, AtomDelete, id=G2gd.wxID_ATOMSEDITDELETE)
5089            G2frame.dataFrame.Bind(wx.EVT_MENU, AtomRefine, id=G2gd.wxID_ATOMSREFINE)
5090            G2frame.dataFrame.Bind(wx.EVT_MENU, AtomModify, id=G2gd.wxID_ATOMSMODIFY)
5091            G2frame.dataFrame.Bind(wx.EVT_MENU, AtomTransform, id=G2gd.wxID_ATOMSTRANSFORM)
5092            G2frame.dataFrame.Bind(wx.EVT_MENU, OnReloadDrawAtoms, id=G2gd.wxID_RELOADDRAWATOMS)
5093            G2frame.dataFrame.Bind(wx.EVT_MENU, OnDistAngle, id=G2gd.wxID_ATOMSDISAGL)
5094            G2frame.dataFrame.Bind(wx.EVT_MENU, OnDistAnglePrt, id=G2gd.wxID_ATOMSPDISAGL)
5095            for id in G2frame.dataFrame.ReImportMenuId:     #loop over submenu items
5096                G2frame.dataFrame.Bind(wx.EVT_MENU, OnReImport, id=id)               
5097            FillAtomsGrid(Atoms)
5098        elif text == 'Draw Options':
5099            G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.DataDrawOptions)
5100            FillSelectPageMenu(G2frame.dataFrame.DataDrawOptions)
5101            UpdateDrawOptions()
5102            wx.CallAfter(G2plt.PlotStructure,G2frame,data)
5103        elif text == 'Draw Atoms':
5104            G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.DrawAtomsMenu)
5105            FillSelectPageMenu(G2frame.dataFrame.DrawAtomsMenu)
5106            G2frame.dataFrame.Bind(wx.EVT_MENU, DrawAtomStyle, id=G2gd.wxID_DRAWATOMSTYLE)
5107            G2frame.dataFrame.Bind(wx.EVT_MENU, DrawAtomLabel, id=G2gd.wxID_DRAWATOMLABEL)
5108            G2frame.dataFrame.Bind(wx.EVT_MENU, DrawAtomColor, id=G2gd.wxID_DRAWATOMCOLOR)
5109            G2frame.dataFrame.Bind(wx.EVT_MENU, ResetAtomColors, id=G2gd.wxID_DRAWATOMRESETCOLOR)
5110            G2frame.dataFrame.Bind(wx.EVT_MENU, SetViewPoint, id=G2gd.wxID_DRAWVIEWPOINT)
5111            G2frame.dataFrame.Bind(wx.EVT_MENU, AddSymEquiv, id=G2gd.wxID_DRAWADDEQUIV)
5112            G2frame.dataFrame.Bind(wx.EVT_MENU, TransformSymEquiv, id=G2gd.wxID_DRAWTRANSFORM)
5113            G2frame.dataFrame.Bind(wx.EVT_MENU, FillCoordSphere, id=G2gd.wxID_DRAWFILLCOORD)           
5114            G2frame.dataFrame.Bind(wx.EVT_MENU, FillUnitCell, id=G2gd.wxID_DRAWFILLCELL)
5115            G2frame.dataFrame.Bind(wx.EVT_MENU, DrawAtomsDelete, id=G2gd.wxID_DRAWDELETE)
5116            G2frame.dataFrame.Bind(wx.EVT_MENU, OnDrawDistVP, id=G2gd.wxID_DRAWDISTVP)
5117            G2frame.dataFrame.Bind(wx.EVT_MENU, OnDrawDAT, id=G2gd.wxID_DRAWDISAGLTOR)
5118            G2frame.dataFrame.Bind(wx.EVT_MENU, OnDrawPlane, id=G2gd.wxID_DRAWPLANE)
5119            G2frame.dataFrame.Bind(wx.EVT_MENU, OnRestraint, id=G2gd.wxID_DRAWRESTRBOND)
5120            G2frame.dataFrame.Bind(wx.EVT_MENU, OnRestraint, id=G2gd.wxID_DRAWRESTRANGLE)
5121            G2frame.dataFrame.Bind(wx.EVT_MENU, OnRestraint, id=G2gd.wxID_DRAWRESTRPLANE)
5122            G2frame.dataFrame.Bind(wx.EVT_MENU, OnRestraint, id=G2gd.wxID_DRAWRESTRCHIRAL)
5123            G2frame.dataFrame.Bind(wx.EVT_MENU, OnDefineRB, id=G2gd.wxID_DRAWDEFINERB)
5124            UpdateDrawAtoms()
5125            wx.CallAfter(G2plt.PlotStructure,G2frame,data)
5126        elif text == 'RB Models':
5127            G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.RigidBodiesMenu)
5128            FillSelectPageMenu(G2frame.dataFrame.RigidBodiesMenu)
5129            G2frame.dataFrame.Bind(wx.EVT_MENU, OnAutoFindResRB, id=G2gd.wxID_AUTOFINDRESRB)
5130            G2frame.dataFrame.Bind(wx.EVT_MENU, OnRBAssign, id=G2gd.wxID_ASSIGNATMS2RB)
5131            G2frame.dataFrame.Bind(wx.EVT_MENU, OnRBCopyParms, id=G2gd.wxID_COPYRBPARMS)
5132            G2frame.dataFrame.Bind(wx.EVT_MENU, OnGlobalResRBTherm, id=G2gd.wxID_GLOBALTHERM)
5133            G2frame.dataFrame.Bind(wx.EVT_MENU, OnGlobalResRBRef, id=G2gd.wxID_GLOBALRESREFINE)
5134            G2frame.dataFrame.Bind(wx.EVT_MENU, OnRBRemoveAll, id=G2gd.wxID_RBREMOVEALL)
5135            FillRigidBodyGrid()
5136        elif text == 'Map peaks':
5137            G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.MapPeaksMenu)
5138            FillSelectPageMenu(G2frame.dataFrame.MapPeaksMenu)
5139            G2frame.dataFrame.Bind(wx.EVT_MENU, OnPeaksMove, id=G2gd.wxID_PEAKSMOVE)
5140            G2frame.dataFrame.Bind(wx.EVT_MENU, OnPeaksViewPoint, id=G2gd.wxID_PEAKSVIEWPT)
5141            G2frame.dataFrame.Bind(wx.EVT_MENU, OnPeaksDistVP, id=G2gd.wxID_PEAKSDISTVP)
5142            G2frame.dataFrame.Bind(wx.EVT_MENU, OnPeaksDA, id=G2gd.wxID_PEAKSDA)
5143            G2frame.dataFrame.Bind(wx.EVT_MENU, OnShowBonds, id=G2gd.wxID_SHOWBONDS)
5144            G2frame.dataFrame.Bind(wx.EVT_MENU, OnPeaksEquiv, id=G2gd.wxID_FINDEQVPEAKS)
5145            G2frame.dataFrame.Bind(wx.EVT_MENU, OnPeaksUnique, id=G2gd.wxID_PEAKSUNIQUE)
5146            G2frame.dataFrame.Bind(wx.EVT_MENU, OnPeaksDelete, id=G2gd.wxID_PEAKSDELETE)
5147            G2frame.dataFrame.Bind(wx.EVT_MENU, OnPeaksClear, id=G2gd.wxID_PEAKSCLEAR)
5148            FillMapPeaksGrid()
5149            wx.CallAfter(G2plt.PlotStructure,G2frame,data)
5150        elif text == 'MC/SA':
5151            G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.MCSAMenu)
5152            FillSelectPageMenu(G2frame.dataFrame.MCSAMenu)
5153            G2frame.dataFrame.Bind(wx.EVT_MENU, OnMCSAaddAtom, id=G2gd.wxID_ADDMCSAATOM)
5154            G2frame.dataFrame.Bind(wx.EVT_MENU, OnMCSAaddRB, id=G2gd.wxID_ADDMCSARB)
5155            G2frame.dataFrame.Bind(wx.EVT_MENU, OnMCSAclear, id=G2gd.wxID_CLEARMCSARB)
5156            G2frame.dataFrame.Bind(wx.EVT_MENU, OnMCSAmove, id=G2gd.wxID_MOVEMCSA)
5157            G2frame.dataFrame.Bind(wx.EVT_MENU, OnClearResults, id=G2gd.wxID_MCSACLEARRESULTS)
5158            UpdateMCSA()                       
5159            wx.CallAfter(G2plt.PlotStructure,G2frame,data)
5160        elif text == 'Texture':
5161            G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.TextureMenu)
5162            FillSelectPageMenu(G2frame.dataFrame.TextureMenu)
5163            G2frame.dataFrame.Bind(wx.EVT_MENU, OnTextureRefine, id=G2gd.wxID_REFINETEXTURE)
5164            G2frame.dataFrame.Bind(wx.EVT_MENU, OnTextureClear, id=G2gd.wxID_CLEARTEXTURE)
5165            UpdateTexture()                       
5166            G2plt.PlotTexture(G2frame,data,Start=True)           
5167        elif text == 'Pawley reflections':
5168            G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.PawleyMenu)
5169            FillSelectPageMenu(G2frame.dataFrame.PawleyMenu)
5170            G2frame.dataFrame.Bind(wx.EVT_MENU, OnPawleyLoad, id=G2gd.wxID_PAWLEYLOAD)
5171            G2frame.dataFrame.Bind(wx.EVT_MENU, OnPawleyEstimate, id=G2gd.wxID_PAWLEYESTIMATE)
5172            G2frame.dataFrame.Bind(wx.EVT_MENU, OnPawleyUpdate, id=G2gd.wxID_PAWLEYUPDATE)
5173            FillPawleyReflectionsGrid()
5174        else:
5175            G2gd.SetDataMenuBar(G2frame)
5176    Pages = []   
5177    wx.Frame.Unbind(G2frame.dataFrame,wx.EVT_SIZE) # ignore size events during this routine
5178    G2frame.dataDisplay.gridList = []
5179    General = wx.ScrolledWindow(G2frame.dataDisplay)
5180    G2frame.dataDisplay.AddPage(General,'General')
5181    Pages.append('General')
5182    DData = wx.ScrolledWindow(G2frame.dataDisplay)
5183    G2frame.dataDisplay.AddPage(DData,'Data')
5184    Pages.append('Data')
5185    Atoms = G2gd.GSGrid(G2frame.dataDisplay)
5186    G2frame.dataDisplay.gridList.append(Atoms)
5187    G2frame.dataDisplay.AddPage(Atoms,'Atoms')
5188    Pages.append('Atoms')
5189    drawOptions = wx.ScrolledWindow(G2frame.dataDisplay)
5190    G2frame.dataDisplay.AddPage(drawOptions,'Draw Options')
5191    Pages.append('Draw Options')
5192    drawAtoms = G2gd.GSGrid(G2frame.dataDisplay)
5193    G2frame.dataDisplay.gridList.append(drawAtoms)
5194    G2frame.dataDisplay.AddPage(drawAtoms,'Draw Atoms')
5195    Pages.append('Draw Atoms')
5196    RigidBodies = wx.ScrolledWindow(G2frame.dataDisplay)
5197    G2frame.dataDisplay.AddPage(RigidBodies,'RB Models')
5198    Pages.append('RB Models')
5199    MapPeaks = G2gd.GSGrid(G2frame.dataDisplay)
5200    G2frame.dataDisplay.gridList.append(MapPeaks)   
5201    G2frame.dataDisplay.AddPage(MapPeaks,'Map peaks')
5202    Pages.append('Map peaks')
5203    MCSA = wx.ScrolledWindow(G2frame.dataDisplay)
5204    G2frame.dataDisplay.AddPage(MCSA,'MC/SA')
5205    Pages.append('MC/SA')
5206    Texture = wx.ScrolledWindow(G2frame.dataDisplay)
5207    G2frame.dataDisplay.AddPage(Texture,'Texture')
5208    Pages.append('Texture')
5209    G2frame.PawleyRefl = G2gd.GSGrid(G2frame.dataDisplay)
5210    G2frame.dataDisplay.gridList.append(G2frame.PawleyRefl)
5211    G2frame.dataDisplay.AddPage(G2frame.PawleyRefl,'Pawley reflections')
5212    Pages.append('Pawley reflections')
5213   
5214    G2frame.dataDisplay.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CHANGED, OnPageChanged)
5215    SetupGeneral()   
5216    GeneralData = data['General']
5217    if oldPage is None:
5218        ChangePage(0)
5219    elif oldPage:
5220        G2frame.dataDisplay.SetSelection(oldPage)
5221    else:
5222        ChangePage(0)
Note: See TracBrowser for help on using the repository browser.