source: trunk/GSASIIpwdGUI.py @ 2499

Last change on this file since 2499 was 2499, checked in by vondreele, 5 years ago

move setting of G2frame.HKL from MakeReflectionTable? to ShowReflTable?; makes reflection tic mark tool tip match selected reflection list
work on Mag moment derivs.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 243.2 KB
Line 
1# -*- coding: utf-8 -*-
2#GSASIIpwdGUI - powder data display routines
3########### SVN repository information ###################
4# $Date: 2016-10-20 16:27:37 +0000 (Thu, 20 Oct 2016) $
5# $Author: vondreele $
6# $Revision: 2499 $
7# $URL: trunk/GSASIIpwdGUI.py $
8# $Id: GSASIIpwdGUI.py 2499 2016-10-20 16:27:37Z vondreele $
9########### SVN repository information ###################
10'''
11*GSASIIpwdGUI: Powder Pattern GUI routines*
12-------------------------------------------
13
14Used to define GUI controls for the routines that interact
15with the powder histogram (PWDR) data tree items.
16
17'''
18import sys
19import os.path
20import wx
21import wx.grid as wg
22import wx.lib.scrolledpanel as wxscroll
23import numpy as np
24import numpy.ma as ma
25import math
26import time
27import copy
28import random as ran
29import cPickle
30import scipy.interpolate as si
31import GSASIIpath
32GSASIIpath.SetVersionNumber("$Revision: 2499 $")
33import GSASIImath as G2mth
34import GSASIIpwd as G2pwd
35import GSASIIIO as G2IO
36import GSASIIlattice as G2lat
37import GSASIIspc as G2spc
38import GSASIIindex as G2indx
39import GSASIIplot as G2plt
40import GSASIIgrid as G2gd
41import GSASIIctrls as G2G
42import GSASIIElemGUI as G2elemGUI
43import GSASIIElem as G2elem
44import GSASIIsasd as G2sasd
45import GSASIIexprGUI as G2exG
46VERY_LIGHT_GREY = wx.Colour(235,235,235)
47WACV = wx.ALIGN_CENTER_VERTICAL
48Pwr10 = unichr(0x0b9)+unichr(0x0b0)
49Pwr20 = unichr(0x0b2)+unichr(0x0b0)
50Pwrm1 = unichr(0x207b)+unichr(0x0b9)
51Pwrm2 = unichr(0x207b)+unichr(0x0b2)
52Pwrm4 = unichr(0x207b)+unichr(0x2074)   #really -d but looks like -4 as a superscript
53# trig functions in degrees
54sind = lambda x: math.sin(x*math.pi/180.)
55tand = lambda x: math.tan(x*math.pi/180.)
56cosd = lambda x: math.cos(x*math.pi/180.)
57asind = lambda x: 180.*math.asin(x)/math.pi
58   
59################################################################################
60###### class definitions
61################################################################################
62
63class RDFDialog(wx.Dialog):
64    def __init__(self,parent):
65        wx.Dialog.__init__(self,parent,-1,'Background radial distribution function',
66            pos=wx.DefaultPosition,style=wx.DEFAULT_DIALOG_STYLE)
67        self.panel = wx.Panel(self)         #just a dummy - gets destroyed in Draw!
68        self.result = {'UseObsCalc':True,'maxR':20.0,'Smooth':'linear'}
69       
70        self.Draw()
71       
72    def Draw(self):
73       
74        def OnUseOC(event):
75            self.result['UseObsCalc'] = not self.result['UseObsCalc']
76           
77        def OnSmCombo(event):
78            self.result['Smooth'] = smCombo.GetValue()
79           
80        def OnMaxR(event):
81            event.Skip()
82            try:
83                val = float(maxR.GetValue())
84                if val <= 0.:
85                    raise ValueError
86            except ValueError:
87                val = self.result['maxR']
88            self.result['maxR'] = val
89            maxR.SetValue('%.1f'%(val))
90       
91        self.panel.Destroy()
92        self.panel = wx.Panel(self)
93        Ind = {}
94        mainSizer = wx.BoxSizer(wx.VERTICAL)
95        mainSizer.Add(wx.StaticText(self.panel,label='Background RDF controls:'),0,WACV)
96        useOC = wx.CheckBox(self.panel,label=' Use obs - calc intensities?')
97        useOC.SetValue(self.result['UseObsCalc'])
98        useOC.Bind(wx.EVT_CHECKBOX,OnUseOC)
99        mainSizer.Add(useOC,0,WACV)
100        dataSizer = wx.BoxSizer(wx.HORIZONTAL)
101        dataSizer.Add(wx.StaticText(self.panel,label=' Smoothing type: '),0,WACV)
102        smChoice = ['linear','nearest',]
103        smCombo = wx.ComboBox(self.panel,value=self.result['Smooth'],choices=smChoice,
104            style=wx.CB_READONLY|wx.CB_DROPDOWN)
105        smCombo.Bind(wx.EVT_COMBOBOX, OnSmCombo)
106        dataSizer.Add(smCombo,0,WACV)
107        dataSizer.Add(wx.StaticText(self.panel,label=' Maximum radial dist.: '),0,WACV)
108        maxR = wx.TextCtrl(self.panel,value='%.1f'%(self.result['maxR']),style=wx.TE_PROCESS_ENTER)
109        maxR.Bind(wx.EVT_TEXT_ENTER,OnMaxR)       
110        maxR.Bind(wx.EVT_KILL_FOCUS,OnMaxR)
111        dataSizer.Add(maxR,0,WACV)
112        mainSizer.Add(dataSizer,0,WACV)
113
114        OkBtn = wx.Button(self.panel,-1,"Ok")
115        OkBtn.Bind(wx.EVT_BUTTON, self.OnOk)
116        cancelBtn = wx.Button(self.panel,-1,"Cancel")
117        cancelBtn.Bind(wx.EVT_BUTTON, self.OnCancel)
118        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
119        btnSizer.Add((20,20),1)
120        btnSizer.Add(OkBtn)
121        btnSizer.Add((20,20),1)
122        btnSizer.Add(cancelBtn)
123        btnSizer.Add((20,20),1)
124       
125        mainSizer.Add(btnSizer,0,wx.EXPAND|wx.BOTTOM|wx.TOP, 10)
126        self.panel.SetSizer(mainSizer)
127        self.panel.Fit()
128        self.Fit()
129       
130    def GetSelection(self):
131        return self.result
132
133    def OnOk(self,event):
134        parent = self.GetParent()
135        parent.Raise()
136        self.EndModal(wx.ID_OK)
137
138    def OnCancel(self,event):
139        parent = self.GetParent()
140        parent.Raise()
141        self.EndModal(wx.ID_CANCEL)
142       
143   
144################################################################################
145##### Setup routines
146################################################################################
147   
148def IsHistogramInAnyPhase(G2frame,histoName):
149    'Needs a doc string'
150    phases = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Phases')
151    if phases:
152        item, cookie = G2frame.PatternTree.GetFirstChild(phases)
153        while item:
154            data = G2frame.PatternTree.GetItemPyData(item)
155            histoList = data['Histograms'].keys()
156            if histoName in histoList:
157                return G2frame.PatternTree.GetItemText(item)
158            item, cookie = G2frame.PatternTree.GetNextChild(phases, cookie)
159        return False
160    else:
161        return False
162
163def SetDefaultSample():
164    'Fills in default items for the Sample dictionary'
165    return {
166        'InstrName':'',
167        'ranId':ran.randint(0,sys.maxint),
168        'Scale':[1.0,True],'Type':'Debye-Scherrer','Absorption':[0.0,False],
169        'DisplaceX':[0.0,False],'DisplaceY':[0.0,False],'Diffuse':[],
170        'Temperature':300.,'Pressure':0.1,'Time':0.0,
171        'FreePrm1':0.,'FreePrm2':0.,'FreePrm3':0.,
172        'Gonio. radius':200.0,
173        'Omega':0.0,'Chi':0.0,'Phi':0.0,'Azimuth':0.0,
174#SASD items
175        'Materials':[{'Name':'vacuum','VolFrac':1.0,},{'Name':'vacuum','VolFrac':0.0,}],
176        'Thick':1.0,'Contrast':[0.0,0.0],       #contrast & anomalous contrast
177        'Trans':1.0,                            #measured transmission
178        'SlitLen':0.0,                          #Slit length - in Q(A-1)
179        }
180def SetupSampleLabels(histName,dataType,histType):
181    '''Setup a list of labels and number formatting for use in
182    labeling sample parameters.
183    :param str histName: Name of histogram, ("PWDR ...")
184    :param str dataType:
185    '''
186    parms = []
187    parms.append(['Scale','Histogram scale factor: ',[10,7]])
188    if 'C' in histType:
189        parms.append(['Gonio. radius','Goniometer radius (mm): ',[10,3]])
190    if 'PWDR' in histName:
191        if dataType == 'Debye-Scherrer':
192            if 'T' in histType:
193                parms += [['Absorption',u'Sample absorption (\xb5\xb7r/l): ',[10,4]],]
194            else:
195                parms += [['DisplaceX',u'Sample X displ. perp. to beam (\xb5m): ',[10,3]],
196                    ['DisplaceY',u'Sample Y displ. || to beam (\xb5m): ',[10,3]],
197                    ['Absorption',u'Sample absorption (\xb5\xb7r): ',[10,4]],]
198        elif dataType == 'Bragg-Brentano':
199            parms += [['Shift',u'Sample displacement(\xb5m): ',[10,4]],
200                ['Transparency',u'Sample transparency(1/\xb5eff, cm): ',[10,3]],
201                ['SurfRoughA','Surface roughness A: ',[10,4]],
202                ['SurfRoughB','Surface roughness B: ',[10,4]]]
203    elif 'SASD' in histName:
204        parms.append(['Thick','Sample thickness (mm)',[10,3]])
205        parms.append(['Trans','Transmission (meas)',[10,3]])
206        parms.append(['SlitLen',u'Slit length (Q,\xc5'+Pwrm1+')',[10,3]])
207    parms.append(['Omega','Goniometer omega:',[10,3]])
208    parms.append(['Chi','Goniometer chi:',[10,3]])
209    parms.append(['Phi','Goniometer phi:',[10,3]])
210    parms.append(['Azimuth','Detector azimuth:',[10,3]])
211    parms.append(['Time','Clock time (s):',[12,3]])
212    parms.append(['Temperature','Sample temperature (K): ',[10,3]])
213    parms.append(['Pressure','Sample pressure (MPa): ',[10,3]])
214    return parms
215
216def SetDefaultSASDModel():
217    'Fills in default items for the SASD Models dictionary'   
218    return {'Back':[0.0,False],'Size':{'MinDiam':50,'MaxDiam':10000,'Nbins':100,'logBins':True,'Method':'MaxEnt','Distribution':[],
219        'Shape':['Spheroid',1.0],'MaxEnt':{'Niter':100,'Precision':0.01,'Sky':-3},
220        'IPG':{'Niter':100,'Approach':0.8,'Power':-1},'Reg':{},},           
221        'Particle':{'Matrix':{'Name':'vacuum','VolFrac':[0.0,False]},'Levels':[],},
222        'Current':'Size dist.','BackFile':'',
223        }
224       
225def SetDefaultSubstances():
226    'Fills in default items for the SASD Substances dictionary'
227    return {'Substances':{'vacuum':{'Elements':{},'Volume':1.0,'Density':0.0,'Scatt density':0.0}}}
228
229def GetHistsLikeSelected(G2frame):
230    '''Get the histograms that match the current selected one:
231    The histogram prefix and data type (PXC etc.), the number of
232    wavelengths and the instrument geometry (Debye-Scherrer etc.)
233    must all match. The current histogram is not included in the list.
234
235    :param wx.Frame G2frame: pointer to main GSAS-II data tree
236    '''
237    histList = []
238    inst,inst2 = G2frame.PatternTree.GetItemPyData(
239        G2gd.GetPatternTreeItemId(
240            G2frame,G2frame.PatternId, 'Instrument Parameters')
241        )
242    hType = inst['Type'][0]
243    if 'Lam1' in inst:
244        hLam = 2
245    elif 'Lam' in inst:
246        hLam = 1
247    else:
248        hLam = 0
249    sample = G2frame.PatternTree.GetItemPyData(
250        G2gd.GetPatternTreeItemId(
251            G2frame,G2frame.PatternId, 'Sample Parameters')
252        )
253    hGeom = sample.get('Type')
254    hstName = G2frame.PatternTree.GetItemText(G2frame.PatternId)
255    hPrefix = hstName.split()[0]+' '
256    # cycle through tree looking for items that match the above
257    item, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)       
258    while item:
259        name = G2frame.PatternTree.GetItemText(item)
260        if name.startswith(hPrefix) and name != hstName:
261            cGeom,cType,cLam, = '?','?',-1
262            subitem, subcookie = G2frame.PatternTree.GetFirstChild(item)
263            while subitem:
264                subname = G2frame.PatternTree.GetItemText(subitem)
265                if subname == 'Sample Parameters':
266                    sample = G2frame.PatternTree.GetItemPyData(subitem)
267                    cGeom = sample.get('Type')
268                elif subname == 'Instrument Parameters':
269                    inst,inst2 = G2frame.PatternTree.GetItemPyData(subitem)
270                    cType = inst['Type'][0]
271                    if 'Lam1' in inst:
272                        cLam = 2
273                    elif 'Lam' in inst:
274                        cLam = 1
275                    else:
276                        cLam = 0
277                subitem, subcookie = G2frame.PatternTree.GetNextChild(item, subcookie)
278            if cLam == hLam and cType == hType and cGeom == hGeom:
279                if name not in histList: histList.append(name)
280        item, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)
281    return histList
282
283def SetCopyNames(histName,dataType,addNames=[]):
284    '''Determine the items in the sample parameters that should be copied,
285    depending on the histogram type and the instrument type.
286    '''
287    copyNames = ['Scale',]
288    histType = 'HKLF'
289    if 'PWDR' in histName:
290        histType = 'PWDR'
291        if 'Debye' in dataType:
292            copyNames += ['DisplaceX','DisplaceY','Absorption']
293        else:       #Bragg-Brentano
294            copyNames += ['Shift','Transparency','SurfRoughA','SurfRoughB']
295    elif 'SASD' in histName:
296        histType = 'SASD'
297        copyNames += ['Materials','Thick',]
298    if len(addNames):
299        copyNames += addNames
300    return histType,copyNames
301   
302def CopyPlotCtrls(G2frame):
303    '''Global copy: Copy plot controls from current histogram to others.
304    '''
305    hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
306    histList = GetHistsLikeSelected(G2frame)
307    if not histList:
308        G2frame.ErrorDialog('No match','No other histograms match '+hst,G2frame.dataFrame)
309        return
310    sourceData = G2frame.PatternTree.GetItemPyData(G2frame.PatternId)
311   
312    if 'Offset' not in sourceData[0]:    #patch for old data
313        sourceData[0].update({'Offset':[0.0,0.0],'delOffset':0.02,'refOffset':-1.0,
314            'refDelt':0.01,'qPlot':False,'dPlot':False,'sqrtPlot':False})
315        G2frame.PatternTree.SetItemPyData(G2frame.PatternId,sourceData)
316       
317    dlg = G2G.G2MultiChoiceDialog(
318        G2frame.dataFrame, 
319        'Copy plot controls from\n'+str(hst[5:])+' to...',
320        'Copy plot controls', histList)
321    results = []
322    try:
323        if dlg.ShowModal() == wx.ID_OK:
324            results = dlg.GetSelections()
325    finally:
326        dlg.Destroy()
327    copyList = []
328    for i in results: 
329        copyList.append(histList[i])
330
331    keys = ['Offset','delOffset','refOffset','refDelt','qPlot','dPlot','sqrtPlot']
332    source = dict(zip(keys,[sourceData[0][item] for item in keys]))
333    for hist in copyList:
334        Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,hist)
335        data = G2frame.PatternTree.GetItemPyData(Id)
336        data[0].update(source)
337        G2frame.PatternTree.SetItemPyData(Id,data)
338    print 'Copy of plot controls successful'
339
340def CopySelectedHistItems(G2frame):
341    '''Global copy: Copy items from current histogram to others.
342    '''
343    hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
344    histList = GetHistsLikeSelected(G2frame)
345    if not histList:
346        G2frame.ErrorDialog('No match','No other histograms match '+hst,G2frame.dataFrame)
347        return
348    choices = ['Limits','Background','Instrument Parameters','Sample Parameters']
349    dlg = G2G.G2MultiChoiceDialog(
350        G2frame.dataFrame, 
351        'Copy which histogram sections from\n'+str(hst[5:]),
352        'Select copy sections', choices, filterBox=False)
353    dlg.SetSelections(range(len(choices)))
354    choiceList = []
355    if dlg.ShowModal() == wx.ID_OK:
356        choiceList = [choices[i] for i in dlg.GetSelections()]
357    if not choiceList: return
358   
359    dlg = G2G.G2MultiChoiceDialog(
360        G2frame.dataFrame, 
361        'Copy parameters from\n'+str(hst[5:])+' to...',
362        'Copy parameters', histList)
363    results = []
364    try:
365        if dlg.ShowModal() == wx.ID_OK:
366            results = dlg.GetSelections()
367    finally:
368        dlg.Destroy()
369    copyList = []
370    for i in results: 
371        copyList.append(histList[i])
372
373    if 'Limits' in choiceList: # Limits
374        data = G2frame.PatternTree.GetItemPyData(
375            G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId,'Limits'))
376        for item in copyList:
377            Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
378            G2frame.PatternTree.SetItemPyData(
379                G2gd.GetPatternTreeItemId(G2frame,Id,'Limits'),
380                copy.deepcopy(data))
381    if 'Background' in choiceList:  # Background
382        data = G2frame.PatternTree.GetItemPyData(
383            G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId,'Background'))
384        for item in copyList:
385            Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
386            G2frame.PatternTree.SetItemPyData(
387                G2gd.GetPatternTreeItemId(G2frame,Id,'Background'),
388                copy.deepcopy(data))
389    if 'Instrument Parameters' in choiceList:  # Instrument Parameters
390        # for now all items in Inst. parms are copied
391        data,data1 = G2frame.PatternTree.GetItemPyData(
392            G2gd.GetPatternTreeItemId(
393                G2frame,G2frame.PatternId,'Instrument Parameters'))
394        for item in copyList:
395            Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
396            G2frame.PatternTree.GetItemPyData(
397                G2gd.GetPatternTreeItemId(G2frame,Id,'Instrument Parameters')
398                )[0].update(copy.deepcopy(data))
399            G2frame.PatternTree.GetItemPyData(
400                G2gd.GetPatternTreeItemId(G2frame,Id,'Instrument Parameters')
401                )[1].update(copy.deepcopy(data1))
402    if 'Sample Parameters' in choiceList:  # Sample Parameters
403        data = G2frame.PatternTree.GetItemPyData(
404            G2gd.GetPatternTreeItemId(
405                G2frame,G2frame.PatternId,'Sample Parameters'))
406        # selects items to be copied
407        histType,copyNames = SetCopyNames(hst,data['Type'],
408            addNames = ['Omega','Chi','Phi','Gonio. radius','InstrName'])
409        copyDict = {parm:data[parm] for parm in copyNames}
410        for item in copyList:
411            Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
412            G2frame.PatternTree.GetItemPyData(
413                G2gd.GetPatternTreeItemId(G2frame,Id,'Sample Parameters')
414                ).update(copy.deepcopy(copyDict))
415                         
416################################################################################
417#####  Powder Peaks
418################################################################################           
419       
420def UpdatePeakGrid(G2frame, data):
421    '''respond to selection of PWDR powder peaks data tree item.
422    '''
423    if G2frame.dataDisplay:
424        G2frame.dataFrame.Clear()
425       
426    def OnAutoSearch(event):
427        PatternId = G2frame.PatternId
428        PickId = G2frame.PickId
429        limits = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Limits'))[1]
430        inst,inst2 = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Instrument Parameters'))
431        profile = G2frame.PatternTree.GetItemPyData(PatternId)[1]
432        x0 = profile[0]
433        iBeg = np.searchsorted(x0,limits[0])
434        iFin = np.searchsorted(x0,limits[1])
435        x = x0[iBeg:iFin]
436        y0 = profile[1][iBeg:iFin]
437        y1 = copy.copy(y0)
438        ysig = 0.5*np.std(y1)
439        offset = [-1,1]
440        ymask = ma.array(y0,mask=(y0<ysig))
441        for off in offset:
442            ymask = ma.array(ymask,mask=(ymask-np.roll(y0,off)<=0.))
443        indx = ymask.nonzero()
444        mags = ymask[indx]
445        poss = x[indx]
446        refs = zip(poss,mags)
447        if 'C' in Inst['Type'][0]:   
448            refs = G2mth.sortArray(refs,0,reverse=True)     #small 2-Thetas first
449        else:   #'T'OF
450            refs = G2mth.sortArray(refs,0,reverse=False)    #big TOFs first
451        for i,ref1 in enumerate(refs):      #reject picks closer than 1 FWHM
452            for ref2 in refs[i+1:]:
453                if abs(ref2[0]-ref1[0]) < G2pwd.getFWHM(ref1[0],inst):
454                    del(refs[i])
455        if 'C' in Inst['Type'][0]:   
456            refs = G2mth.sortArray(refs,1,reverse=True)
457        else:   #'T'OF
458            refs = G2mth.sortArray(refs,1,reverse=False)
459        for pos,mag in refs:
460            data['peaks'].append(G2mth.setPeakparms(inst,inst2,pos,mag))
461        UpdatePeakGrid(G2frame,data)
462        G2plt.PlotPatterns(G2frame,plotType='PWDR')
463       
464    def OnCopyPeaks(event):
465        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
466        histList = GetHistsLikeSelected(G2frame)
467        if not histList:
468            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
469            return
470        copyList = []
471        dlg = G2G.G2MultiChoiceDialog(
472            G2frame.dataFrame, 
473            'Copy peak list from\n'+str(hst[5:])+' to...',
474            'Copy peaks', histList)
475        try:
476            if dlg.ShowModal() == wx.ID_OK:
477                for i in dlg.GetSelections():
478                    copyList.append(histList[i])
479        finally:
480            dlg.Destroy()
481        for item in copyList:
482            Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
483            G2frame.PatternTree.SetItemPyData(
484                G2gd.GetPatternTreeItemId(G2frame,Id,'Peak List'),copy.deepcopy(data))
485   
486    def OnUnDo(event):
487        DoUnDo()
488        G2frame.dataFrame.UnDo.Enable(False)
489       
490    def DoUnDo():
491        print 'Undo last refinement'
492        file = open(G2frame.undofile,'rb')
493        PatternId = G2frame.PatternId
494        for item in ['Background','Instrument Parameters','Peak List']:
495            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, item),cPickle.load(file))
496            if G2frame.dataDisplay.GetName() == item:
497                if item == 'Background':
498                    UpdateBackground(G2frame,G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, item)))
499                elif item == 'Instrument Parameters':
500                    UpdateInstrumentGrid(G2frame,G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, item)))
501                elif item == 'Peak List':
502                    UpdatePeakGrid(G2frame,G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, item)))
503            print item,' recovered'
504        file.close()
505       
506    def SaveState():
507        G2frame.undofile = os.path.join(G2frame.dirname,'GSASII.save')
508        file = open(G2frame.undofile,'wb')
509        PatternId = G2frame.PatternId
510        for item in ['Background','Instrument Parameters','Peak List']:
511            cPickle.dump(G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId,item)),file,1)
512        file.close()
513        G2frame.dataFrame.UnDo.Enable(True)
514       
515    def OnLSQPeakFit(event):
516        if not G2frame.GSASprojectfile:            #force a save of the gpx file so SaveState can write in the same directory
517            G2frame.OnFileSaveas(event)
518        OnPeakFit('LSQ')
519       
520    def OnOneCycle(event):
521        OnPeakFit('LSQ',oneCycle=True)
522       
523    def OnSeqPeakFit(event):
524        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
525        histList = GetHistsLikeSelected(G2frame)
526        if not histList:
527            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
528            return
529        sel = []
530        dlg = G2G.G2MultiChoiceDialog(G2frame.dataFrame, 'Sequential peak fits',
531             'Select dataset to include',histList)
532        dlg.SetSelections(sel)
533        names = []
534        if dlg.ShowModal() == wx.ID_OK:
535            for sel in dlg.GetSelections():
536                names.append(histList[sel])
537        dlg.Destroy()
538        if not names:
539            return
540        SeqResult = {}
541        Reverse = False
542        CopyForward = False
543        choice = ['Reverse sequence','Copy from prev.',]
544        dlg = wx.MultiChoiceDialog(G2frame.dataFrame,'Sequential controls','Select controls',choice)
545        if dlg.ShowModal() == wx.ID_OK:
546            for sel in dlg.GetSelections():
547                if sel:
548                    CopyForward = True
549                else:
550                    Reverse = True
551        dlg.Destroy()
552        dlg = wx.ProgressDialog('Sequential peak fit','Data set name = '+names[0],len(names), 
553            style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE|wx.PD_REMAINING_TIME|wx.PD_CAN_ABORT)
554        Controls = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.root, 'Controls'))
555        controls = {'deriv type':'analytic','min dM/M':0.0001,}
556        Controls['ShowCell'] = False
557        print 'Peak Fitting with '+controls['deriv type']+' derivatives:'
558        oneCycle = False
559        FitPgm = 'LSQ'
560        prevVaryList = []
561        Names = []
562        if Reverse:
563            names.reverse()
564        try:
565            for i,name in enumerate(names):
566                print ' Sequential fit for ',name
567                GoOn = dlg.Update(i,newmsg='Data set name = '+name)[0]
568                if not GoOn:
569                    break
570                PatternId =  G2gd.GetPatternTreeItemId(G2frame,G2frame.root,name)
571                if i and CopyForward:
572                    G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Peak List'),copy.deepcopy(peaks))
573                    prevVaryList = varyList[:]
574                peaks = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Peak List'))
575                background = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Background'))
576                limits = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Limits'))[1]
577                inst,inst2 = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Instrument Parameters'))
578                data = G2frame.PatternTree.GetItemPyData(PatternId)[1]
579                wx.BeginBusyCursor()
580                dlg2 = wx.ProgressDialog('Residual','Peak fit Rwp = ',101.0, 
581                    style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE|wx.PD_REMAINING_TIME|wx.PD_CAN_ABORT)
582                screenSize = wx.ClientDisplayRect()
583                Size = dlg.GetSize()
584                if 50 < Size[0] < 500: # sanity check on size, since this fails w/Win & wx3.0
585                    dlg2.SetSize((int(Size[0]*1.2),Size[1])) # increase size a bit along x
586                    dlg2.SetPosition(wx.Point(screenSize[2]-Size[0]-305,screenSize[1]+5))
587                try:
588                    peaks['sigDict'],result,sig,Rvals,varyList,parmDict,fullvaryList,badVary = G2pwd.DoPeakFit(FitPgm,peaks['peaks'],
589                        background,limits,inst,inst2,data,prevVaryList,oneCycle,controls,dlg2)
590                finally:
591                    dlg2.Destroy()
592                if len(result[0]) != len(fullvaryList):
593                    print ' ***** Sequential peak fit stopped at '+name+' *****'
594                    break
595                else:
596                    Names.append(name)   
597                    G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Peak List'),copy.deepcopy(peaks))
598                    SeqResult[name] = {'variables':result[0],'varyList':varyList,'sig':sig,'Rvals':Rvals,
599                        'covMatrix':np.eye(len(result[0])),'title':name,'parmDict':parmDict,
600                        'fullVary':fullvaryList,'badVary':badVary}
601            dlg.Destroy()
602            print ' ***** Sequential peak fit successful *****'
603        finally:
604            wx.EndBusyCursor()
605        if Reverse:
606            Names.reverse()
607        SeqResult['histNames'] = Names
608        Id =  G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Sequential peak fit results')
609        if Id:
610            G2frame.PatternTree.SetItemPyData(Id,SeqResult)
611        else:
612            Id = G2frame.PatternTree.AppendItem(parent=G2frame.root,text='Sequential peak fit results')
613            G2frame.PatternTree.SetItemPyData(Id,SeqResult)
614        G2frame.PatternTree.SelectItem(Id)
615       
616    def OnClearPeaks(event):
617        dlg = wx.MessageDialog(G2frame,'Delete all peaks?','Clear peak list',wx.OK|wx.CANCEL)
618        try:
619            if dlg.ShowModal() == wx.ID_OK:
620                peaks = {'peaks':[],'sigDict':{}}
621        finally:
622            dlg.Destroy()
623        UpdatePeakGrid(G2frame,peaks)
624        G2plt.PlotPatterns(G2frame,plotType='PWDR')
625       
626    def OnPeakFit(FitPgm,oneCycle=False):
627        SaveState()
628        controls = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.root, 'Controls'))
629        if not controls:
630            controls = {'deriv type':'analytic','min dM/M':0.0001,}     #fill in defaults if needed
631        print 'Peak Fitting with '+controls['deriv type']+' derivatives:'
632        PatternId = G2frame.PatternId
633        PickId = G2frame.PickId
634        peaks = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Peak List'))
635        if not peaks:
636            G2frame.ErrorDialog('No peaks!','Nothing to fit!')
637            return
638        background = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Background'))
639        limits = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Limits'))[1]
640        inst,inst2 = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Instrument Parameters'))
641        data = G2frame.PatternTree.GetItemPyData(PatternId)[1]
642        wx.BeginBusyCursor()
643        dlg = wx.ProgressDialog('Residual','Peak fit Rwp = ',101.0, 
644            style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE|wx.PD_REMAINING_TIME|wx.PD_CAN_ABORT)
645        screenSize = wx.ClientDisplayRect()
646        Size = dlg.GetSize()
647        if 50 < Size[0] < 500: # sanity check on size, since this fails w/Win & wx3.0
648            dlg.SetSize((int(Size[0]*1.2),Size[1])) # increase size a bit along x
649            dlg.SetPosition(wx.Point(screenSize[2]-Size[0]-305,screenSize[1]+5))
650        try:
651            peaks['sigDict'] = G2pwd.DoPeakFit(FitPgm,peaks['peaks'],background,limits,inst,inst2,data,[],oneCycle,controls,dlg)[0]
652        finally:
653            wx.EndBusyCursor()   
654        G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Peak List'),copy.copy(peaks))
655        UpdatePeakGrid(G2frame,copy.copy(peaks))
656        G2plt.PlotPatterns(G2frame,plotType='PWDR')
657        print 'finished'
658        return
659       
660    def OnResetSigGam(event):
661        PatternId = G2frame.PatternId
662        PickId = G2frame.PickId
663        Inst,Inst2 = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Instrument Parameters'))
664        peaks = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Peak List'))
665        if not peaks['peaks']:
666            G2frame.ErrorDialog('No peaks!','Nothing to do!')
667            return
668        newpeaks = {'peaks':[],'sigDict':{}}
669        for peak in peaks['peaks']:
670            newpeaks['peaks'].append(G2mth.setPeakparms(Inst,Inst2,peak[0],peak[2]))
671        G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Peak List'),newpeaks)
672        UpdatePeakGrid(G2frame,newpeaks)
673               
674    def RefreshPeakGrid(event):
675        r,c =  event.GetRow(),event.GetCol()
676       
677        event.StopPropagation()
678        data['peaks'] = G2frame.PeakTable.GetData()
679        T = []
680        for peak in data['peaks']:T.append(peak[0])
681        D = dict(zip(T,data['peaks']))
682        T.sort()
683        X = []
684        for key in T: X.append(D[key])
685        data['peaks'] = X       
686       
687    def setBackgroundColors():
688       for r in range(G2frame.dataDisplay.GetNumberRows()):
689           for c in range(G2frame.dataDisplay.GetNumberCols()):
690               if G2frame.dataDisplay.GetColLabelValue(c) in ['position','intensity','alpha','beta','sigma','gamma']:
691                   if float(G2frame.dataDisplay.GetCellValue(r,c)) < 0.:
692                       G2frame.dataDisplay.SetCellBackgroundColour(r,c,wx.RED)
693                   else:
694                       G2frame.dataDisplay.SetCellBackgroundColour(r,c,wx.WHITE)
695                                                 
696    def KeyEditPeakGrid(event):
697        rowList = G2frame.dataDisplay.GetSelectedRows()
698        colList = G2frame.dataDisplay.GetSelectedCols()
699        selectList = G2frame.dataDisplay.GetSelectedCells()
700        data = G2frame.PatternTree.GetItemPyData(G2frame.PickId)
701        if event.GetKeyCode() == wx.WXK_RETURN:
702            event.Skip(True)
703        elif event.GetKeyCode() == wx.WXK_CONTROL:
704            event.Skip(True)
705        elif event.GetKeyCode() == wx.WXK_SHIFT:
706            event.Skip(True)
707        elif rowList:
708            G2frame.dataDisplay.ClearSelection()
709            if event.GetKeyCode() == wx.WXK_DELETE:
710                G2frame.dataDisplay.ClearGrid()
711                rowList.sort()
712                rowList.reverse()
713                nDel = 0
714                for row in rowList:
715                    G2frame.PeakTable.DeleteRow(row)
716                    nDel += 1
717                if nDel:
718                    msg = wg.GridTableMessage(G2frame.PeakTable, 
719                        wg.GRIDTABLE_NOTIFY_ROWS_DELETED,0,nDel)
720                    G2frame.dataDisplay.ProcessTableMessage(msg)
721                data['peaks'] = G2frame.PeakTable.GetData()[:-nDel]
722                G2frame.PatternTree.SetItemPyData(G2frame.PickId,data)
723                G2frame.dataDisplay.ForceRefresh()
724                setBackgroundColors()
725                       
726        elif colList:
727            G2frame.dataDisplay.ClearSelection()
728            key = event.GetKeyCode()
729            for col in colList:
730                if G2frame.PeakTable.GetTypeName(0,col) == wg.GRID_VALUE_BOOL:
731                    if key == 89: #'Y'
732                        for row in range(G2frame.PeakTable.GetNumberRows()): data['peaks'][row][col]=True
733                    elif key == 78:  #'N'
734                        for row in range(G2frame.PeakTable.GetNumberRows()): data['peaks'][row][col]=False
735        elif selectList:
736            G2frame.dataDisplay.ClearSelection()
737            key = event.GetKeyCode()
738            for row,col in selectList:
739                if G2frame.PeakTable.GetTypeName(row,col) == wg.GRID_VALUE_BOOL:
740                    if key == 89: #'Y'
741                        data['peaks'][row][col]=True
742                    elif key == 78:  #'N'
743                        data['peaks'][row][col]=False
744        G2plt.PlotPatterns(G2frame,plotType='PWDR')
745           
746    G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.PeakMenu)
747    if not G2frame.dataFrame.GetStatusBar():
748        Status = G2frame.dataFrame.CreateStatusBar()
749    Status.SetStatusText('Global refine: select refine column & press Y or N')
750    G2frame.Bind(wx.EVT_MENU, OnAutoSearch, id=G2gd.wxID_AUTOSEARCH)
751    G2frame.Bind(wx.EVT_MENU, OnCopyPeaks, id=G2gd.wxID_PEAKSCOPY)
752    G2frame.Bind(wx.EVT_MENU, OnUnDo, id=G2gd.wxID_UNDO)
753    G2frame.Bind(wx.EVT_MENU, OnLSQPeakFit, id=G2gd.wxID_LSQPEAKFIT)
754    G2frame.Bind(wx.EVT_MENU, OnOneCycle, id=G2gd.wxID_LSQONECYCLE)
755    G2frame.Bind(wx.EVT_MENU, OnSeqPeakFit, id=G2gd.wxID_SEQPEAKFIT)
756    G2frame.Bind(wx.EVT_MENU, OnClearPeaks, id=G2gd.wxID_CLEARPEAKS)
757    G2frame.Bind(wx.EVT_MENU, OnResetSigGam, id=G2gd.wxID_RESETSIGGAM)
758    if data['peaks']:
759        G2frame.dataFrame.AutoSearch.Enable(False)
760        G2frame.dataFrame.PeakCopy.Enable(True)
761        G2frame.dataFrame.PeakFit.Enable(True)
762        G2frame.dataFrame.PFOneCycle.Enable(True)
763        G2frame.dataFrame.SeqPeakFit.Enable(True)
764    else:
765        G2frame.dataFrame.PeakFit.Enable(False)
766        G2frame.dataFrame.PeakCopy.Enable(False)
767        G2frame.dataFrame.PFOneCycle.Enable(False)
768        G2frame.dataFrame.AutoSearch.Enable(True)
769        G2frame.dataFrame.SeqPeakFit.Enable(False)
770    G2frame.PickTable = []
771    rowLabels = []
772    PatternId = G2frame.PatternId
773    Inst = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Instrument Parameters'))[0]
774    for i in range(len(data['peaks'])): rowLabels.append(str(i+1))
775    if 'C' in Inst['Type'][0]:
776        colLabels = ['position','refine','intensity','refine','sigma','refine','gamma','refine']
777        Types = [wg.GRID_VALUE_FLOAT+':10,4',wg.GRID_VALUE_BOOL,
778            wg.GRID_VALUE_FLOAT+':10,1',wg.GRID_VALUE_BOOL,
779            wg.GRID_VALUE_FLOAT+':10,5',wg.GRID_VALUE_BOOL,
780            wg.GRID_VALUE_FLOAT+':10,5',wg.GRID_VALUE_BOOL]
781    else:
782        colLabels = ['position','refine','intensity','refine','alpha','refine',
783            'beta','refine','sigma','refine','gamma','refine']
784        Types = [wg.GRID_VALUE_FLOAT+':10,1',wg.GRID_VALUE_BOOL,
785            wg.GRID_VALUE_FLOAT+':10,4',wg.GRID_VALUE_BOOL,
786            wg.GRID_VALUE_FLOAT+':10,4',wg.GRID_VALUE_BOOL,
787            wg.GRID_VALUE_FLOAT+':10,5',wg.GRID_VALUE_BOOL,
788            wg.GRID_VALUE_FLOAT+':10,5',wg.GRID_VALUE_BOOL,
789            wg.GRID_VALUE_FLOAT+':10,5',wg.GRID_VALUE_BOOL]
790    T = []
791    for peak in data['peaks']:
792        T.append(peak[0])
793    D = dict(zip(T,data['peaks']))
794    T.sort()
795    if 'T' in Inst['Type'][0]:  #want big TOF's first
796        T.reverse()
797    X = []
798    for key in T: X.append(D[key])
799    data['peaks'] = X
800    G2frame.PatternTree.SetItemPyData(G2frame.PickId,data)
801    G2frame.PeakTable = G2G.Table(data['peaks'],rowLabels=rowLabels,colLabels=colLabels,types=Types)
802    G2frame.dataFrame.SetLabel('Peak List')
803    G2frame.dataDisplay = G2G.GSGrid(parent=G2frame.dataFrame)
804    G2frame.dataDisplay.SetTable(G2frame.PeakTable, True)
805    setBackgroundColors()                         
806    G2frame.dataDisplay.Bind(wg.EVT_GRID_CELL_CHANGE, RefreshPeakGrid)
807    G2frame.dataDisplay.Bind(wx.EVT_KEY_DOWN, KeyEditPeakGrid)
808    G2frame.dataDisplay.SetMargins(0,0)
809    G2frame.dataDisplay.AutoSizeColumns(False)
810    G2frame.dataFrame.setSizePosLeft([535,350])
811    G2frame.dataFrame.SendSizeEvent()
812       
813################################################################################
814#####  Background
815################################################################################           
816       
817def UpdateBackground(G2frame,data):
818    '''respond to selection of PWDR background data tree item.
819    '''
820    if len(data) < 2:       #add Debye diffuse & peaks scattering here
821        data.append({'nDebye':0,'debyeTerms':[],'nPeaks':0,'peaksList':[]})
822    if 'nPeaks' not in data[1]:
823        data[1].update({'nPeaks':0,'peaksList':[]})
824    ValObj = {}
825   
826    def OnBackFlagCopy(event):
827        flag = data[0][1]
828        backDict = data[-1]
829        if backDict['nDebye']:
830            DBflags = []
831            for term in backDict['debyeTerms']:
832                DBflags.append(term[1::2])
833        if backDict['nPeaks']:
834            PKflags = []
835            for term in backDict['peaksList']:
836                PKflags.append(term[1::2])           
837        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
838        histList = GetHistsLikeSelected(G2frame)
839        if not histList:
840            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
841            return
842        dlg = G2G.G2MultiChoiceDialog(
843            G2frame.dataFrame, 
844            'Copy bkg ref. flags from\n'+str(hst[5:])+' to...',
845            'Copy bkg flags', histList)
846        copyList = []
847        try:
848            if dlg.ShowModal() == wx.ID_OK:
849                for i in dlg.GetSelections(): 
850                    copyList.append(histList[i])
851        finally:
852            dlg.Destroy()
853        for item in copyList:
854            Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
855            backData = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Background'))
856            backData[0][1] = copy.copy(flag)
857            bkDict = backData[-1]
858            if bkDict['nDebye'] == backDict['nDebye']:
859                for i,term in enumerate(bkDict['debyeTerms']):
860                    term[1::2] = copy.copy(DBflags[i])
861            if bkDict['nPeaks'] == backDict['nPeaks']:
862                for i,term in enumerate(bkDict['peaksList']):
863                    term[1::2] = copy.copy(PKflags[i])                   
864           
865    def OnBackCopy(event):
866        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
867        histList = GetHistsLikeSelected(G2frame)
868        if not histList:
869            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
870            return
871        copyList = []
872        dlg = G2G.G2MultiChoiceDialog(
873            G2frame.dataFrame, 
874            'Copy bkg params from\n'+str(hst[5:])+' to...',
875            'Copy parameters', histList)
876        try:
877            if dlg.ShowModal() == wx.ID_OK:
878                for i in dlg.GetSelections():
879                    copyList.append(histList[i])
880        finally:
881            dlg.Destroy()
882        for item in copyList:
883            Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
884            G2frame.PatternTree.SetItemPyData(
885                G2gd.GetPatternTreeItemId(G2frame,Id,'Background'),copy.copy(data))
886
887    def OnBkgFit(event):
888        def SetInstParms(Inst):
889            dataType = Inst['Type'][0]
890            insVary = []
891            insNames = []
892            insVals = []
893            for parm in Inst:
894                insNames.append(parm)
895                insVals.append(Inst[parm][1])
896                if parm in ['U','V','W','X','Y','SH/L','I(L2)/I(L1)','alpha',
897                    'beta-0','beta-1','beta-q','sig-0','sig-1','sig-2','sig-q',] and Inst[parm][2]:
898                        insVary.append(parm)
899            instDict = dict(zip(insNames,insVals))
900            instDict['X'] = max(instDict['X'],0.01)
901            instDict['Y'] = max(instDict['Y'],0.01)
902            if 'SH/L' in instDict:
903                instDict['SH/L'] = max(instDict['SH/L'],0.002)
904            return dataType,instDict,insVary
905   
906        PatternId = G2frame.PatternId       
907        controls = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.root, 'Controls'))
908        background = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Background'))
909        limits = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Limits'))[1]
910        inst,inst2 = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Instrument Parameters'))
911        # sort the points for convenience and then separate them; extend the range if needed
912        background[1]['FixedPoints'] = sorted(background[1]['FixedPoints'],key=lambda pair:pair[0])       
913        X = [x for x,y in background[1]['FixedPoints']]
914        Y = [y for x,y in background[1]['FixedPoints']]
915        if X[0] > limits[0]:
916            X = [limits[0]] + X
917            Y = [Y[0]] + Y
918        if X[-1] < limits[1]:
919            X += [limits[1]]
920            Y += [Y[-1]]
921        # interpolate the fixed points onto the grid of data points within limits
922        pwddata = G2frame.PatternTree.GetItemPyData(PatternId)[1]
923        xBeg = np.searchsorted(pwddata[0],limits[0])
924        xFin = np.searchsorted(pwddata[0],limits[1])
925        xdata = pwddata[0][xBeg:xFin]
926        ydata = si.interp1d(X,Y)(ma.getdata(xdata))
927        #GSASIIpath.IPyBreak()
928        W = [1]*len(xdata)
929        Z = [0]*len(xdata)
930
931        # load instrument and background params
932        dataType,insDict,insVary = SetInstParms(inst)
933        bakType,bakDict,bakVary = G2pwd.SetBackgroundParms(background)
934        # how many background parameters are refined?
935        if len(bakVary)*1.5 > len(X):
936            msg = ("You are attempting to vary "+str(len(bakVary))+
937                   " background terms with only "+str(len(X))+" background points"+
938                    "\nAdd more points or reduce the number of terms")
939            print msg
940            G2frame.ErrorDialog('Too few points',msg)
941            return
942       
943        wx.BeginBusyCursor()
944        try:
945            G2pwd.DoPeakFit('LSQ',[],background,limits,inst,inst2,
946                np.array((xdata,ydata,W,Z,Z,Z)),bakVary,False,controls)
947        finally:
948            wx.EndBusyCursor()
949        # compute the background values and plot them
950        parmDict = {}
951        bakType,bakDict,bakVary = G2pwd.SetBackgroundParms(background)
952        parmDict.update(bakDict)
953        parmDict.update(insDict)
954        pwddata[3] *= 0
955        pwddata[5] *= 0
956        pwddata[4][xBeg:xFin] = G2pwd.getBackground(
957            '',parmDict,bakType,dataType,xdata)[0]
958        G2plt.PlotPatterns(G2frame,plotType='PWDR')
959        # show the updated background values
960        wx.CallLater(100,UpdateBackground,G2frame,data)
961       
962    def OnBkgClear(event):
963        if 'FixedPoints' not in data[1]:
964            return
965        else:
966            del data[1]['FixedPoints']
967            G2plt.PlotPatterns(G2frame,plotType='PWDR')
968   
969    def OnPeaksMove(event):
970        if not data[1]['nPeaks']:
971            G2frame.ErrorDialog('Error','No peaks to move')
972            return
973        Peaks = {'peaks':[],'sigDict':{}}
974        for peak in data[1]['peaksList']:
975            Peaks['peaks'].append([peak[0],0,peak[2],0,peak[4],0,peak[6],0])
976        G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Peak List'),Peaks)
977       
978    def OnMakeRDF(event):
979        dlg = RDFDialog(G2frame)
980        try:
981            if dlg.ShowModal() == wx.ID_OK:
982                RDFcontrols = dlg.GetSelection()
983            else:
984                return
985        finally:
986            dlg.Destroy()
987        PatternId = G2frame.PatternId       
988        background = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Background'))
989        limits = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Limits'))[1]
990        inst,inst2 = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Instrument Parameters'))
991        pwddata = G2frame.PatternTree.GetItemPyData(PatternId)[1]
992        auxPlot = G2pwd.MakeRDF(RDFcontrols,background,inst,pwddata)
993#        GSASIIpath.IPyBreak()
994        superMinusOne = unichr(0xaf)+unichr(0xb9)
995        for plot in auxPlot:
996            XY = np.array(plot[:2])
997            if plot[2] == 'D(R)':
998                xlabel = r'$R, \AA$'
999                ylabel = r'$D(R), arb. units$'
1000            else:
1001                xlabel = r'$Q,\AA$'+superMinusOne
1002                ylabel = r'$I(Q)$'
1003            G2plt.PlotXY(G2frame,[XY,],Title=plot[2],labelX=xlabel,labelY=ylabel,lines=True)     
1004       
1005    def BackSizer():
1006       
1007        def OnNewType(event):
1008            data[0][0] = bakType.GetValue()
1009           
1010        def OnBakRef(event):
1011            data[0][1] = bakRef.GetValue()
1012           
1013        def OnBakTerms(event):
1014            data[0][2] = int(bakTerms.GetValue())
1015            M = len(data[0])
1016            N = data[0][2]+3
1017            item = data[0]
1018            if N > M:       #add terms
1019                for i in range(M,N): 
1020                    item.append(0.0)
1021            elif N < M:     #delete terms
1022                for i in range(N,M):
1023                    del(item[-1])
1024            G2frame.PatternTree.SetItemPyData(BackId,data)
1025            #wx.CallAfter(UpdateBackground,G2frame,data)
1026            wx.CallLater(100,UpdateBackground,G2frame,data)
1027           
1028        def OnBakVal(event):
1029            event.Skip()
1030            Obj = event.GetEventObject()
1031            item = ValObj[Obj.GetId()][0]
1032            try:
1033                value = float(Obj.GetValue())
1034            except ValueError:
1035                value = data[0][item]
1036            data[0][item] = value
1037            Obj.SetValue('%10.4f'%(value))
1038       
1039        backSizer = wx.BoxSizer(wx.VERTICAL)
1040        topSizer = wx.BoxSizer(wx.HORIZONTAL)
1041        topSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' Background function: '),0,WACV)
1042        bakType = wx.ComboBox(G2frame.dataDisplay,value=data[0][0],
1043                choices=Choices,style=wx.CB_READONLY|wx.CB_DROPDOWN)
1044        bakType.Bind(wx.EVT_COMBOBOX, OnNewType)
1045        topSizer.Add(bakType)
1046        topSizer.Add((5,0),0)
1047        bakRef = wx.CheckBox(G2frame.dataDisplay,label=' Refine?')
1048        bakRef.SetValue(bool(data[0][1]))
1049        bakRef.Bind(wx.EVT_CHECKBOX, OnBakRef)
1050        topSizer.Add(bakRef,0,WACV)
1051        topSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' No. coeff.: '),0,WACV)
1052        bakTerms = wx.ComboBox(G2frame.dataDisplay,-1,value=str(data[0][2]),choices=[str(i+1) for i in range(36)],
1053            style=wx.CB_READONLY|wx.CB_DROPDOWN)
1054        bakTerms.Bind(wx.EVT_COMBOBOX,OnBakTerms)
1055        topSizer.Add(bakTerms,0,WACV)
1056        topSizer.Add((5,0),0)
1057        backSizer.Add(topSizer)
1058        backSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' Background coefficients:'),0,WACV)
1059        bakSizer = wx.FlexGridSizer(0,5,5,5)
1060        for i,value in enumerate(data[0][3:]):
1061            bakVal = wx.TextCtrl(G2frame.dataDisplay,wx.ID_ANY,'%10.4g'%(value),style=wx.TE_PROCESS_ENTER)
1062            bakSizer.Add(bakVal,0,WACV)
1063            ValObj[bakVal.GetId()] = [i+3]
1064            bakVal.Bind(wx.EVT_TEXT_ENTER,OnBakVal)
1065            bakVal.Bind(wx.EVT_KILL_FOCUS,OnBakVal)
1066        backSizer.Add(bakSizer)
1067        return backSizer
1068       
1069    def DebyeSizer():
1070       
1071        def OnDebTerms(event):
1072            data[1]['nDebye'] = int(debTerms.GetValue())
1073            M = len(data[1]['debyeTerms'])
1074            N = data[1]['nDebye']
1075            if N > M:       #add terms
1076                for i in range(M,N): 
1077                    data[1]['debyeTerms'].append([1.0,False,1.0,False,0.010,False])
1078            elif N < M:     #delete terms
1079                for i in range(N,M):
1080                    del(data[1]['debyeTerms'][-1])
1081            #wx.CallAfter(UpdateBackground,G2frame,data)
1082            wx.CallLater(100,UpdateBackground,G2frame,data)
1083
1084        def KeyEditPeakGrid(event):
1085            colList = debyeGrid.GetSelectedCols()
1086            if event.GetKeyCode() == wx.WXK_RETURN:
1087                event.Skip(True)
1088            elif event.GetKeyCode() == wx.WXK_CONTROL:
1089                event.Skip(True)
1090            elif event.GetKeyCode() == wx.WXK_SHIFT:
1091                event.Skip(True)
1092            elif colList:
1093                debyeGrid.ClearSelection()
1094                key = event.GetKeyCode()
1095                for col in colList:
1096                    if debyeTable.GetTypeName(0,col) == wg.GRID_VALUE_BOOL:
1097                        if key == 89: #'Y'
1098                            for row in range(debyeGrid.GetNumberRows()): data[1]['debyeTerms'][row][col]=True
1099                        elif key == 78:  #'N'
1100                            for row in range(debyeGrid.GetNumberRows()): data[1]['debyeTerms'][row][col]=False
1101
1102       
1103        debSizer = wx.BoxSizer(wx.VERTICAL)
1104        topSizer = wx.BoxSizer(wx.HORIZONTAL)
1105        topSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' Debye scattering: '),0,WACV)
1106        topSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' No. coeff.: '),0,WACV)
1107        debTerms = wx.ComboBox(G2frame.dataDisplay,-1,value=str(data[1]['nDebye']),choices=[str(i) for i in range(12)],
1108            style=wx.CB_READONLY|wx.CB_DROPDOWN)
1109        debTerms.Bind(wx.EVT_COMBOBOX,OnDebTerms)
1110        topSizer.Add(debTerms,0,WACV)
1111        topSizer.Add((5,0),0)
1112        debSizer.Add(topSizer)
1113        if data[1]['nDebye']:
1114            debSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' Debye diffuse terms:'),0,WACV)       
1115            rowLabels = []
1116            for i in range(len(data[1]['debyeTerms'])): rowLabels.append(str(i))
1117            colLabels = ['A','refine','R','refine','U','refine']
1118            Types = [wg.GRID_VALUE_FLOAT+':10,2',wg.GRID_VALUE_BOOL,
1119            wg.GRID_VALUE_FLOAT+':10,3',wg.GRID_VALUE_BOOL,
1120            wg.GRID_VALUE_FLOAT+':10,5',wg.GRID_VALUE_BOOL]
1121            debyeTable = G2G.Table(data[1]['debyeTerms'],rowLabels=rowLabels,colLabels=colLabels,types=Types)
1122            debyeGrid = G2G.GSGrid(parent=G2frame.dataDisplay)
1123            debyeGrid.SetTable(debyeTable, True)
1124            debyeGrid.Bind(wx.EVT_KEY_DOWN, KeyEditPeakGrid)
1125            debyeGrid.AutoSizeColumns(False)
1126            debSizer.Add(debyeGrid)       
1127        return debSizer
1128     
1129    def PeaksSizer():
1130
1131        def OnPeaks(event):
1132            data[1]['nPeaks'] = int(peaks.GetValue())
1133            M = len(data[1]['peaksList'])
1134            N = data[1]['nPeaks']
1135            if N > M:       #add terms
1136                for i in range(M,N): 
1137                    data[1]['peaksList'].append([1.0,False,1.0,False,0.10,False,0.10,False])
1138            elif N < M:     #delete terms
1139                for i in range(N,M):
1140                    del(data[1]['peaksList'][-1])
1141            #wx.CallAfter(UpdateBackground,G2frame,data)
1142            wx.CallLater(100,UpdateBackground,G2frame,data)
1143           
1144        def KeyEditPeakGrid(event):
1145            colList = peaksGrid.GetSelectedCols()
1146            if event.GetKeyCode() == wx.WXK_RETURN:
1147                event.Skip(True)
1148            elif event.GetKeyCode() == wx.WXK_CONTROL:
1149                event.Skip(True)
1150            elif event.GetKeyCode() == wx.WXK_SHIFT:
1151                event.Skip(True)
1152            elif colList:
1153                peaksGrid.ClearSelection()
1154                key = event.GetKeyCode()
1155                for col in colList:
1156                    if peaksTable.GetTypeName(0,col) == wg.GRID_VALUE_BOOL:
1157                        if key == 89: #'Y'
1158                            for row in range(peaksGrid.GetNumberRows()): data[1]['peaksList'][row][col]=True
1159                        elif key == 78:  #'N'
1160                            for row in range(peaksGrid.GetNumberRows()): data[1]['peaksList'][row][col]=False
1161
1162        peaksSizer = wx.BoxSizer(wx.VERTICAL)
1163        topSizer = wx.BoxSizer(wx.HORIZONTAL)
1164        topSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' Peaks in background: '),0,WACV)
1165        topSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' No. peaks: '),0,WACV)
1166        peaks = wx.ComboBox(G2frame.dataDisplay,-1,value=str(data[1]['nPeaks']),choices=[str(i) for i in range(30)],
1167            style=wx.CB_READONLY|wx.CB_DROPDOWN)
1168        peaks.Bind(wx.EVT_COMBOBOX,OnPeaks)
1169        topSizer.Add(peaks,0,WACV)
1170        topSizer.Add((5,0),0)
1171        peaksSizer.Add(topSizer)
1172        if data[1]['nPeaks']:
1173            peaksSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' Peak list:'),0,WACV)       
1174            rowLabels = []
1175            for i in range(len(data[1]['peaksList'])): rowLabels.append(str(i))
1176            colLabels = ['pos','refine','int','refine','sig','refine','gam','refine']
1177            Types = [wg.GRID_VALUE_FLOAT+':10,2',wg.GRID_VALUE_BOOL,
1178            wg.GRID_VALUE_FLOAT+':10,3',wg.GRID_VALUE_BOOL,
1179            wg.GRID_VALUE_FLOAT+':10,3',wg.GRID_VALUE_BOOL,
1180            wg.GRID_VALUE_FLOAT+':10,5',wg.GRID_VALUE_BOOL]
1181            peaksTable = G2G.Table(data[1]['peaksList'],rowLabels=rowLabels,colLabels=colLabels,types=Types)
1182            peaksGrid = G2G.GSGrid(parent=G2frame.dataDisplay)
1183            peaksGrid.SetTable(peaksTable, True)
1184            peaksGrid.Bind(wx.EVT_KEY_DOWN, KeyEditPeakGrid)
1185            peaksGrid.AutoSizeColumns(False)
1186            peaksSizer.Add(peaksGrid)       
1187        return peaksSizer
1188               
1189    if G2frame.dataDisplay:
1190        G2frame.dataFrame.DestroyChildren()
1191    G2frame.dataDisplay = wx.Panel(G2frame.dataFrame)
1192    G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.BackMenu)
1193    G2frame.dataFrame.SetLabel('Background')
1194    if not G2frame.dataFrame.GetStatusBar():
1195        Status = G2frame.dataFrame.CreateStatusBar()
1196    G2frame.Bind(wx.EVT_MENU,OnBackCopy,id=G2gd.wxID_BACKCOPY)
1197    G2frame.Bind(wx.EVT_MENU,OnBackFlagCopy,id=G2gd.wxID_BACKFLAGCOPY)
1198    G2frame.Bind(wx.EVT_MENU,OnPeaksMove,id=G2gd.wxID_PEAKSMOVE)
1199    G2frame.Bind(wx.EVT_MENU,OnMakeRDF,id=G2gd.wxID_MAKEBACKRDF)
1200    G2frame.Bind(wx.EVT_MENU,OnBkgFit,id=G2frame.dataFrame.wxID_BackPts['Fit'])
1201    G2frame.Bind(wx.EVT_MENU,OnBkgClear,id=G2frame.dataFrame.wxID_BackPts['Clear'])   
1202    BackId = G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Background')
1203    Choices = ['chebyschev','cosine','Q^2 power series','Q^-2 power series','lin interpolate','inv interpolate','log interpolate']
1204    mainSizer = wx.BoxSizer(wx.VERTICAL)
1205    mainSizer.Add(BackSizer())
1206    mainSizer.Add((0,5),0)
1207    mainSizer.Add(DebyeSizer())
1208    mainSizer.Add((0,5),0)
1209    mainSizer.Add(PeaksSizer())
1210    mainSizer.Layout()   
1211    G2frame.dataDisplay.SetSizer(mainSizer)
1212    Size = mainSizer.Fit(G2frame.dataFrame)
1213    G2frame.dataDisplay.SetSize(Size)
1214    G2frame.dataFrame.setSizePosLeft(Size)
1215       
1216################################################################################
1217#####  Limits
1218################################################################################           
1219       
1220def UpdateLimitsGrid(G2frame, data,plottype):
1221    '''respond to selection of PWDR Limits data tree item.
1222    '''
1223    if G2frame.dataDisplay:
1224        G2frame.dataFrame.Clear()
1225    G2frame.ifGetExclude = False
1226       
1227    def KeyEditPeakGrid(event):
1228        '''for deleting excluded regions
1229        '''
1230        if event.GetKeyCode() == wx.WXK_DELETE:
1231            row = G2frame.dataDisplay.GetSelectedRows()[0]
1232            if row > 1: #can't delete limits!
1233                del(data[row])
1234                wx.CallAfter(UpdateLimitsGrid,G2frame,data,plottype)
1235                G2plt.PlotPatterns(G2frame,plotType=plottype)
1236                       
1237    def RefreshLimitsGrid(event):
1238        event.StopPropagation()
1239        data = G2frame.LimitsTable.GetData()
1240        old = data[0]
1241        new = data[1]
1242        new[0] = max(old[0],new[0])
1243        new[1] = max(new[0],min(old[1],new[1]))
1244        excl = []
1245        if len(data) > 2:
1246            excl = data[2:]
1247            for item in excl:
1248                item[0] = max(old[0],item[0])
1249                item[1] = max(item[0],min(old[1],item[1]))
1250        data = [old,new]+excl
1251        G2frame.LimitsTable.SetData(data)
1252        G2plt.PlotPatterns(G2frame,plotType=plottype)
1253       
1254    def OnLimitCopy(event):
1255        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
1256        histList = GetHistsLikeSelected(G2frame)
1257        if not histList:
1258            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
1259            return
1260        copyList = []
1261        dlg = G2G.G2MultiChoiceDialog(
1262            G2frame.dataFrame, 
1263            'Copy limits from\n'+str(hst[5:])+' to...',
1264            'Copy limits', histList)
1265        try:
1266            if dlg.ShowModal() == wx.ID_OK:
1267                for i in dlg.GetSelections(): 
1268                    item = histList[i]
1269                    Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
1270                    G2frame.PatternTree.SetItemPyData(
1271                        G2gd.GetPatternTreeItemId(G2frame,Id,'Limits'),copy.copy(data))
1272        finally:
1273            dlg.Destroy()
1274           
1275    def OnAddExcl(event):
1276        G2frame.ifGetExclude = True
1277        print 'Add excluded region'
1278       
1279    G2frame.LimitsTable = []
1280    colLabels = ['Tmin','Tmax']
1281    rowLabels = ['original','changed']
1282    for i in range(len(data)-2):
1283        rowLabels.append('exclude')
1284    Types = 2*[wg.GRID_VALUE_FLOAT+':12,5',]
1285    G2frame.LimitsTable = G2G.Table(data,rowLabels=rowLabels,colLabels=colLabels,types=Types)
1286    G2frame.dataFrame.SetLabel('Limits')
1287    G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.LimitMenu)
1288    if not G2frame.dataFrame.GetStatusBar():
1289        Status = G2frame.dataFrame.CreateStatusBar()
1290    if len(data)>2:
1291        Status.SetStatusText('To delete excluded region: select & press Delete key')
1292    G2frame.Bind(wx.EVT_MENU,OnLimitCopy,id=G2gd.wxID_LIMITCOPY)
1293    G2frame.Bind(wx.EVT_MENU,OnAddExcl,id=G2gd.wxID_ADDEXCLREGION)   
1294    G2frame.dataDisplay = G2G.GSGrid(parent=G2frame.dataFrame)
1295    G2frame.dataDisplay.SetTable(G2frame.LimitsTable, True)   
1296    G2frame.dataDisplay.SetCellStyle(0,0,VERY_LIGHT_GREY,True)
1297    G2frame.dataDisplay.SetCellStyle(0,1,VERY_LIGHT_GREY,True)
1298    G2frame.dataDisplay.Bind(wg.EVT_GRID_CELL_CHANGE, RefreshLimitsGrid)               
1299    G2frame.dataDisplay.Bind(wx.EVT_KEY_DOWN, KeyEditPeakGrid)
1300    G2frame.dataDisplay.SetMargins(0,0)
1301    G2frame.dataDisplay.AutoSizeColumns(False)
1302    G2frame.dataFrame.setSizePosLeft([230,260])                               
1303    G2frame.dataFrame.SendSizeEvent()
1304   
1305################################################################################
1306#####  Instrument parameters
1307################################################################################           
1308       
1309def UpdateInstrumentGrid(G2frame,data):
1310    '''respond to selection of PWDR/SASD Instrument Parameters
1311    data tree item.
1312    '''
1313    if 'Bank' not in data:  #get it from name; absent for default parms selection
1314        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
1315        if 'Bank' in hst:
1316            bank = int(hst.split('Bank')[1].split('_')[0])
1317            data['Bank'] = [bank,bank,0]
1318        else:
1319            data['Bank'] = [1,1,0]
1320
1321    def keycheck(keys):
1322        good = []
1323        for key in keys:
1324            if key in ['Type','Bank','U','V','W','X','Y','SH/L','I(L2)/I(L1)','alpha',
1325                'beta-0','beta-1','beta-q','sig-0','sig-1','sig-2','sig-q','Polariz.',
1326                'Lam','Azimuth','2-theta','fltPath','difC','difA','difB','Zero','Lam1','Lam2']:
1327                good.append(key)
1328        return good
1329       
1330    def updateData(inst,ref):
1331        data = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,
1332            G2frame.PatternId,'Instrument Parameters'))[0]
1333        for item in data:
1334            try:
1335                data[item] = [data[item][0],inst[item],ref[item]]
1336            except KeyError:
1337                try:
1338                    data[item] = [data[item][0],inst[item]]
1339                except KeyError:
1340                    pass        #skip 'Polariz.' for N-data
1341   
1342    def RefreshInstrumentGrid(event,doAnyway=False):
1343        if doAnyway or event.GetRow() == 1:
1344            peaks = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Peak List'))
1345            newpeaks = []
1346            for peak in peaks['peaks']:
1347                newpeaks.append(G2mth.setPeakparms(data,Inst2,peak[0],peak[2]))
1348            peaks['peaks'] = newpeaks
1349            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Peak List'),peaks)
1350           
1351    def OnCalibrate(event):
1352        Pattern = G2frame.PatternTree.GetItemPyData(G2frame.PatternId)
1353        xye = ma.array(ma.getdata(Pattern[1]))
1354        cw = np.diff(xye[0])
1355        IndexPeaks = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Index Peak List'))
1356        if not len(IndexPeaks[0]):
1357            G2frame.ErrorDialog('Can not calibrate','Index Peak List empty')
1358            return
1359        if not np.any(IndexPeaks[1]):
1360            G2frame.ErrorDialog('Can not calibrate','Peak positions not refined')
1361            return False
1362        Ok = False
1363        for peak in IndexPeaks[0]:
1364            if peak[2] and peak[3]:
1365                Ok = True
1366        if not Ok:
1367            G2frame.ErrorDialog('Can not calibrate','Index Peak List not indexed')
1368            return           
1369        if G2pwd.DoCalibInst(IndexPeaks,data):
1370            UpdateInstrumentGrid(G2frame,data)
1371            XY = []
1372            Sigs = []
1373            for ip,peak in enumerate(IndexPeaks[0]):
1374                if peak[2] and peak[3]:
1375                    binwid = cw[np.searchsorted(xye[0],peak[0])]
1376                    XY.append([peak[-1],peak[0],binwid])
1377                    Sigs.append(IndexPeaks[1][ip])
1378            if len(XY):
1379                XY = np.array(XY)
1380                G2plt.PlotCalib(G2frame,data,XY,Sigs,newPlot=True)
1381        else:
1382            G2frame.ErrorDialog('Can not calibrate','Nothing selected for refinement')
1383
1384    def OnLoad(event):
1385        '''Loads instrument parameters from a G2 .instprm file
1386        in response to the Instrument Parameters-Operations/Load Profile menu
1387        If instprm file has multiple banks each with header #Bank n: ..., this
1388        finds matching bank no. to load - rejects nonmatches.
1389       
1390        Note that similar code is found in ReadPowderInstprm (GSASII.py)
1391        '''
1392        data = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,
1393            G2frame.PatternId,'Instrument Parameters'))[0]
1394        bank = data['Bank'][0]
1395        pth = G2G.GetImportPath(G2frame)
1396        if not pth: pth = '.'
1397        dlg = wx.FileDialog(G2frame, 'Choose GSAS-II instrument parameters file', pth, '', 
1398            'instrument parameter files (*.instprm)|*.instprm',wx.OPEN)
1399        try:
1400            if dlg.ShowModal() == wx.ID_OK:
1401                filename = dlg.GetPath()
1402                File = open(filename,'r')
1403                S = File.readline()
1404                newItems = []
1405                newVals = []
1406                Found = False
1407                while S:
1408                    if S[0] == '#':
1409                        if Found:
1410                            break
1411                        if 'Bank' in S:
1412                            if bank == int(S.split(':')[0].split()[1]):
1413                                S = File.readline()
1414                                continue
1415                            else:
1416                                S = File.readline()
1417                                while S and '#Bank' not in S:
1418                                    S = File.readline()
1419                                continue
1420                        else:   #a non #Bank file
1421                            S = File.readline()
1422                            continue
1423                    Found = True
1424                    [item,val] = S[:-1].split(':')
1425                    newItems.append(item)
1426                    try:
1427                        newVals.append(float(val))
1428                    except ValueError:
1429                        newVals.append(val)                       
1430                    S = File.readline()               
1431                File.close()
1432                if Found:
1433                    Inst,Inst2 = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId,'Instrument Parameters'))
1434                    if 'Bank' not in Inst:  #patch for old .instprm files - may cause faults for TOF data
1435                        Inst['Bank'] = [1,1,0]
1436                    data = G2IO.makeInstDict(newItems,newVals,len(newVals)*[False,])
1437                    G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId,'Instrument Parameters'),[data,Inst2])
1438                    RefreshInstrumentGrid(event,doAnyway=True)          #to get peaks updated
1439                else:
1440                    G2frame.ErrorDialog('No match','Bank %d not in %s'%(bank,filename),G2frame.dataFrame)
1441                UpdateInstrumentGrid(G2frame,data)
1442                G2plt.PlotPeakWidths(G2frame)
1443        finally:
1444            dlg.Destroy()
1445       
1446    def OnSave(event):
1447        '''Respond to the Instrument Parameters Operations/Save Profile menu
1448        item: writes current parameters to a .instprm file
1449        It does not write Bank n: on # line & thus can be used any time w/o clash of bank nos.
1450        '''
1451        pth = G2G.GetExportPath(G2frame)
1452        dlg = wx.FileDialog(G2frame, 'Choose GSAS-II instrument parameters file', pth, '', 
1453            'instrument parameter files (*.instprm)|*.instprm',wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT)
1454        try:
1455            if dlg.ShowModal() == wx.ID_OK:
1456                filename = dlg.GetPath()
1457                # make sure extension is .instprm
1458                filename = os.path.splitext(filename)[0]+'.instprm'
1459                File = open(filename,'w')
1460                File.write("#GSAS-II instrument parameter file; do not add/delete items!\n")
1461                for item in data:
1462                    File.write(item+':'+str(data[item][1])+'\n')
1463                File.close()
1464        finally:
1465            dlg.Destroy()
1466           
1467    def OnSaveAll(event):
1468        '''Respond to the Instrument Parameters Operations/Save all Profile menu & writes
1469        selected inst parms. across multiple banks into a single file
1470        Each block starts with #Bank n: GSAS-II instrument... where n is bank no.
1471        item: writes parameters from selected PWDR entries to a .instprm file
1472        '''
1473        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
1474        histList = GetHistsLikeSelected(G2frame)
1475        histList.insert(0,hst)
1476        saveList = []
1477        dlg = G2G.G2MultiChoiceDialog(
1478            G2frame.dataFrame, 
1479            'Save instrument parameters from',
1480            'Save instrument parameters', histList)
1481        try:
1482            if dlg.ShowModal() == wx.ID_OK:
1483                for i in dlg.GetSelections():
1484                    saveList.append(histList[i])
1485        finally:
1486            dlg.Destroy()
1487        pth = G2G.GetExportPath(G2frame)
1488        dlg = wx.FileDialog(G2frame, 'Choose GSAS-II instrument parameters file', pth, '', 
1489            'instrument parameter files (*.instprm)|*.instprm',wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT)
1490        try:
1491            if dlg.ShowModal() == wx.ID_OK:
1492                filename = dlg.GetPath()
1493                # make sure extension is .instprm
1494                filename = os.path.splitext(filename)[0]+'.instprm'
1495                File = open(filename,'w')
1496                for hist in saveList:
1497                    Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,hist)
1498                    inst = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Instrument Parameters'))[0]
1499                    if 'Bank' not in inst:  #patch
1500                        bank = 1
1501                        if 'Bank' in hist:
1502                            bank = int(hist.split('Bank')[1])
1503                        inst['Bank'] = [bank,bank,0]
1504                    bank = inst['Bank'][0]               
1505                    File.write("#Bank %d: GSAS-II instrument parameter file; do not add/delete items!\n"%(bank))
1506                    for item in inst:
1507                        File.write(item+':'+str(inst[item][1])+'\n')                                   
1508                File.close()
1509        finally:
1510            dlg.Destroy()
1511                                               
1512    def OnReset(event):
1513        insVal.update(insDef)
1514        updateData(insVal,insRef)
1515        RefreshInstrumentGrid(event,doAnyway=True)          #to get peaks updated
1516        UpdateInstrumentGrid(G2frame,data)
1517        G2plt.PlotPeakWidths(G2frame)
1518       
1519    def OnInstFlagCopy(event):
1520        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
1521        histList = GetHistsLikeSelected(G2frame)
1522        if not histList:
1523            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
1524            return
1525        keys = data.keys()
1526        try:
1527            keys.remove('Source')
1528        except ValueError:
1529            pass
1530        flags = dict(zip(keys,[data[key][2] for key in keys]))
1531        instType = data['Type'][0]
1532        copyList = []
1533        dlg = G2G.G2MultiChoiceDialog(
1534            G2frame.dataFrame, 
1535            'Copy inst ref. flags from\n'+hst[5:],
1536            'Copy refinement flags', histList)
1537        try:
1538            if dlg.ShowModal() == wx.ID_OK:
1539                for i in dlg.GetSelections():
1540                    copyList.append(histList[i])
1541        finally:
1542            dlg.Destroy()
1543        for item in copyList:
1544            Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
1545            instData = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Instrument Parameters'))[0]
1546            if 'Bank' not in instData:
1547                instData['Bank'] = [1,1,0]
1548#            GSASIIpath.IPyBreak()
1549            if len(data) == len(instData) and instType == instData['Type'][0]:   #don't mix data types or lam & lam1/lam2 parms!
1550                for item in instData:
1551                    if item not in ['Source',]:
1552                        instData[item][2] = copy.copy(flags[item])
1553            else:
1554                print item+' not copied - instrument parameters not commensurate'
1555       
1556    def OnInstCopy(event):
1557        #need fix for dictionary
1558        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
1559        histList = GetHistsLikeSelected(G2frame)
1560        if not histList:
1561            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
1562            return
1563        copyList = []
1564        instType = data['Type'][0]
1565        dlg = G2G.G2MultiChoiceDialog(
1566            G2frame.dataFrame, 
1567            'Copy inst params from\n'+hst,
1568            'Copy parameters', histList)
1569        try:
1570            if dlg.ShowModal() == wx.ID_OK:
1571                for i in dlg.GetSelections(): 
1572                    copyList.append(histList[i])
1573        finally:
1574            dlg.Destroy()
1575        for item in copyList:
1576            Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
1577            instData = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Instrument Parameters'))[0]
1578            if 'Bank' not in instData:
1579                instData['Bank'] = [1,1,0]
1580            if len(data) == len(instData) and instType == instData['Type'][0]:  #don't mix data types or lam & lam1/lam2 parms!
1581                instData.update(data)
1582            else:
1583                print item+' not copied - instrument parameters not commensurate'
1584                         
1585    def AfterChange(invalid,value,tc):
1586        if invalid: return
1587        updateData(insVal,insRef)
1588       
1589    def OnItemRef(event):
1590        Obj = event.GetEventObject()
1591        item = RefObj[Obj.GetId()]
1592        insRef[item] = Obj.GetValue()
1593        updateData(insVal,insRef)
1594
1595    def OnCopy1Val(event):
1596        '''Select one instrument parameter value to edit and copy to many histograms
1597        optionally allow values to be edited in a table
1598        '''
1599        updateData(insVal,insRef)
1600        G2G.SelectEdit1Var(G2frame,data,labelLst,elemKeysLst,dspLst,refFlgElem)
1601        insVal.update({key:data[key][1] for key in instkeys})
1602        insRef.update({key:data[key][2] for key in instkeys})
1603        wx.CallAfter(MakeParameterWindow)
1604       
1605    def lblWdef(lbl,dec,val):
1606        'Label parameter showing the default value'
1607        fmt = "%15."+str(dec)+"f"
1608        return " " + lbl + " (" + (fmt % val).strip() + "): "
1609
1610    def RefineBox(item):
1611        'Define a refine checkbox with binding'
1612        wid = wx.CheckBox(G2frame.dataDisplay,label=' Refine?  ')
1613        wid.SetValue(bool(insRef[item]))
1614        RefObj[wid.GetId()] = item
1615        wid.Bind(wx.EVT_CHECKBOX, OnItemRef)
1616        return wid
1617
1618    def OnLamPick(event):
1619        data['Source'][1] = lamType = event.GetEventObject().GetValue()
1620        if 'P' in insVal['Type']:
1621            insVal['Lam1'] = waves[lamType][0]
1622            insVal['Lam2'] = waves[lamType][1]
1623        elif 'S' in insVal['Type'] and 'synch' not in lamType:
1624            insVal['Lam'] = meanwaves[lamType]
1625        updateData(insVal,insRef)
1626        i,j= wx.__version__.split('.')[0:2]
1627        if int(i)+int(j)/10. > 2.8:
1628            pass # repaint crashes wxpython 2.9
1629            wx.CallLater(100, MakeParameterWindow)
1630            #wx.CallAfter(MakeParameterWindow)
1631        else:
1632            wx.CallAfter(MakeParameterWindow)
1633
1634    def MakeParameterWindow():
1635        'Displays the Instrument parameters in the datadisplay frame'
1636        if G2frame.dataDisplay:
1637            G2frame.dataFrame.Clear()
1638        G2frame.dataFrame.SetLabel('Instrument Parameters')
1639        G2frame.dataDisplay = wx.Panel(G2frame.dataFrame)
1640        mainSizer = wx.BoxSizer(wx.VERTICAL)
1641        instSizer = wx.FlexGridSizer(0,6,5,5)
1642        subSizer = wx.BoxSizer(wx.HORIZONTAL)
1643        text = ' Histogram Type: %s  Bank: %d'%(insVal['Type'],insVal['Bank'])
1644        subSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,text),0,WACV)
1645        mainSizer.Add(subSizer)
1646        labelLst[:],elemKeysLst[:],dspLst[:],refFlgElem[:] = [],[],[],[]
1647        if 'P' in insVal['Type']:                   #powder data
1648            if 'C' in insVal['Type']:               #constant wavelength
1649                labelLst.append('Azimuth angle')
1650                elemKeysLst.append(['Azimuth',1])
1651                dspLst.append([10,2])
1652                refFlgElem.append(None)                   
1653                if 'Lam1' in insVal:
1654                    subSizer = wx.BoxSizer(wx.HORIZONTAL)
1655                    subSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' Azimuth: '),0,WACV)
1656                    txt = '%7.2f'%(insVal['Azimuth'])
1657                    subSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,txt.strip()),0,WACV)
1658                    subSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,'   Ka1/Ka2: '),0,WACV)
1659                    txt = u%8.6f/%8.6f\xc5'%(insVal['Lam1'],insVal['Lam2'])
1660                    subSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,txt.strip()),0,WACV)
1661                    waveSizer = wx.BoxSizer(wx.HORIZONTAL)
1662                    waveSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,'  Source type: '),0,WACV)
1663                    # PATCH?: for now at least, Source is not saved anywhere before here
1664                    if 'Source' not in data: data['Source'] = ['CuKa','?']
1665                    choice = ['TiKa','CrKa','FeKa','CoKa','CuKa','MoKa','AgKa']
1666                    lamPick = wx.ComboBox(G2frame.dataDisplay,value=data['Source'][1],choices=choice,style=wx.CB_READONLY|wx.CB_DROPDOWN)
1667                    lamPick.Bind(wx.EVT_COMBOBOX, OnLamPick)
1668                    waveSizer.Add(lamPick,0)
1669                    subSizer.Add(waveSizer,0)
1670                    mainSizer.Add(subSizer)
1671                    instSizer.Add(wx.StaticText(
1672                        G2frame.dataDisplay,-1,
1673                        lblWdef('I(L2)/I(L1)',4,insDef['I(L2)/I(L1)'])),
1674                        0,WACV)
1675                    key = 'I(L2)/I(L1)'
1676                    labelLst.append(key)
1677                    elemKeysLst.append([key,1])
1678                    dspLst.append([10,4])
1679                    refFlgElem.append([key,2])                   
1680                    ratVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,insVal,key,nDig=(10,4),typeHint=float,OnLeave=AfterChange)
1681                    instSizer.Add(ratVal,0)
1682                    instSizer.Add(RefineBox(key),0,WACV)
1683                    instSizer.Add((5,5),0)
1684                    instSizer.Add((5,5),0)
1685                    instSizer.Add((5,5),0)               
1686                else: # single wavelength
1687                    instSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' Azimuth: '),0,WACV)
1688                    txt = '%7.2f'%(insVal['Azimuth'])
1689                    instSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,txt.strip()),0,WACV)
1690                    instSizer.Add((5,5),0)
1691                    key = 'Lam'
1692                    instSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,u' Lam (\xc5): (%10.6f)'%(insDef[key])),
1693                        0,WACV)
1694                    waveVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,insVal,key,nDig=(10,6),typeHint=float,OnLeave=AfterChange)
1695                    labelLst.append(u'Lam (\xc5)')
1696                    elemKeysLst.append([key,1])
1697                    dspLst.append([10,6])
1698                    instSizer.Add(waveVal,0,WACV)
1699                    refFlgElem.append([key,2])                   
1700                    instSizer.Add(RefineBox(key),0,WACV)
1701#                    if ifHisto:
1702#                        refFlgElem.append([key,2])                   
1703#                        instSizer.Add(RefineBox(key),0,WACV)
1704#                    else:
1705#                        refFlgElem.append(None)                   
1706#                        instSizer.Add((5,5),0)
1707                for item in ['Zero','Polariz.']:
1708                    if item in insDef:
1709                        labelLst.append(item)
1710                        elemKeysLst.append([item,1])
1711                        dspLst.append([10,4])
1712                        instSizer.Add(
1713                            wx.StaticText(G2frame.dataDisplay,-1,lblWdef(item,4,insDef[item])),
1714                            0,WACV)
1715                        itemVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,insVal,item,nDig=(10,4),typeHint=float,OnLeave=AfterChange)
1716                        instSizer.Add(itemVal,0,WACV)
1717                        refFlgElem.append([item,2])
1718                        instSizer.Add(RefineBox(item),0,WACV)
1719#                        if ifHisto:
1720#                            refFlgElem.append([item,2])
1721#                            instSizer.Add(RefineBox(item),0,WACV)
1722#                        else:
1723#                            refFlgElem.append(None)                   
1724#                            instSizer.Add((5,5),0)
1725                    else:                           #skip Polariz. for neutrons
1726                        instSizer.Add((5,5),0)
1727                        instSizer.Add((5,5),0)
1728                        instSizer.Add((5,5),0)
1729                for item in ['U','V','W','','X','Y','SH/L']:
1730                    if item == '':
1731                        instSizer.Add((5,5),0)
1732                        instSizer.Add((5,5),0)
1733                        instSizer.Add((5,5),0)
1734                        continue
1735                    nDig = (10,3)
1736                    if item == 'SH/L':
1737                        nDig = (10,5)
1738                    labelLst.append(item)
1739                    elemKeysLst.append([item,1])
1740                    dspLst.append(nDig)
1741                    refFlgElem.append([item,2])
1742                    instSizer.Add(
1743                        wx.StaticText(G2frame.dataDisplay,-1,lblWdef(item,nDig[1],insDef[item])),
1744                        0,WACV)
1745                    itemVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,insVal,item,nDig=nDig,typeHint=float,OnLeave=AfterChange)
1746                    instSizer.Add(itemVal,0,WACV)
1747                    instSizer.Add(RefineBox(item),0,WACV)
1748            elif 'T' in insVal['Type']:                                   #time of flight (neutrons)
1749                subSizer = wx.BoxSizer(wx.HORIZONTAL)
1750                subSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' Fligth path: '),0,WACV)
1751                txt = '%8.3f'%(insVal['fltPath'])
1752                subSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,txt.strip()),0,WACV)
1753                labelLst.append('flight path')
1754                elemKeysLst.append(['fltpath',1])
1755                dspLst.append([10,2])
1756                refFlgElem.append(None)                   
1757                subSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,'  2-theta: '),0,WACV)
1758                txt = '%7.2f'%(insVal['2-theta'])
1759                subSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,txt.strip()),0,WACV)
1760                labelLst.append('2-theta')
1761                elemKeysLst.append(['2-theta',1])
1762                dspLst.append([10,2])
1763                refFlgElem.append(None)                   
1764                if 'Pdabc' in Inst2:
1765                    Items = ['sig-0','sig-1','sig-2','sig-q','X','Y']
1766                    subSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,'  difC: '),0,WACV)
1767                    txt = '%8.2f'%(insVal['difC'])
1768                    subSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,txt.strip()),0,WACV)
1769                    labelLst.append('difC')
1770                    elemKeysLst.append(['difC',1])
1771                    dspLst.append([10,2])
1772                    refFlgElem.append(None)
1773                    subSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,'  alpha, beta: fixed by table'),0,WACV)
1774                else:
1775                    Items = ['difC','difA','difB','Zero','alpha','beta-0','beta-1','beta-q','sig-0','sig-1','sig-2','sig-q','X','Y']
1776                mainSizer.Add((5,5),0)
1777                mainSizer.Add(subSizer)
1778                mainSizer.Add((5,5),0)
1779                for item in Items:
1780                    if item == '':
1781                        instSizer.Add((5,5),0)
1782                        instSizer.Add((5,5),0)
1783                        instSizer.Add((5,5),0)
1784                        continue
1785                    nDig = (10,3)
1786                    fmt = '%10.3f'
1787                    if 'beta' in item:
1788                        fmt = '%12.6g'
1789                        nDig = (12,6)
1790                    Fmt = ' %s: ('+fmt+')'
1791                    instSizer.Add(
1792                            wx.StaticText(G2frame.dataDisplay,-1,lblWdef(item,nDig[1],insDef[item])),
1793                            0,WACV)
1794                    itemVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,insVal,item,nDig=nDig,typeHint=float,OnLeave=AfterChange)
1795                    instSizer.Add(itemVal,0,WACV)
1796                    labelLst.append(item)
1797                    elemKeysLst.append([item,1])
1798                    dspLst.append(nDig)
1799                    refFlgElem.append([item,2])
1800                    instSizer.Add(RefineBox(item),0,WACV)
1801            elif 'PKS' in insVal['Type']:   #peak positions only
1802                key = 'Lam'
1803                instSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,u' Lam (\xc5): (%10.6f)'%(insDef[key])),
1804                    0,WACV)
1805                waveVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,insVal,key,nDig=(10,6),typeHint=float,OnLeave=AfterChange)
1806                labelLst.append(u'Lam (\xc5)')
1807                elemKeysLst.append([key,1])
1808                dspLst.append([10,6])
1809                instSizer.Add(waveVal,0,WACV)
1810                refFlgElem.append([key,2])                   
1811#                    instSizer.Add(RefineBox(key),0,WACV)
1812                for item in ['Zero',]:
1813                    if item in insDef:
1814                        labelLst.append(item)
1815                        elemKeysLst.append([item,1])
1816                        dspLst.append([10,4])
1817                        instSizer.Add(
1818                            wx.StaticText(G2frame.dataDisplay,-1,lblWdef(item,4,insDef[item])),
1819                            0,WACV)
1820                        itemVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,insVal,item,nDig=(10,4),typeHint=float,OnLeave=AfterChange)
1821                        instSizer.Add(itemVal,0,WACV)
1822                        refFlgElem.append([item,2])
1823#                        instSizer.Add(RefineBox(item),0,WACV)
1824               
1825               
1826        elif 'S' in insVal['Type']:                       #single crystal data
1827            if 'C' in insVal['Type']:               #constant wavelength
1828                instSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,u' Lam (\xc5): (%10.6f)'%(insDef['Lam'])),
1829                    0,WACV)
1830                waveVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,insVal,'Lam',nDig=(10,6),typeHint=float,OnLeave=AfterChange)
1831                instSizer.Add(waveVal,0,WACV)
1832                labelLst.append(u'Lam (\xc5)')
1833                waveSizer = wx.BoxSizer(wx.HORIZONTAL)
1834                waveSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,'  Source type: '),0,WACV)
1835                # PATCH?: for now at least, Source is not saved anywhere before here
1836                if 'Source' not in data: data['Source'] = ['CuKa','?']
1837                choice = ['synchrotron','TiKa','CrKa','FeKa','CoKa','CuKa','MoKa','AgKa']
1838                lamPick = wx.ComboBox(G2frame.dataDisplay,value=data['Source'][1],choices=choice,style=wx.CB_READONLY|wx.CB_DROPDOWN)
1839                lamPick.Bind(wx.EVT_COMBOBOX, OnLamPick)
1840                waveSizer.Add(lamPick,0,WACV)
1841                instSizer.Add(waveSizer,0,WACV)
1842                elemKeysLst.append(['Lam',1])
1843                dspLst.append([10,6])
1844                refFlgElem.append(None)
1845            else:                                   #time of flight (neutrons)
1846                pass                                #for now
1847        elif 'L' in insVal['Type']:
1848            if 'C' in insVal['Type']:       
1849                instSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,u' Lam (\xc5): (%10.6f)'%(insDef['Lam'])),
1850                    0,WACV)
1851                waveVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,insVal,'Lam',nDig=(10,6),typeHint=float,OnLeave=AfterChange)
1852                instSizer.Add(waveVal,0,WACV)
1853                labelLst.append(u'Lam (\xc5)')
1854                elemKeysLst.append(['Lam',1])
1855                dspLst.append([10,6])
1856                refFlgElem.append(None)
1857                instSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,'  Azimuth: %7.2f'%(insVal['Azimuth'])),0,WACV)
1858                labelLst.append('Azimuth angle')
1859                elemKeysLst.append(['Azimuth',1])
1860                dspLst.append([10,2])
1861                refFlgElem.append(None)                   
1862            else:                                   #time of flight (neutrons)
1863                pass                                #for now
1864
1865        mainSizer.Add(instSizer,0)
1866        mainSizer.Layout()   
1867        G2frame.dataDisplay.SetSizer(mainSizer)
1868        G2frame.dataFrame.setSizePosLeft(mainSizer.Fit(G2frame.dataFrame))
1869        G2frame.dataFrame.SendSizeEvent()  # this causes a frame repaint, even if the size does not change!
1870        # end of MakeParameterWindow
1871               
1872    # beginning of UpdateInstrumentGrid code   
1873    #patch: make sure all parameter items are lists
1874    patched = 0
1875    for key in data:
1876        if type(data[key]) is tuple:
1877            data[key] = list(data[key])
1878            patched += 1
1879    if patched: print patched,' instrument parameters changed from tuples'
1880    #end of patch
1881    labelLst,elemKeysLst,dspLst,refFlgElem = [],[],[],[]
1882    instkeys = keycheck(data.keys())
1883    if 'P' in data['Type'][0]:          #powder data
1884        insVal = dict(zip(instkeys,[data[key][1] for key in instkeys]))
1885        insDef = dict(zip(instkeys,[data[key][0] for key in instkeys]))
1886        insRef = dict(zip(instkeys,[data[key][2] for key in instkeys]))
1887        if 'NC' in data['Type'][0]:
1888            del(insDef['Polariz.'])
1889            del(insVal['Polariz.'])
1890            del(insRef['Polariz.'])
1891    elif 'S' in data['Type'][0]:                               #single crystal data
1892        insVal = dict(zip(instkeys,[data[key][1] for key in instkeys]))
1893        insDef = dict(zip(instkeys,[data[key][0] for key in instkeys]))
1894        insRef = {}
1895    elif 'L' in data['Type'][0]:                               #low angle data
1896        insVal = dict(zip(instkeys,[data[key][1] for key in instkeys]))
1897        insDef = dict(zip(instkeys,[data[key][0] for key in instkeys]))
1898        insRef = {}
1899    ValObj = {}
1900    RefObj = {}
1901    waves = {'CuKa':[1.54051,1.54433],'TiKa':[2.74841,2.75207],'CrKa':[2.28962,2.29351],
1902        'FeKa':[1.93597,1.93991],'CoKa':[1.78892,1.79278],'MoKa':[0.70926,0.713543],
1903        'AgKa':[0.559363,0.563775]}
1904    meanwaves = {'CuKa':1.5418,'TiKa':2.7496,'CrKa':2.2909,'FeKa':1.9373,
1905        'CoKa':1.7902,'MoKa':0.7107,'AgKa':0.5608}
1906    Inst2 = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,
1907            G2frame.PatternId,'Instrument Parameters'))[1]       
1908    try:
1909        histoName = G2frame.PatternTree.GetItemPyData(G2frame.PatternId)[-1]
1910        ifHisto = IsHistogramInAnyPhase(G2frame,histoName)
1911    except TypeError:       #PKS data never used in a phase as data
1912        ifhisto = False
1913    G2gd.SetDataMenuBar(G2frame)
1914    #patch
1915    if 'P' in insVal['Type']:                   #powder data
1916        if 'C' in insVal['Type']:               #constant wavelength
1917            if 'Azimuth' not in insVal:
1918                insVal['Azimuth'] = 0.0
1919                insDef['Azimuth'] = 0.0
1920                insRef['Azimuth'] = False
1921#        if 'T' in insVal['Type']:
1922#            if 'difB' not in insVal:
1923#                insVal['difB'] = 0.0
1924#                insDef['difB'] = 0.0
1925#                insRef['difB'] = False
1926    #end of patch
1927    if 'P' in insVal['Type']:                   #powder data menu commands
1928        G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.InstMenu)
1929        if not G2frame.dataFrame.GetStatusBar():
1930            Status = G2frame.dataFrame.CreateStatusBar()           
1931            Status.SetStatusText('NB: Azimuth is used for polarization only')
1932        G2frame.Bind(wx.EVT_MENU,OnCalibrate,id=G2gd.wxID_INSTCALIB)
1933        G2frame.Bind(wx.EVT_MENU,OnLoad,id=G2gd.wxID_INSTLOAD)
1934        G2frame.Bind(wx.EVT_MENU,OnSave,id=G2gd.wxID_INSTSAVE)
1935        G2frame.Bind(wx.EVT_MENU,OnSaveAll,id=G2gd.wxID_INSTSAVEALL)
1936        G2frame.Bind(wx.EVT_MENU,OnReset,id=G2gd.wxID_INSTPRMRESET)
1937        G2frame.Bind(wx.EVT_MENU,OnInstCopy,id=G2gd.wxID_INSTCOPY)
1938        G2frame.Bind(wx.EVT_MENU,OnInstFlagCopy,id=G2gd.wxID_INSTFLAGCOPY)
1939        #G2frame.Bind(wx.EVT_MENU,OnWaveChange,id=G2gd.wxID_CHANGEWAVETYPE)       
1940        G2frame.Bind(wx.EVT_MENU,OnCopy1Val,id=G2gd.wxID_INST1VAL)
1941    elif 'L' in insVal['Type']:                   #SASD data menu commands
1942        G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.SASDInstMenu)
1943        if not G2frame.dataFrame.GetStatusBar():
1944            Status = G2frame.dataFrame.CreateStatusBar()
1945        G2frame.Bind(wx.EVT_MENU,OnInstCopy,id=G2gd.wxID_INSTCOPY)
1946    MakeParameterWindow()
1947       
1948   
1949################################################################################
1950#####  Sample parameters
1951################################################################################           
1952       
1953def UpdateSampleGrid(G2frame,data):
1954    '''respond to selection of PWDR/SASD Sample Parameters
1955    data tree item.
1956    '''
1957
1958    def OnSampleSave(event):
1959        '''Respond to the Sample Parameters Operations/Save menu
1960        item: writes current parameters to a .samprm file
1961        '''
1962        pth = G2G.GetExportPath(G2frame)
1963        dlg = wx.FileDialog(G2frame, 'Choose GSAS-II sample parameters file', pth, '', 
1964            'sample parameter files (*.samprm)|*.samprm',wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT)
1965        try:
1966            if dlg.ShowModal() == wx.ID_OK:
1967                filename = dlg.GetPath()
1968                # make sure extension is .samprm
1969                filename = os.path.splitext(filename)[0]+'.samprm'
1970                File = open(filename,'w')
1971                File.write("#GSAS-II sample parameter file\n")
1972                File.write("'Type':'"+str(data['Type'])+"'\n")
1973                File.write("'Gonio. radius':"+str(data['Gonio. radius'])+"\n")
1974                if data.get('InstrName'):
1975                    File.write("'InstrName':'"+str(data['InstrName'])+"'\n")
1976                File.close()
1977        finally:
1978            dlg.Destroy()
1979           
1980    def OnSampleLoad(event):
1981        '''Loads sample parameters from a G2 .samprm file
1982        in response to the Sample Parameters-Operations/Load menu
1983       
1984        Note that similar code is found in ReadPowderInstprm (GSASII.py)
1985        '''
1986        pth = G2G.GetImportPath(G2frame)
1987        if not pth: pth = '.'
1988        dlg = wx.FileDialog(G2frame, 'Choose GSAS-II sample parameters file', pth, '', 
1989            'sample parameter files (*.samprm)|*.samprm',wx.OPEN)
1990        try:
1991            if dlg.ShowModal() == wx.ID_OK:
1992                filename = dlg.GetPath()
1993                File = open(filename,'r')
1994                S = File.readline()
1995                newItems = {}
1996                while S:
1997                    if S[0] == '#':
1998                        S = File.readline()
1999                        continue
2000                    [item,val] = S[:-1].split(':')
2001                    newItems[item.strip("'")] = eval(val)
2002                    S = File.readline()               
2003                File.close()
2004                data.update(newItems)
2005                G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId,'Sample Parameters'),data)
2006                UpdateSampleGrid(G2frame,data)
2007        finally:
2008            dlg.Destroy()
2009           
2010    def OnAllSampleLoad(event):
2011        filename = ''
2012        pth = G2G.GetImportPath(G2frame)
2013        if not pth: pth = '.'
2014        dlg = wx.FileDialog(G2frame, 'Choose multihistogram metadata text file', pth, '', 
2015            'metadata file (*.*)|*.*',wx.OPEN)
2016        try:
2017            if dlg.ShowModal() == wx.ID_OK:
2018                filename = dlg.GetPath()
2019                File = open(filename,'r')
2020                S = File.readline()
2021                newItems = []
2022                itemNames = []
2023                Comments = []
2024                while S:
2025                    if S[0] == '#':
2026                        Comments.append(S)
2027                        S = File.readline()
2028                        continue
2029                    S = S.replace(',',' ').replace('\t',' ')
2030                    Stuff = S[:-1].split()
2031                    itemNames.append(Stuff[0])
2032                    newItems.append(Stuff[1:])
2033                    S = File.readline()               
2034                File.close()
2035        finally:
2036            dlg.Destroy()
2037        if not filename:
2038            G2frame.ErrorDialog('Nothing to do','No file selected')
2039            return
2040        dataDict = dict(zip(itemNames,newItems))
2041        ifany = False
2042        Controls = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Controls'))
2043        Names = [' ','Phi','Chi','Omega','Time','Temperature','Pressure']
2044        freeNames = {}
2045        for name in ['FreePrm1','FreePrm2','FreePrm3']:
2046            freeNames[Controls[name]] = name
2047            Names.append(Controls[name])
2048        dlg = G2G.G2ColumnIDDialog( G2frame,' Choose multihistogram metadata columns:',
2049            'Select columns',Comments,Names,np.array(newItems).T)
2050        try:
2051            if dlg.ShowModal() == wx.ID_OK:
2052                colNames,newData = dlg.GetSelection()
2053                dataDict = dict(zip(itemNames,newData.T))
2054                for item in colNames:
2055                    if item != ' ':
2056                        ifany = True
2057        finally:
2058            dlg.Destroy()
2059        if not ifany:
2060            G2frame.ErrorDialog('Nothing to do','No columns identified')
2061            return
2062        histList = [G2frame.PatternTree.GetItemText(G2frame.PatternId),]
2063        histList += GetHistsLikeSelected(G2frame)
2064        colIds = {}
2065        for i,name in enumerate(colNames):
2066            if name != ' ':
2067                colIds[name] = i
2068        for hist in histList:
2069            name = hist.split()[1]  #this is file name
2070            newItems = {}
2071            for item in colIds:
2072                key = freeNames.get(item,item)
2073                newItems[key] = float(dataDict[name][colIds[item]])
2074            Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,hist)
2075            sampleData = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Sample Parameters'))
2076            sampleData.update(newItems)       
2077        UpdateSampleGrid(G2frame,data)       
2078   
2079    def OnSetScale(event):
2080        histList = []
2081        item, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)
2082        while item:
2083            name = G2frame.PatternTree.GetItemText(item)
2084            if 'SASD' in name and name != histName:
2085                histList.append(name)
2086            item, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)
2087        if not len(histList):      #nothing to copy to!
2088            return
2089        dlg = wx.SingleChoiceDialog(G2frame,'Select reference histogram for scaling',
2090            'Reference histogram',histList)
2091        try:
2092            if dlg.ShowModal() == wx.ID_OK:
2093                sel = dlg.GetSelection()
2094                refHist = histList[sel]
2095        finally:
2096            dlg.Destroy()
2097        Limits = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Limits'))
2098        Profile = G2frame.PatternTree.GetItemPyData(G2frame.PatternId)[1]
2099        Data = [Profile,Limits,data]
2100        refId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,refHist)
2101        refSample = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,refId, 'Sample Parameters'))
2102        refLimits = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,refId, 'Limits'))
2103        refProfile = G2frame.PatternTree.GetItemPyData(refId)[1]
2104        refData = [refProfile,refLimits,refSample]
2105        G2sasd.SetScale(Data,refData)
2106        G2plt.PlotPatterns(G2frame,plotType='SASD',newPlot=True)
2107        UpdateSampleGrid(G2frame,data)       
2108       
2109    def OnSampleCopy(event):
2110        histType,copyNames = SetCopyNames(histName,data['Type'],
2111            addNames = ['Omega','Chi','Phi','Gonio. radius','InstrName'])
2112        copyDict = {}
2113        for parm in copyNames:
2114            copyDict[parm] = data[parm]
2115        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
2116        histList = GetHistsLikeSelected(G2frame)
2117        if not histList:
2118            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
2119            return
2120        dlg = G2G.G2MultiChoiceDialog(
2121            G2frame.dataFrame,
2122            'Copy sample params from\n'+str(hst[5:])+' to...',
2123            'Copy sample parameters', histList)
2124        try:
2125            if dlg.ShowModal() == wx.ID_OK:
2126                result = dlg.GetSelections()
2127                for i in result: 
2128                    item = histList[i]
2129                    Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
2130                    sampleData = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Sample Parameters'))
2131                    sampleData.update(copy.deepcopy(copyDict))
2132        finally:
2133            dlg.Destroy()
2134
2135    def OnSampleCopySelected(event):
2136        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
2137        Controls = G2frame.PatternTree.GetItemPyData(
2138            G2gd.GetPatternTreeItemId(G2frame,G2frame.root, 'Controls'))
2139        histList = GetHistsLikeSelected(G2frame)
2140        if not histList:
2141            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
2142            return
2143        # Assemble a list of item labels
2144        TextTable = {key:label for key,label,dig in
2145                     SetupSampleLabels(hst,data.get('Type'),Inst['Type'][0])
2146                     }
2147        # get flexible labels
2148        TextTable.update({
2149            key:Controls[key] for key in Controls if key.startswith('FreePrm')
2150            })
2151        # add a few extra
2152        TextTable.update({
2153            'Type':'Diffractometer type',
2154            'InstrName':'Instrument Name',
2155            })
2156        # Assemble a list of dict entries that would be labeled in the Sample
2157        # params data window (drop ranId and items not used).
2158        keyList = [i for i in data.keys() if i in TextTable]
2159        keyText = [TextTable[i] for i in keyList]
2160        # sort both lists together, ordered by keyText
2161        keyText, keyList = zip(*sorted(zip(keyText,keyList))) # sort lists
2162        selectedKeys = []
2163        dlg = G2G.G2MultiChoiceDialog(
2164            G2frame.dataFrame,
2165            'Select which sample parameters\nto copy',
2166            'Select sample parameters', keyText)
2167        try:
2168            if dlg.ShowModal() == wx.ID_OK:
2169                selectedKeys = [keyList[i] for i in dlg.GetSelections()]
2170        finally:
2171            dlg.Destroy()
2172        if not selectedKeys: return # nothing to copy
2173        copyDict = {}
2174        for parm in selectedKeys:
2175            copyDict[parm] = data[parm]
2176        dlg = G2G.G2MultiChoiceDialog(
2177            G2frame.dataFrame,
2178            'Copy sample params from\n'+str(hst[5:])+' to...',
2179            'Copy sample parameters', histList)
2180        try:
2181            if dlg.ShowModal() == wx.ID_OK:
2182                result = dlg.GetSelections()
2183                for i in result: 
2184                    item = histList[i]
2185                    Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
2186                    sampleData = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Sample Parameters'))
2187                    sampleData.update(copy.deepcopy(copyDict))
2188        finally:
2189            dlg.Destroy()           
2190        G2plt.PlotPatterns(G2frame,plotType=hst[:4],newPlot=False)
2191
2192    def OnSampleFlagCopy(event):
2193        histType,copyNames = SetCopyNames(histName,data['Type'])
2194        flagDict = {}
2195        for parm in copyNames:
2196            flagDict[parm] = data[parm][1]
2197        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
2198        histList = GetHistsLikeSelected(G2frame)
2199        if not histList:
2200            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
2201            return
2202        dlg = G2G.G2MultiChoiceDialog(
2203            G2frame.dataFrame, 
2204            'Copy sample ref. flags from\n'+str(hst[5:])+' to...',
2205            'Copy sample flags', histList)
2206        try:
2207            if dlg.ShowModal() == wx.ID_OK:
2208                result = dlg.GetSelections()
2209                for i in result: 
2210                    item = histList[i]
2211                    Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
2212                    sampleData = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Sample Parameters'))
2213                    for name in copyNames:
2214                        sampleData[name][1] = copy.copy(flagDict[name])
2215        finally:
2216            dlg.Destroy()
2217
2218    def OnHistoChange():
2219        '''Called when the histogram type is changed to refresh the window
2220        '''
2221        #wx.CallAfter(UpdateSampleGrid,G2frame,data)
2222        wx.CallLater(100,UpdateSampleGrid,G2frame,data)
2223       
2224    def SetNameVal():
2225        inst = instNameVal.GetValue()
2226        data['InstrName'] = inst.strip()
2227
2228    def OnNameVal(event):
2229        event.Skip()
2230        wx.CallAfter(SetNameVal)
2231       
2232    def AfterChange(invalid,value,tc):
2233        if invalid:
2234            return
2235        if tc.key == 0 and 'SASD' in histName:          #a kluge for Scale!
2236            G2plt.PlotPatterns(G2frame,plotType='SASD',newPlot=True)
2237        elif tc.key == 'Thick':
2238            wx.CallAfter(UpdateSampleGrid,G2frame,data)           
2239           
2240    def OnMaterial(event):
2241        event.Skip()
2242        Obj = event.GetEventObject()
2243        id,key = Info[Obj.GetId()]
2244        if key == 'Name':
2245            data['Materials'][id][key] = Obj.GetValue()
2246        elif key == 'VolFrac':
2247            try:
2248                value = min(max(0.,float(Obj.GetValue())),1.)
2249            except ValueError:
2250                value = data['Materials'][id][key]
2251            data['Materials'][id][key] = value
2252            data['Materials'][not id][key] = 1.-value
2253        wx.CallAfter(UpdateSampleGrid,G2frame,data)
2254
2255    def OnCopy1Val(event):
2256        'Select one value to copy to many histograms and optionally allow values to be edited in a table'
2257        G2G.SelectEdit1Var(G2frame,data,labelLst,elemKeysLst,dspLst,refFlgElem)
2258        wx.CallAfter(UpdateSampleGrid,G2frame,data)
2259       
2260    ######## DEBUG #######################################################
2261    #import GSASIIpwdGUI
2262    #reload(GSASIIpwdGUI)
2263    #reload(G2gd)
2264    ######################################################################
2265    Inst = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(
2266            G2frame,G2frame.PatternId, 'Instrument Parameters'))[0]
2267    histName = G2frame.PatternTree.GetItemText(G2frame.PatternId)
2268    if G2frame.dataDisplay:
2269        G2frame.dataFrame.Clear()
2270    G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.SampleMenu)
2271    G2frame.dataFrame.SetLabel('Sample Parameters')
2272    G2frame.Bind(wx.EVT_MENU, OnSetScale, id=G2gd.wxID_SETSCALE)
2273    G2frame.Bind(wx.EVT_MENU, OnSampleCopy, id=G2gd.wxID_SAMPLECOPY)
2274    G2frame.Bind(wx.EVT_MENU, OnSampleCopySelected, id=G2gd.wxID_SAMPLECOPYSOME)
2275    G2frame.Bind(wx.EVT_MENU, OnSampleFlagCopy, id=G2gd.wxID_SAMPLEFLAGCOPY)
2276    G2frame.Bind(wx.EVT_MENU, OnSampleSave, id=G2gd.wxID_SAMPLESAVE)
2277    G2frame.Bind(wx.EVT_MENU, OnSampleLoad, id=G2gd.wxID_SAMPLELOAD)
2278    G2frame.Bind(wx.EVT_MENU, OnCopy1Val, id=G2gd.wxID_SAMPLE1VAL)
2279    G2frame.Bind(wx.EVT_MENU, OnAllSampleLoad, id=G2gd.wxID_ALLSAMPLELOAD)
2280    if 'SASD' in histName:
2281        G2frame.dataFrame.SetScale.Enable(True)
2282    if not G2frame.dataFrame.GetStatusBar():
2283        Status = G2frame.dataFrame.CreateStatusBar()   
2284    G2frame.dataDisplay = wx.Panel(G2frame.dataFrame)
2285    Controls = G2frame.PatternTree.GetItemPyData(
2286        G2gd.GetPatternTreeItemId(G2frame,G2frame.root, 'Controls'))
2287#patch
2288    if 'ranId' not in data:
2289        data['ranId'] = ran.randint(0,sys.maxint)
2290    if not 'Gonio. radius' in data:
2291        data['Gonio. radius'] = 200.0
2292    if not 'Omega' in data:
2293        data.update({'Omega':0.0,'Chi':0.0,'Phi':0.0})
2294    if 'Azimuth' not in data:
2295        data['Azimuth'] = 0.0
2296    if type(data['Temperature']) is int:
2297        data['Temperature'] = float(data['Temperature'])
2298    if 'Time' not in data:
2299        data['Time'] = 0.0
2300    if 'FreePrm1' not in Controls:
2301        Controls['FreePrm1'] = 'Sample humidity (%)'
2302    if 'FreePrm2' not in Controls:
2303        Controls['FreePrm2'] = 'Sample voltage (V)'
2304    if 'FreePrm3' not in Controls:
2305        Controls['FreePrm3'] = 'Applied load (MN)'
2306    if 'FreePrm1' not in data:
2307        data['FreePrm1'] = 0.
2308    if 'FreePrm2' not in data:
2309        data['FreePrm2'] = 0.
2310    if 'FreePrm3' not in data:
2311        data['FreePrm3'] = 0.
2312    if 'SurfRoughA' not in data and 'PWDR' in histName:
2313        data['SurfRoughA'] = [0.,False]
2314        data['SurfRoughB'] = [0.,False]
2315    if 'Trans' not in data and 'SASD' in histName:
2316        data['Trans'] = 1.0
2317    if 'SlitLen' not in data and 'SASD' in histName:
2318        data['SlitLen'] = 0.0
2319    if 'Shift' not in data:
2320        data['Shift'] = [0.0,False]
2321    if 'Transparency' not in data:
2322        data['Transparency'] = [0.0,False]
2323    data['InstrName'] = data.get('InstrName','')
2324#patch end
2325    labelLst,elemKeysLst,dspLst,refFlgElem = [],[],[],[]
2326    parms = SetupSampleLabels(histName,data.get('Type'),Inst['Type'][0])
2327    mainSizer = wx.BoxSizer(wx.VERTICAL)
2328    topSizer = wx.BoxSizer(wx.HORIZONTAL)
2329    topSizer.Add((-1,-1),1,wx.EXPAND,1)
2330    topSizer.Add(wx.StaticText(G2frame.dataDisplay,label='Sample and Experimental Parameters'))
2331    topSizer.Add((-1,-1),1,wx.EXPAND,1)
2332    mainSizer.Add(topSizer,0,wx.EXPAND,1)
2333    nameSizer = wx.BoxSizer(wx.HORIZONTAL)
2334    nameSizer.Add(wx.StaticText(G2frame.dataDisplay,wx.ID_ANY,' Instrument Name'),
2335                0,WACV)
2336    nameSizer.Add((-1,-1),1,wx.EXPAND,1)
2337    instNameVal = wx.TextCtrl(G2frame.dataDisplay,wx.ID_ANY,data['InstrName'],
2338                              size=(200,-1),style=wx.TE_PROCESS_ENTER)       
2339    nameSizer.Add(instNameVal)
2340    instNameVal.Bind(wx.EVT_CHAR,OnNameVal)
2341    mainSizer.Add(nameSizer,0,wx.EXPAND,1)
2342    mainSizer.Add((5,5),0)
2343    labelLst.append('Instrument Name')
2344    elemKeysLst.append(['InstrName'])
2345    dspLst.append(None)
2346    refFlgElem.append(None)
2347
2348    if 'PWDR' in histName:
2349        nameSizer = wx.BoxSizer(wx.HORIZONTAL)
2350        nameSizer.Add(wx.StaticText(G2frame.dataDisplay,wx.ID_ANY,' Diffractometer type: '),
2351                    0,WACV)
2352        if 'T' in Inst['Type'][0]:
2353            choices = ['Debye-Scherrer',]
2354        else:
2355            choices = ['Debye-Scherrer','Bragg-Brentano',]
2356        histoType = G2G.G2ChoiceButton(G2frame.dataDisplay,choices,
2357                    strLoc=data,strKey='Type',
2358                    onChoice=OnHistoChange)
2359        nameSizer.Add(histoType)
2360        mainSizer.Add(nameSizer,0,wx.EXPAND,1)
2361        mainSizer.Add((5,5),0)
2362
2363    parmSizer = wx.FlexGridSizer(0,2,5,0)
2364    for key,lbl,nDig in parms:
2365        labelLst.append(lbl.strip().strip(':').strip())
2366        dspLst.append(nDig)
2367        if 'list' in str(type(data[key])):
2368            parmRef = G2G.G2CheckBox(G2frame.dataDisplay,' '+lbl,data[key],1)
2369            parmSizer.Add(parmRef,0,WACV|wx.EXPAND)
2370            parmVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,data[key],0,
2371                nDig=nDig,typeHint=float,OnLeave=AfterChange)
2372            elemKeysLst.append([key,0])
2373            refFlgElem.append([key,1])
2374        else:
2375            parmSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' '+lbl),
2376                0,WACV|wx.EXPAND)
2377            parmVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,data,key,
2378                typeHint=float,OnLeave=AfterChange)
2379            elemKeysLst.append([key])
2380            refFlgElem.append(None)
2381        parmSizer.Add(parmVal,1,wx.EXPAND)
2382    Info = {}
2383       
2384    for key in ('FreePrm1','FreePrm2','FreePrm3'):
2385        parmVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,Controls,key,typeHint=str,
2386                                        notBlank=False)
2387        parmSizer.Add(parmVal,1,wx.EXPAND)
2388        parmVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,data,key,typeHint=float)
2389        parmSizer.Add(parmVal,1,wx.EXPAND)
2390        labelLst.append(Controls[key])
2391        dspLst.append(None)
2392        elemKeysLst.append([key])
2393        refFlgElem.append(None)
2394       
2395    mainSizer.Add(parmSizer,1,wx.EXPAND)
2396    mainSizer.Add((0,5),0)   
2397    if 'SASD' in histName:
2398        rho = [0.,0.]
2399        anomrho = [0.,0.]
2400        mu = 0.
2401        subSizer = wx.FlexGridSizer(0,4,5,5)
2402        Substances = G2frame.PatternTree.GetItemPyData(
2403            G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Substances'))
2404        for id,item in enumerate(data['Materials']):
2405            subSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Material: '),0,WACV)
2406            matsel = wx.ComboBox(G2frame.dataDisplay,value=item['Name'],choices=Substances['Substances'].keys(),
2407                style=wx.CB_READONLY|wx.CB_DROPDOWN)
2408            Info[matsel.GetId()] = [id,'Name']
2409            matsel.Bind(wx.EVT_COMBOBOX,OnMaterial)       
2410            subSizer.Add(matsel,0,WACV)
2411            subSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Volume fraction: '),0,WACV)
2412            volfrac = wx.TextCtrl(G2frame.dataDisplay,value=str('%.3f'%(item['VolFrac'])),style=wx.TE_PROCESS_ENTER)
2413            Info[volfrac.GetId()] = [id,'VolFrac']
2414            volfrac.Bind(wx.EVT_TEXT_ENTER,OnMaterial)
2415            volfrac.Bind(wx.EVT_KILL_FOCUS,OnMaterial)
2416            subSizer.Add(volfrac,0,WACV)
2417            material = Substances['Substances'][item['Name']]
2418            mu += item['VolFrac']*material.get('XAbsorption',0.)
2419            rho[id] = material['Scatt density']
2420            anomrho[id] = material.get('XAnom density',0.)
2421        data['Contrast'] = [(rho[1]-rho[0])**2,(anomrho[1]-anomrho[0])**2]
2422        mainSizer.Add(subSizer,0)
2423        conSizer = wx.BoxSizer(wx.HORIZONTAL)
2424        conSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Contrast: %10.2f '%(data['Contrast'][0])),0,WACV)
2425        conSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Anom. Contrast: %10.2f '%(data['Contrast'][1])),0,WACV)
2426        mut =  mu*data['Thick']
2427        conSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Transmission (calc): %10.3f  '%(np.exp(-mut))),0,WACV)
2428        mainSizer.Add(conSizer,0)
2429   
2430    mainSizer.Layout()   
2431    G2frame.dataDisplay.SetSizer(mainSizer)
2432    Size = mainSizer.Fit(G2frame.dataFrame)
2433    G2frame.dataDisplay.SetSize(Size)
2434    G2frame.dataFrame.setSizePosLeft(Size)
2435               
2436################################################################################
2437#####  Indexing Peaks
2438################################################################################           
2439       
2440def UpdateIndexPeaksGrid(G2frame, data):
2441    '''respond to selection of PWDR Index Peak List data
2442    tree item.
2443    '''
2444    bravaisSymb = ['Fm3m','Im3m','Pm3m','R3-H','P6/mmm','I4/mmm',
2445        'P4/mmm','Fmmm','Immm','Cmmm','Pmmm','C2/m','P2/m','P1']
2446    IndexId = G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Index Peak List')
2447    Inst = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Instrument Parameters'))[0]
2448    limitId = G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Limits')
2449    Limits = G2frame.PatternTree.GetItemPyData(limitId)
2450    def RefreshIndexPeaksGrid(event):
2451        r,c =  event.GetRow(),event.GetCol()
2452        peaks = G2frame.IndexPeaksTable.GetData()
2453        if c == 2:
2454            if peaks[r][c]:
2455                peaks[r][c] = False
2456            else:
2457                peaks[r][c] = True
2458            G2frame.IndexPeaksTable.SetData(peaks)
2459            G2frame.PatternTree.SetItemPyData(IndexId,[peaks,data[1]])
2460            G2frame.dataDisplay.ForceRefresh()
2461            if 'PKS' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
2462                G2plt.PlotPowderLines(G2frame)
2463            else:
2464                G2plt.PlotPatterns(G2frame,plotType='PWDR')
2465           
2466    def OnReload(event):
2467        peaks = []
2468        sigs = []
2469        Peaks = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Peak List'))
2470        for ip,peak in enumerate(Peaks['peaks']):
2471            dsp = G2lat.Pos2dsp(Inst,peak[0])
2472            peaks.append([peak[0],peak[2],True,False,0,0,0,dsp,0.0])    #SS?
2473            try:
2474                sig = Peaks['sigDict']['pos'+str(ip)]
2475            except KeyError:
2476                sig = 0.
2477            sigs.append(sig)
2478        data = [peaks,sigs]
2479        G2frame.PatternTree.SetItemPyData(IndexId,data)
2480        UpdateIndexPeaksGrid(G2frame,data)
2481       
2482    def KeyEditPickGrid(event):
2483        colList = G2frame.dataDisplay.GetSelectedCols()
2484        rowList = G2frame.dataDisplay.GetSelectedRows()
2485        data = G2frame.PatternTree.GetItemPyData(IndexId)
2486        if event.GetKeyCode() == wx.WXK_RETURN:
2487            event.Skip(True)
2488        elif event.GetKeyCode() == wx.WXK_CONTROL:
2489            event.Skip(True)
2490        elif event.GetKeyCode() == wx.WXK_SHIFT:
2491            event.Skip(True)
2492        elif colList:
2493            G2frame.dataDisplay.ClearSelection()
2494            key = event.GetKeyCode()
2495            for col in colList:
2496                if G2frame.IndexPeaksTable.GetColLabelValue(col) in ['use',]:
2497                    if key == 89: #'Y'
2498                        for row in range(G2frame.IndexPeaksTable.GetNumberRows()): data[0][row][col]=True
2499                    elif key == 78:  #'N'
2500                        for row in range(G2frame.IndexPeaksTable.GetNumberRows()): data[0][row][col]=False
2501                    elif key == 83: # 'S'
2502                        for row in range(G2frame.IndexPeaksTable.GetNumberRows()): data[0][row][col] = not data[0][row][col]
2503                       
2504           
2505    if G2frame.dataDisplay:
2506        G2frame.dataFrame.Clear()
2507    if not G2frame.dataFrame.GetStatusBar():
2508        Status = G2frame.dataFrame.CreateStatusBar()
2509    if 'PWD' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
2510        G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.IndPeaksMenu)
2511        G2frame.Bind(wx.EVT_MENU, OnReload, id=G2gd.wxID_INDXRELOAD)
2512    G2frame.dataFrame.IndexPeaks.Enable(False)
2513    G2frame.IndexPeaksTable = []
2514    if len(data[0]):
2515        G2frame.dataFrame.IndexPeaks.Enable(True)
2516        Unit = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Unit Cells List'))
2517        if Unit:
2518            if len(Unit) == 4:  #patch
2519                Unit.append({})
2520            controls,bravais,cellist,dmin,ssopt = Unit
2521            if 'T' in Inst['Type'][0]:   #TOF - use other limit!
2522                dmin = G2lat.Pos2dsp(Inst,Limits[1][0])
2523            else:
2524                dmin = G2lat.Pos2dsp(Inst,Limits[1][1])
2525            G2frame.HKL = []
2526            if ssopt.get('Use',False):
2527                cell = controls[6:12]
2528                A = G2lat.cell2A(cell)
2529                ibrav = bravaisSymb.index(controls[5])
2530                spc = controls[13]
2531                SGData = G2spc.SpcGroup(spc)[1]
2532                SSGData = G2spc.SSpcGroup(SGData,ssopt['ssSymb'])[1]
2533                Vec = ssopt['ModVec']
2534                maxH = ssopt['maxH']
2535                G2frame.HKL = G2pwd.getHKLMpeak(dmin,Inst,SGData,SSGData,Vec,maxH,A)
2536                G2frame.HKL = np.array(G2frame.HKL)
2537                data[0] = G2indx.IndexSSPeaks(data[0],G2frame.HKL)[1]
2538            else:        #select cell from table - no SS
2539                for i,cell in enumerate(cellist):
2540                    if cell[-2]:
2541                        ibrav = cell[2]
2542                        A = G2lat.cell2A(cell[3:9])
2543                        G2frame.HKL = G2lat.GenHBravais(dmin,ibrav,A)
2544                        for hkl in G2frame.HKL:
2545                            hkl.insert(4,G2lat.Dsp2pos(Inst,hkl[3]))
2546                        G2frame.HKL = np.array(G2frame.HKL)
2547                        data[0] = G2indx.IndexPeaks(data[0],G2frame.HKL)[1]
2548                        break
2549    rowLabels = []
2550    for i in range(len(data[0])): rowLabels.append(str(i+1))
2551    colLabels = ['position','intensity','use','indexed','h','k','l','d-obs','d-calc']
2552    Types = [wg.GRID_VALUE_FLOAT+':10,4',wg.GRID_VALUE_FLOAT+':10,1',]+2*[wg.GRID_VALUE_BOOL,]+ \
2553        3*[wg.GRID_VALUE_LONG,]+2*[wg.GRID_VALUE_FLOAT+':10,5',]
2554    if len(data[0]) and len(data[0][0]) > 9:
2555        colLabels = ['position','intensity','use','indexed','h','k','l','m','d-obs','d-calc']
2556        Types = [wg.GRID_VALUE_FLOAT+':10,4',wg.GRID_VALUE_FLOAT+':10,1',]+2*[wg.GRID_VALUE_BOOL,]+ \
2557            4*[wg.GRID_VALUE_LONG,]+2*[wg.GRID_VALUE_FLOAT+':10,5',]
2558    G2frame.PatternTree.SetItemPyData(IndexId,data)
2559    G2frame.IndexPeaksTable = G2G.Table(data[0],rowLabels=rowLabels,colLabels=colLabels,types=Types)
2560    G2frame.dataFrame.SetLabel('Index Peak List')
2561    G2frame.dataDisplay = G2G.GSGrid(parent=G2frame.dataFrame)               
2562    G2frame.dataDisplay.SetTable(G2frame.IndexPeaksTable, True)
2563    XY = []
2564    Sigs = []
2565    for r in range(G2frame.dataDisplay.GetNumberRows()):
2566        for c in range(G2frame.dataDisplay.GetNumberCols()):
2567            if c == 2:
2568                G2frame.dataDisplay.SetReadOnly(r,c,isReadOnly=False)
2569            else:
2570                G2frame.dataDisplay.SetReadOnly(r,c,isReadOnly=True)
2571        if data[0][r][2] and data[0][r][3]:
2572            XY.append([data[0][r][-1],data[0][r][0]])
2573            try:
2574                sig = data[1][r]
2575            except IndexError:
2576                sig = 0.
2577            Sigs.append(sig)
2578    G2frame.dataDisplay.Bind(wg.EVT_GRID_CELL_LEFT_CLICK, RefreshIndexPeaksGrid)
2579    G2frame.dataDisplay.Bind(wx.EVT_KEY_DOWN, KeyEditPickGrid)                 
2580    G2frame.dataDisplay.SetMargins(0,0)
2581    G2frame.dataDisplay.AutoSizeColumns(False)
2582    G2frame.dataFrame.setSizePosLeft([490,300])
2583    if len(XY):
2584        XY = np.array(XY)
2585        G2plt.PlotCalib(G2frame,Inst,XY,Sigs,newPlot=True)
2586    G2frame.dataFrame.SendSizeEvent()
2587     
2588################################################################################
2589#####  Unit cells
2590################################################################################           
2591       
2592def UpdateUnitCellsGrid(G2frame, data):
2593    '''respond to selection of PWDR Unit Cells data tree item.
2594    '''
2595    UnitCellsId = G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Unit Cells List')
2596    SPGlist = G2spc.spglist
2597    bravaisSymb = ['Fm3m','Im3m','Pm3m','R3-H','P6/mmm','I4/mmm','P4/mmm',
2598        'Fmmm','Immm','Cmmm','Pmmm','C2/m','P2/m','P1']
2599    spaceGroups = ['F m 3 m','I m 3 m','P m 3 m','R 3 m','P 6/m m m','I 4/m m m',
2600        'P 4/m m m','F m m m','I m m m','C m m m','P m m m','C 2/m','P 2/m','P -1']
2601    Inst = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Instrument Parameters'))[0]
2602    Limits = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Limits'))[1]
2603    if 'C' in Inst['Type'][0] or 'PKS' in Inst['Type'][0]:
2604        wave = G2mth.getWave(Inst)
2605        dmin = G2lat.Pos2dsp(Inst,Limits[1])
2606    else:
2607        difC = Inst['difC'][1]
2608        dmin = G2lat.Pos2dsp(Inst,Limits[0])
2609   
2610    def SetLattice(controls):
2611        ibrav = bravaisSymb.index(controls[5])
2612        if controls[5] in ['Fm3m','Im3m','Pm3m']:
2613            controls[7] = controls[8] = controls[6]
2614            controls[9] = controls[10] = controls[11] = 90.
2615        elif controls[5] in ['R3m','P6/mmm','I4/mmm','P4/mmm']:
2616            controls[7] = controls[6]
2617            controls[9] = controls[10] = controls[11] = 90.
2618            if controls[5] in ['R3-H','P6/mmm']:
2619                controls[11] = 120.
2620        elif controls[5] in ['Fmmm','Immm','Cmmm','Pmmm']:
2621            controls[9] = controls[10] = controls[11] = 90.
2622        elif controls[5] in ['C2/m','P2/m']:
2623            controls[9] = controls[11] = 90.  # b unique
2624        if len(controls) < 13: controls.append(0)
2625        controls[12] = G2lat.calc_V(G2lat.cell2A(controls[6:12]))
2626        return ibrav
2627       
2628    def OnNcNo(event):
2629        controls[2] = NcNo.GetValue()
2630       
2631    def OnIfX20(event):
2632        G2frame.ifX20 = x20.GetValue()
2633       
2634    def OnStartVol(event):
2635        event.Skip()
2636        try:
2637            stVol = int(float(startVol.GetValue()))
2638            if stVol < 25:
2639                raise ValueError
2640        except ValueError:
2641            stVol = 25
2642        controls[3] = stVol
2643        startVol.SetValue("%d"%(stVol))
2644       
2645    def OnBravais(event):
2646        Obj = event.GetEventObject()
2647        bravais[bravList.index(Obj.GetId())] = Obj.GetValue()
2648       
2649    def OnZero(event):
2650        event.Skip()
2651        try:
2652            Zero = min(5.0,max(-5.0,float(zero.GetValue())))
2653        except ValueError:
2654            Zero = 0.0
2655        controls[1] = Zero
2656        zero.SetValue("%.4f"%(Zero))
2657       
2658    def OnZeroVar(event):
2659        controls[0] = zeroVar.GetValue()
2660       
2661    def OnSSopt(event):
2662        if controls[5] in ['Fm3m','Im3m','Pm3m']:
2663            SSopt.SetValue(False)
2664            G2frame.ErrorDialog('Cubic lattice', 'Superlattice not allowed for a cubic lattice')
2665            return
2666        ssopt['Use'] = SSopt.GetValue()
2667        if 'ssSymb' not in ssopt:
2668            ssopt.update({'ssSymb':'(abg)','ModVec':[0.1,0.1,0.1],'maxH':1})
2669        wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)
2670       
2671    def OnSelMG(event):
2672        ssopt['ssSymb'] = selMG.GetValue()
2673        Vec = ssopt['ModVec']
2674        modS = G2spc.splitSSsym(ssopt['ssSymb'])[0]
2675        ssopt['ModVec'] = G2spc.SSGModCheck(Vec,modS)[0]
2676        print ' Selecting: ',controls[13],ssopt['ssSymb'], 'maxH:',ssopt['maxH']
2677        OnHklShow(event)
2678        wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)
2679       
2680    def OnModVal(event):
2681        event.Skip()
2682        Obj = event.GetEventObject()
2683        ObjId = Obj.GetId()
2684        Id = Indx[ObjId]
2685        try:
2686            value = min(0.98,max(-0.98,float(Obj.GetValue())))
2687        except ValueError:
2688            value = ssopt['ModVec'][Id]
2689        Obj.SetValue('%.4f'%(value))
2690        ssopt['ModVec'][Id] = value
2691        OnHklShow(event)
2692       
2693    def OnMoveMod(event):
2694        Obj = event.GetEventObject()
2695        ObjId = Obj.GetId()
2696        Id,valObj = Indx[ObjId]
2697        move = Obj.GetValue()*0.01
2698        Obj.SetValue(0)
2699        value = min(0.98,max(-0.98,float(valObj.GetValue())+move))
2700        valObj.SetValue('%.4f'%(value)) 
2701        ssopt['ModVec'][Id] = value
2702        OnHklShow(event)
2703       
2704    def OnMaxMH(event):
2705        ssopt['maxH'] = int(maxMH.GetValue())
2706        print ' Selecting: ',controls[13],ssopt['ssSymb'], 'maxH:',ssopt['maxH']
2707        OnHklShow(event)
2708       
2709    def OnFindMV(event):
2710        Peaks = np.copy(peaks[0])
2711        print ' Trying: ',controls[13],ssopt['ssSymb'], 'maxH:',1
2712        dlg = wx.ProgressDialog('Elapsed time','Modulation vector search',
2713            style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE)
2714        try:
2715            ssopt['ModVec'],result = G2indx.findMV(Peaks,controls,ssopt,Inst,dlg)
2716            if len(result[0]) == 2:
2717                G2plt.PlotXYZ(G2frame,result[2],1./result[3],labelX='a',labelY='g',
2718                    newPlot=True,Title='Modulation vector search')
2719        finally:
2720            dlg.Destroy()
2721        OnHklShow(event)
2722        wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)
2723       
2724    def OnBravSel(event):
2725        brav = bravSel.GetString(bravSel.GetSelection())
2726        controls[5] = brav
2727        controls[13] = SPGlist[brav][0]       
2728        wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)
2729       
2730    def OnSpcSel(event):
2731        controls[13] = spcSel.GetString(spcSel.GetSelection())
2732        G2frame.dataFrame.RefineCell.Enable(True)
2733        OnHklShow(event)
2734       
2735    def SetCellValue(Obj,ObjId,value):
2736        ibrav = bravaisSymb.index(controls[5])
2737        if controls[5] in ['Fm3m','Im3m','Pm3m']:
2738            controls[6] = controls[7] = controls[8] = value
2739            controls[9] = controls[10] = controls[11] = 90.0
2740            Obj.SetValue("%.5f"%(controls[6]))
2741        elif controls[5] in ['R3-H','P6/mmm','I4/mmm','P4/mmm']:
2742            if ObjId == 0:
2743                controls[6] = controls[7] = value
2744                Obj.SetValue("%.5f"%(controls[6]))
2745            else:
2746                controls[8] = value
2747                Obj.SetValue("%.5f"%(controls[8]))
2748            controls[9] = controls[10] = controls[11] = 90.0
2749            if controls[5] in ['R3-H','P6/mmm']:
2750                controls[11] = 120.
2751        elif controls[5] in ['Fmmm','Immm','Cmmm','Pmmm']:
2752            controls[6+ObjId] = value
2753            Obj.SetValue("%.5f"%(controls[6+ObjId]))
2754            controls[9] = controls[10] = controls[11] = 90.0
2755        elif controls[5] in ['C2/m','P2/m']:
2756            controls[9] = controls[11] = 90.0
2757            if ObjId != 3:
2758                controls[6+ObjId] = value
2759                Obj.SetValue("%.5f"%(controls[6+ObjId]))
2760            else:
2761                controls[10] = value
2762                Obj.SetValue("%.3f"%(controls[10]))
2763        else:
2764            controls[6+ObjId] = value
2765            if ObjId < 3:
2766                Obj.SetValue("%.5f"%(controls[6+ObjId]))
2767            else:
2768                Obj.SetValue("%.3f"%(controls[6+ObjId]))
2769        controls[12] = G2lat.calc_V(G2lat.cell2A(controls[6:12]))
2770        volVal.SetValue("%.3f"%(controls[12]))
2771       
2772    def OnMoveCell(event):
2773        Obj = event.GetEventObject()
2774        ObjId = cellList.index(Obj.GetId())
2775        valObj = valDict[Obj.GetId()]
2776        if ObjId/2 < 3:
2777            move = Obj.GetValue()*0.01
2778        else:
2779            move = Obj.GetValue()*0.1
2780        Obj.SetValue(0)
2781        value = float(valObj.GetValue())+move 
2782        SetCellValue(valObj,ObjId/2,value)
2783        OnHklShow(event)
2784       
2785    def OnExportCells(event):
2786        pth = G2G.GetExportPath(G2frame)
2787        dlg = wx.FileDialog(G2frame, 'Choose Indexing Result csv file', pth, '', 
2788            'indexing result file (*.csv)|*.csv',wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT)
2789        try:
2790            if dlg.ShowModal() == wx.ID_OK:
2791                filename = dlg.GetPath()
2792                filename = os.path.splitext(filename)[0]+'.csv'
2793                File = open(filename,'w')
2794                names = 'M20,X20,Bravais,a,b,c,alpha,beta,gamma,volume\n'
2795                File.write(names)
2796                fmt = '%.2f,%d,%s,%.4f,%.4f,%.4f,%.2f,%.2f,%.2f,%.3f\n'
2797                for cell in cells:
2798                    File.write(fmt%(cell[0],cell[1],bravaisSymb[cell[2]], cell[3],cell[4],cell[5], cell[6],cell[7],cell[8],cell[9]))
2799                File.close()
2800        finally:
2801            dlg.Destroy()
2802       
2803    def OnCellChange(event):
2804        event.Skip()
2805        Obj = event.GetEventObject()
2806        ObjId = cellList.index(Obj.GetId())
2807        try:
2808            value = max(1.0,float(Obj.GetValue()))
2809        except ValueError:
2810            if ObjId/2 < 3:               #bad cell edge - reset
2811                value = controls[6+ObjId/2]
2812            else:                       #bad angle
2813                value = 90.
2814        SetCellValue(Obj,ObjId/2,value)
2815        wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)
2816       
2817    def OnHklShow(event):
2818        PatternId = G2frame.PatternId
2819        PickId = G2frame.PickId   
2820        peaks = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Index Peak List'))
2821        limits = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Limits'))[1]
2822        controls,bravais,cells,dminx,ssopt = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Unit Cells List'))
2823        cell = controls[6:12]
2824        A = G2lat.cell2A(cell)
2825#        ibrav = bravaisSymb.index(controls[5])
2826        spc = controls[13]
2827        SGData = G2spc.SpcGroup(spc)[1]
2828        if ssopt.get('Use',False):
2829            SSGData = G2spc.SSpcGroup(SGData,ssopt['ssSymb'])[1]
2830            Vec = ssopt['ModVec']
2831            maxH = ssopt['maxH']
2832            G2frame.HKL = G2pwd.getHKLMpeak(dmin,Inst,SGData,SSGData,Vec,maxH,A)
2833            peaks = [G2indx.IndexSSPeaks(peaks[0],G2frame.HKL)[1],peaks[1]]   #keep esds from peak fit
2834            M20,X20 = G2indx.calc_M20SS(peaks[0],G2frame.HKL)
2835        else:
2836            if len(peaks[0]):
2837#                dmin = peaks[0][-1][7]
2838                G2frame.HKL = G2pwd.getHKLpeak(dmin,SGData,A,Inst)
2839                peaks = [G2indx.IndexPeaks(peaks[0],G2frame.HKL)[1],peaks[1]]   #keep esds from peak fit
2840                M20,X20 = G2indx.calc_M20(peaks[0],G2frame.HKL)
2841            else:
2842                M20 = X20 = 0.
2843                G2frame.HKL = G2pwd.getHKLpeak(dmin,SGData,A,Inst)
2844        G2frame.HKL = np.array(G2frame.HKL)
2845        if len(G2frame.HKL):
2846            print ' new M20,X20: %.2f %d fraction found: %.3f'%(M20,X20,float(len(peaks[0]))/len(G2frame.HKL))
2847        G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Index Peak List'),peaks)
2848        if 'PKS' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
2849            G2plt.PlotPowderLines(G2frame)
2850        else:
2851            G2plt.PlotPatterns(G2frame)
2852           
2853    def OnSortCells(event):
2854        controls,bravais,cells,dminx,ssopt = G2frame.PatternTree.GetItemPyData(UnitCellsId)
2855        c =  event.GetCol()
2856        if colLabels[c] == 'M20':
2857            cells = G2indx.sortM20(cells)
2858        elif colLabels[c] in ['X20','Bravais','a','b','c','alpha','beta','gamma','Volume']:
2859            if c == 1:
2860                c += 1  #X20 before Use
2861            cells = G2indx.sortCells(cells,c-1)     #an extra column (Use) not in cells
2862        else:
2863            return
2864        data = [controls,bravais,cells,dmin,ssopt]
2865        G2frame.PatternTree.SetItemPyData(UnitCellsId,data)
2866        wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)
2867       
2868    def CopyUnitCell(event):
2869        controls,bravais,cells,dminx,ssopt = G2frame.PatternTree.GetItemPyData(UnitCellsId)
2870        for Cell in cells:
2871            if Cell[-2]:
2872                break
2873        cell = Cell[2:9]
2874        controls[4] = 1
2875        controls[5] = bravaisSymb[cell[0]]
2876        controls[6:12] = cell[1:8]
2877        controls[12] = G2lat.calc_V(G2lat.cell2A(controls[6:12]))
2878        controls[13] = spaceGroups[bravaisSymb.index(controls[5])]
2879        G2frame.PatternTree.SetItemPyData(UnitCellsId,[controls,bravais,cells,dmin,ssopt])
2880        G2frame.dataFrame.RefineCell.Enable(True)
2881        wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)       
2882               
2883    def RefineCell(event):
2884       
2885        def cellPrint(ibrav,A):
2886            cell = G2lat.A2cell(A)
2887            Vol = G2lat.calc_V(A)
2888            if ibrav in ['Fm3m','Im3m','Pm3m']:
2889                print " %s%10.6f" % ('a =',cell[0])
2890            elif ibrav in ['R3-H','P6/mmm','I4/mmm','P4/mmm']:
2891                print " %s%10.6f %s%10.6f %s%12.3f" % ('a =',cell[0],' c =',cell[2],' volume =',Vol)
2892            elif ibrav in ['P4/mmm','Fmmm','Immm','Cmmm','Pmmm']:
2893                print " %s%10.6f %s%10.6f %s%10.6f %s%12.3f" % ('a =',cell[0],'b =',cell[1],'c =',cell[2],' volume =',Vol)
2894            elif ibrav in ['C2/m','P2/m']:
2895                print " %s%10.6f %s%10.6f %s%10.6f %s%8.3f %s%12.3f" % ('a =',cell[0],'b =',cell[1],'c =',cell[2],'beta =',cell[4],' volume =',Vol)
2896            else:
2897                print " %s%10.6f %s%10.6f %s%10.6f" % ('a =',cell[0],'b =',cell[1],'c =',cell[2])
2898                print " %s%8.3f %s%8.3f %s%8.3f %s%12.3f" % ('alpha =',cell[3],'beta =',cell[4],'gamma =',cell[5],' volume =',Vol)
2899               
2900        def vecPrint(Vec):
2901            print ' %s %10.5f %10.5f %10.5f'%('Modulation vector:',Vec[0],Vec[1],Vec[2])
2902             
2903        PatternId = G2frame.PatternId
2904        PickId = G2frame.PickId   
2905        peaks = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Index Peak List'))
2906        if not len(peaks[0]):
2907            G2frame.ErrorDialog('No peaks!', 'Nothing to refine!')
2908            return       
2909        print ' Refine cell'
2910        controls,bravais,cells,dminx,ssopt = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Unit Cells List'))
2911        cell = controls[6:12]
2912        A = G2lat.cell2A(cell)
2913        ibrav = bravaisSymb.index(controls[5])
2914        SGData = G2spc.SpcGroup(controls[13])[1]
2915        if 'C' in Inst['Type'][0] or 'PKS' in Inst['Type'][0]:
2916            if ssopt.get('Use',False):
2917                vecFlags = [True if x in ssopt['ssSymb'] else False for x in ['a','b','g']]
2918                SSGData = G2spc.SSpcGroup(SGData,ssopt['ssSymb'])[1]
2919                G2frame.HKL = G2pwd.getHKLMpeak(dmin,Inst,SGData,SSGData,ssopt['ModVec'],ssopt['maxH'],A)
2920                peaks = [G2indx.IndexSSPeaks(peaks[0],G2frame.HKL)[1],peaks[1]]   #put peak fit esds back in peaks
2921                Lhkl,M20,X20,Aref,Vec,Zero = \
2922                    G2indx.refinePeaksZSS(peaks[0],wave,Inst,SGData,SSGData,ssopt['maxH'],ibrav,A,ssopt['ModVec'],vecFlags,controls[1],controls[0])
2923            else:
2924                G2frame.HKL = G2pwd.getHKLpeak(dmin,SGData,A,Inst)
2925                peaks = [G2indx.IndexPeaks(peaks[0],G2frame.HKL)[1],peaks[1]]   #put peak fit esds back in peaks
2926                Lhkl,M20,X20,Aref,Zero = G2indx.refinePeaksZ(peaks[0],wave,ibrav,A,controls[1],controls[0])
2927        else:   
2928            if ssopt.get('Use',False):
2929                vecFlags = [True if x in ssopt['ssSymb'] else False for x in ['a','b','g']]
2930                SSGData = G2spc.SSpcGroup(SGData,ssopt['ssSymb'])[1]
2931                G2frame.HKL = G2pwd.getHKLMpeak(dmin,Inst,SGData,SSGData,ssopt['ModVec'],ssopt['maxH'],A)
2932                peaks = [G2indx.IndexSSPeaks(peaks[0],G2frame.HKL)[1],peaks[1]]   #put peak fit esds back in peaks
2933                Lhkl,M20,X20,Aref,Vec,Zero = \
2934                    G2indx.refinePeaksTSS(peaks[0],difC,Inst,SGData,SSGData,ssopt['maxH'],ibrav,A,ssopt['ModVec'],vecFlags,controls[1],controls[0])
2935            else:
2936                G2frame.HKL = G2pwd.getHKLpeak(dmin,SGData,A,Inst)
2937                peaks = [G2indx.IndexPeaks(peaks[0],G2frame.HKL)[1],peaks[1]]   #put peak fit esds back in peaks
2938                Lhkl,M20,X20,Aref,Zero = G2indx.refinePeaksT(peaks[0],difC,ibrav,A,controls[1],controls[0])           
2939        G2frame.HKL = np.array(G2frame.HKL)
2940        controls[1] = Zero
2941        controls[6:12] = G2lat.A2cell(Aref)
2942        controls[12] = G2lat.calc_V(Aref)
2943        cells = G2frame.PatternTree.GetItemPyData(UnitCellsId)[2]
2944        for cell in cells:
2945            cell[-2] = False
2946        cells.insert(0,[M20,X20,ibrav]+controls[6:13]+[True,False])
2947        if ssopt.get('Use',False):
2948            ssopt['ModVec'] = Vec
2949            G2frame.HKL = G2pwd.getHKLMpeak(dmin,Inst,SGData,SSGData,ssopt['ModVec'],ssopt['maxH'],A)
2950        else:
2951            G2frame.HKL = G2pwd.getHKLpeak(dmin,SGData,A,Inst)
2952        data = [controls,bravais,cells,dmin,ssopt]
2953        G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Unit Cells List'),data)
2954        print " %s%10.3f" % ('refinement M20 = ',M20)
2955        print ' unindexed lines = ',X20
2956        cellPrint(controls[5],Aref)
2957        ip = 4
2958        if ssopt.get('Use',False):
2959            vecPrint(Vec)
2960            ip = 5
2961        for hkl in G2frame.HKL:
2962            hkl[ip] = G2lat.Dsp2pos(Inst,hkl[ip-1])+controls[1]
2963        G2frame.HKL = np.array(G2frame.HKL)
2964        if 'PKS' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
2965            G2plt.PlotPowderLines(G2frame)
2966        else:
2967            G2plt.PlotPatterns(G2frame)
2968        wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)
2969       
2970    def OnIndexPeaks(event):
2971        PatternId = G2frame.PatternId   
2972        print 'Peak Indexing'
2973        keepcells = []
2974        try:
2975            controls,bravais,cells,dminx,ssopt = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Unit Cells List'))
2976            for cell in cells:
2977                if cell[11]:
2978                    cell[10] = False    #clear selection flag on keepers
2979                    keepcells.append(cell)
2980        except IndexError:
2981            pass
2982        except ValueError:
2983            G2frame.ErrorDialog('Error','Need to set controls in Unit Cell List first')
2984            return
2985        if ssopt.get('Use',False):
2986            G2frame.ErrorDialog('Super lattice error','Indexing not available for super lattices')
2987            return
2988        if True not in bravais:
2989            G2frame.ErrorDialog('Error','No Bravais lattices selected')
2990            return
2991        if not len(peaks[0]):
2992            G2frame.ErrorDialog('Error','Index Peak List is empty')
2993            return
2994        if len(peaks[0][0]) > 9:
2995            G2frame.ErrorDialog('Error','You need to reload Index Peaks List first')
2996            return
2997        G2frame.dataFrame.CopyCell.Enable(False)
2998        G2frame.dataFrame.RefineCell.Enable(False)
2999        dlg = wx.ProgressDialog("Generated reflections",'0 '+" cell search for "+bravaisNames[ibrav],101, 
3000#            style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE|wx.PD_REMAINING_TIME|wx.PD_CAN_SKIP|wx.PD_CAN_ABORT) #desn't work in 32 bit versions
3001            style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE|wx.PD_REMAINING_TIME|wx.PD_CAN_ABORT)
3002        OK,dmin,newcells = G2indx.DoIndexPeaks(peaks[0],controls,bravais,dlg,G2frame.ifX20)
3003        dlg.Destroy()
3004        cells = keepcells+newcells
3005        cells = G2indx.sortM20(cells)
3006        if OK:
3007            cells[0][10] = True         #select best M20
3008            data = [controls,bravais,cells,dmin,ssopt]
3009            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Unit Cells List'),data)
3010            bestCell = cells[0]
3011            if bestCell[0] > 10.:
3012                G2frame.HKL = G2lat.GenHBravais(dmin,bestCell[2],G2lat.cell2A(bestCell[3:9]))
3013                for hkl in G2frame.HKL:
3014                    hkl.insert(4,G2lat.Dsp2pos(Inst,hkl[3])+controls[1])
3015                G2frame.HKL = np.array(G2frame.HKL)
3016                if 'PKS' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
3017                    G2plt.PlotPowderLines(G2frame)
3018                else:
3019                    G2plt.PlotPatterns(G2frame)
3020            G2frame.dataFrame.CopyCell.Enable(True)
3021            G2frame.dataFrame.IndexPeaks.Enable(True)
3022            G2frame.dataFrame.MakeNewPhase.Enable(True)
3023            G2frame.ifX20 = True
3024            wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)
3025               
3026    def RefreshUnitCellsGrid(event):
3027        data = G2frame.PatternTree.GetItemPyData(UnitCellsId)
3028        cells,dminx = data[2:4]
3029        r,c =  event.GetRow(),event.GetCol()
3030        if cells:
3031            if c == 2:
3032                for i in range(len(cells)):
3033                    cells[i][-2] = False
3034                    UnitCellsTable.SetValue(i,c,False)
3035                UnitCellsTable.SetValue(r,c,True)
3036                gridDisplay.ForceRefresh()
3037                cells[r][-2] = True
3038                ibrav = cells[r][2]
3039                A = G2lat.cell2A(cells[r][3:9])
3040                G2frame.HKL = G2lat.GenHBravais(dmin,ibrav,A)
3041                for hkl in G2frame.HKL:
3042                    hkl.insert(4,G2lat.Dsp2pos(Inst,hkl[3])+controls[1])
3043                G2frame.HKL = np.array(G2frame.HKL)
3044                if 'PKS' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
3045                    G2plt.PlotPowderLines(G2frame)
3046                else:
3047                    G2plt.PlotPatterns(G2frame)
3048            elif c == 11:
3049                if UnitCellsTable.GetValue(r,c):
3050                    UnitCellsTable.SetValue(r,c,False)
3051                    cells[r][c] = False
3052                else:
3053                    cells[r][c] = True
3054                    UnitCellsTable.SetValue(r,c,True)
3055                gridDisplay.ForceRefresh()
3056            G2frame.PatternTree.SetItemPyData(UnitCellsId,data)
3057       
3058    def MakeNewPhase(event):
3059        if not G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Phases'):
3060            sub = G2frame.PatternTree.AppendItem(parent=G2frame.root,text='Phases')
3061        else:
3062            sub = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Phases')
3063        PhaseName = ''
3064        dlg = wx.TextEntryDialog(None,'Enter a name for this phase','Phase Name Entry','New phase',
3065            style=wx.OK)
3066        try:
3067            if dlg.ShowModal() == wx.ID_OK:
3068                PhaseName = dlg.GetValue()
3069                cells = G2frame.PatternTree.GetItemPyData(UnitCellsId)[2]
3070                for Cell in cells:
3071                    if Cell[-2]:
3072                        break
3073                cell = Cell[2:10]       
3074                sub = G2frame.PatternTree.AppendItem(parent=sub,text=PhaseName)
3075                E,SGData = G2spc.SpcGroup(controls[13])
3076                G2frame.PatternTree.SetItemPyData(sub, \
3077                    G2IO.SetNewPhase(Name=PhaseName,SGData=SGData,cell=cell[1:],Super=ssopt))
3078                Status.SetStatusText('Change space group from '+str(controls[13])+' if needed')
3079        finally:
3080            dlg.Destroy()
3081           
3082    if G2frame.dataDisplay:
3083        G2frame.dataFrame.DestroyChildren()
3084    G2frame.dataDisplay = wxscroll.ScrolledPanel(G2frame.dataFrame)
3085    G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.IndexMenu)
3086    if not G2frame.dataFrame.GetStatusBar():
3087        Status = G2frame.dataFrame.CreateStatusBar()
3088    G2frame.Bind(wx.EVT_MENU, OnIndexPeaks, id=G2gd.wxID_INDEXPEAKS)
3089    G2frame.Bind(wx.EVT_MENU, CopyUnitCell, id=G2gd.wxID_COPYCELL)
3090    G2frame.Bind(wx.EVT_MENU, RefineCell, id=G2gd.wxID_REFINECELL)
3091    G2frame.Bind(wx.EVT_MENU, MakeNewPhase, id=G2gd.wxID_MAKENEWPHASE)
3092    G2frame.Bind(wx.EVT_MENU, OnExportCells, id=G2gd.wxID_EXPORTCELLS)
3093       
3094    controls,bravais,cells,dminx,ssopt = data
3095    if len(controls) < 13:              #add cell volume if missing
3096        controls.append(G2lat.calc_V(G2lat.cell2A(controls[6:12])))
3097    if len(controls) < 14:              #add space group used in indexing
3098        controls.append(spaceGroups[bravaisSymb.index(controls[5])])
3099    G2frame.PatternTree.SetItemPyData(UnitCellsId,data)            #update with volume
3100    bravaisNames = ['Cubic-F','Cubic-I','Cubic-P','Trigonal-R','Trigonal/Hexagonal-P',
3101        'Tetragonal-I','Tetragonal-P','Orthorhombic-F','Orthorhombic-I','Orthorhombic-C',
3102        'Orthorhombic-P','Monoclinic-C','Monoclinic-P','Triclinic']
3103    cellGUIlist = [[[0,1,2],4,zip([" Unit cell: a = "," Vol = "],["%.5f","%.3f"],[True,False],[0,0])],
3104    [[3,4,5,6],6,zip([" Unit cell: a = "," c = "," Vol = "],["%.5f","%.5f","%.3f"],[True,True,False],[0,2,0])],
3105    [[7,8,9,10],8,zip([" Unit cell: a = "," b = "," c = "," Vol = "],["%.5f","%.5f","%.5f","%.3f"],
3106        [True,True,True,False],[0,1,2,0])],
3107    [[11,12],10,zip([" Unit cell: a = "," b = "," c = "," beta = "," Vol = "],
3108        ["%.5f","%.5f","%.5f","%.3f","%.3f"],[True,True,True,True,False],[0,1,2,4,0])],
3109    [[13,],8,zip([" Unit cell: a = "," b = "," c = "," Vol = "," alpha = "," beta = "," gamma = "],
3110        ["%.5f","%.5f","%.5f","%.3f","%.3f","%.3f","%.3f"],
3111        [True,True,True,False,True,True,True],[0,1,2,0,3,4,5])]]
3112   
3113    G2frame.dataFrame.SetLabel('Unit Cells List')
3114    G2frame.dataFrame.IndexPeaks.Enable(False)
3115    peaks = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Index Peak List'))
3116    if peaks:
3117        G2frame.dataFrame.IndexPeaks.Enable(True)
3118    G2frame.dataFrame.RefineCell.Enable(False)
3119    if controls[12] > 1.0:                               #if a "real" volume (i.e. not default)
3120        G2frame.dataFrame.RefineCell.Enable(True)   
3121    G2frame.dataFrame.CopyCell.Enable(False)
3122    G2frame.dataFrame.MakeNewPhase.Enable(False)       
3123    G2frame.dataFrame.ExportCells.Enable(False)
3124    if cells:
3125        G2frame.dataFrame.CopyCell.Enable(True)
3126        G2frame.dataFrame.MakeNewPhase.Enable(True)
3127        G2frame.dataFrame.ExportCells.Enable(True)
3128    mainSizer = wx.BoxSizer(wx.VERTICAL)
3129    mainSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Indexing controls: '),0,WACV)
3130    mainSizer.Add((5,5),0)
3131    littleSizer = wx.FlexGridSizer(0,5,5,5)
3132    littleSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Max Nc/Nobs '),0,WACV)
3133    NcNo = wx.SpinCtrl(G2frame.dataDisplay)
3134    NcNo.SetRange(2,8)
3135    NcNo.SetValue(controls[2])
3136    NcNo.Bind(wx.EVT_SPINCTRL,OnNcNo)
3137    littleSizer.Add(NcNo,0,WACV)
3138    littleSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Start Volume '),0,WACV)
3139    startVol = wx.TextCtrl(G2frame.dataDisplay,value=str('%d'%(controls[3])),style=wx.TE_PROCESS_ENTER)
3140    startVol.Bind(wx.EVT_TEXT_ENTER,OnStartVol)
3141    startVol.Bind(wx.EVT_KILL_FOCUS,OnStartVol)
3142    littleSizer.Add(startVol,0,WACV)
3143    x20 = wx.CheckBox(G2frame.dataDisplay,label='Use M20/(X20+1)?')
3144    x20.SetValue(G2frame.ifX20)
3145    x20.Bind(wx.EVT_CHECKBOX,OnIfX20)
3146    littleSizer.Add(x20,0,WACV)
3147    mainSizer.Add(littleSizer,0)
3148    mainSizer.Add((5,5),0)
3149    mainSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Select Bravais Lattices for indexing: '),
3150        0,WACV)
3151    mainSizer.Add((5,5),0)
3152    littleSizer = wx.FlexGridSizer(0,7,5,5)
3153    bravList = []
3154    bravs = zip(bravais,bravaisNames)
3155    for brav,bravName in bravs:
3156        bravCk = wx.CheckBox(G2frame.dataDisplay,label=bravName)
3157        bravList.append(bravCk.GetId())
3158        bravCk.SetValue(brav)
3159        bravCk.Bind(wx.EVT_CHECKBOX,OnBravais)
3160        littleSizer.Add(bravCk,0,WACV)
3161    mainSizer.Add(littleSizer,0)
3162    mainSizer.Add((5,5),0)
3163   
3164    mainSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Cell Test & Refinement: '),0,WACV)
3165    mainSizer.Add((5,5),0)
3166    littleSizer = wx.BoxSizer(wx.HORIZONTAL)
3167    littleSizer.Add(wx.StaticText(G2frame.dataDisplay,label=" Bravais lattice "),0,WACV)
3168    bravSel = wx.Choice(G2frame.dataDisplay,choices=bravaisSymb)
3169    bravSel.SetSelection(bravaisSymb.index(controls[5]))
3170    bravSel.Bind(wx.EVT_CHOICE,OnBravSel)
3171    littleSizer.Add(bravSel,0,WACV)
3172    littleSizer.Add(wx.StaticText(G2frame.dataDisplay,label=" Space group "),0,WACV)
3173    spcSel = wx.Choice(G2frame.dataDisplay,choices=SPGlist[controls[5]])
3174    spcSel.SetSelection(SPGlist[controls[5]].index(controls[13]))
3175    spcSel.Bind(wx.EVT_CHOICE,OnSpcSel)
3176    littleSizer.Add(spcSel,0,WACV)
3177    if ssopt.get('Use',False):        #zero for super lattice doesn't work!
3178        controls[0] = False
3179    else:
3180        littleSizer.Add(wx.StaticText(G2frame.dataDisplay,label=" Zero offset"),0,WACV)
3181        zero = wx.TextCtrl(G2frame.dataDisplay,value="%.4f"%(controls[1]),style=wx.TE_PROCESS_ENTER)
3182        zero.Bind(wx.EVT_TEXT_ENTER,OnZero)
3183        zero.Bind(wx.EVT_KILL_FOCUS,OnZero)
3184        littleSizer.Add(zero,0,WACV)
3185        zeroVar = wx.CheckBox(G2frame.dataDisplay,label="Refine?")
3186        zeroVar.SetValue(controls[0])
3187        zeroVar.Bind(wx.EVT_CHECKBOX,OnZeroVar)
3188        littleSizer.Add(zeroVar,0,WACV)
3189    SSopt = wx.CheckBox(G2frame.dataDisplay,label="Super lattice?")
3190    SSopt.SetValue(ssopt.get('Use',False))
3191    SSopt.Bind(wx.EVT_CHECKBOX,OnSSopt)
3192    littleSizer.Add(SSopt,0,WACV)
3193    hklShow = wx.Button(G2frame.dataDisplay,label="Show hkl positions")
3194    hklShow.Bind(wx.EVT_BUTTON,OnHklShow)
3195    littleSizer.Add(hklShow,0,WACV)
3196    mainSizer.Add(littleSizer,0)
3197   
3198    mainSizer.Add((5,5),0)
3199    ibrav = SetLattice(controls)
3200    for cellGUI in cellGUIlist:
3201        if ibrav in cellGUI[0]:
3202            useGUI = cellGUI
3203    cellList = []
3204    valDict = {}
3205    littleSizer = wx.FlexGridSizer(0,useGUI[1],5,5)
3206    for txt,fmt,ifEdit,Id in useGUI[2]:
3207        littleSizer.Add(wx.StaticText(G2frame.dataDisplay,label=txt),0,WACV)
3208        if ifEdit:          #a,b,c,etc.
3209            cellVal = wx.TextCtrl(G2frame.dataDisplay,value=(fmt%(controls[6+Id])),style=wx.TE_PROCESS_ENTER)
3210            cellVal.Bind(wx.EVT_TEXT_ENTER,OnCellChange)       
3211            cellVal.Bind(wx.EVT_KILL_FOCUS,OnCellChange)
3212            valSizer = wx.BoxSizer(wx.HORIZONTAL)
3213            valSizer.Add(cellVal,0,WACV)
3214            cellSpin = wx.SpinButton(G2frame.dataDisplay,style=wx.SP_VERTICAL,size=wx.Size(20,20))
3215            cellSpin.SetValue(0)
3216            cellSpin.SetRange(-1,1)
3217            cellSpin.Bind(wx.EVT_SPIN, OnMoveCell)
3218            valSizer.Add(cellSpin,0,WACV)
3219            littleSizer.Add(valSizer,0,WACV)
3220            cellList.append(cellVal.GetId())
3221            cellList.append(cellSpin.GetId())
3222            valDict[cellSpin.GetId()] = cellVal
3223        else:               #volume
3224            volVal = wx.TextCtrl(G2frame.dataDisplay,value=(fmt%(controls[12])),style=wx.TE_READONLY)
3225            volVal.SetBackgroundColour(VERY_LIGHT_GREY)
3226            littleSizer.Add(volVal,0,WACV)
3227    mainSizer.Add(littleSizer,0)
3228    if ssopt.get('Use',False):        #super lattice display
3229        indChoice = ['1','2','3','4',]
3230        SpSg = controls[13]
3231        ssChoice = G2spc.ssdict[SpSg]
3232        if ssopt['ssSymb'] not in ssChoice:
3233            ssopt['ssSymb'] = ssChoice[0]
3234        ssSizer = wx.BoxSizer(wx.HORIZONTAL)
3235        ssSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Supersymmetry space group: '+SpSg+' '),0,WACV)
3236        selMG = wx.ComboBox(G2frame.dataDisplay,value=ssopt['ssSymb'],
3237                choices=ssChoice,style=wx.CB_READONLY|wx.CB_DROPDOWN)
3238        selMG.Bind(wx.EVT_COMBOBOX, OnSelMG)
3239        ssSizer.Add(selMG,0,WACV)
3240        ssSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Mod. vector: '),0,WACV)
3241        modS = G2spc.splitSSsym(ssopt['ssSymb'])[0]
3242        ssopt['ModVec'],ifShow = G2spc.SSGModCheck(ssopt['ModVec'],modS)
3243        Indx = {}
3244        for i,[val,show] in enumerate(zip(ssopt['ModVec'],ifShow)):
3245            if show:
3246                valSizer = wx.BoxSizer(wx.HORIZONTAL)
3247                modVal = wx.TextCtrl(G2frame.dataDisplay,value=('%.4f'%(val)),
3248                    size=wx.Size(50,20),style=wx.TE_PROCESS_ENTER)
3249                modVal.Bind(wx.EVT_TEXT_ENTER,OnModVal)       
3250                modVal.Bind(wx.EVT_KILL_FOCUS,OnModVal)
3251                valSizer.Add(modVal,0,WACV)
3252                modSpin = wx.SpinButton(G2frame.dataDisplay,style=wx.SP_VERTICAL,size=wx.Size(20,20))
3253                modSpin.SetValue(0)
3254                modSpin.SetRange(-1,1)
3255                modSpin.Bind(wx.EVT_SPIN, OnMoveMod)
3256                valSizer.Add(modSpin,0,WACV)
3257                ssSizer.Add(valSizer,0,WACV)
3258                Indx[modVal.GetId()] = i
3259                Indx[modSpin.GetId()] = [i,modVal]
3260            else:
3261                modVal = wx.TextCtrl(G2frame.dataDisplay,value=('%.3f'%(val)),
3262                    size=wx.Size(50,20),style=wx.TE_READONLY)
3263                modVal.SetBackgroundColour(VERY_LIGHT_GREY)
3264                ssSizer.Add(modVal,0,WACV)
3265        ssSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Max. M: '),0,WACV)
3266        maxMH = wx.ComboBox(G2frame.dataDisplay,value=str(ssopt['maxH']),
3267            choices=indChoice,style=wx.CB_READONLY|wx.CB_DROPDOWN)
3268        maxMH.Bind(wx.EVT_COMBOBOX, OnMaxMH)
3269        ssSizer.Add(maxMH,0,WACV)
3270        findMV = wx.Button(G2frame.dataDisplay,label="Find mod. vec.?")
3271        findMV.Bind(wx.EVT_BUTTON,OnFindMV)
3272        ssSizer.Add(findMV,0,WACV)
3273        mainSizer.Add(ssSizer,0)
3274
3275    if cells:
3276        mainSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label='\n Indexing Result:'),0,WACV)
3277        rowLabels = []
3278        colLabels = ['M20','X20','use','Bravais','a','b','c','alpha','beta','gamma','Volume','Keep']
3279        Types = [wg.GRID_VALUE_FLOAT+':10,2',wg.GRID_VALUE_NUMBER,wg.GRID_VALUE_BOOL,wg.GRID_VALUE_STRING,]+ \
3280            3*[wg.GRID_VALUE_FLOAT+':10,5',]+3*[wg.GRID_VALUE_FLOAT+':10,3',]+ \
3281            [wg.GRID_VALUE_FLOAT+':10,2',wg.GRID_VALUE_BOOL]
3282        numRows = len(cells)
3283        table = []
3284        for cell in cells:
3285            rowLabels.append('')
3286            row = cell[0:2]+[cell[-2]]+[bravaisSymb[cell[2]]]+cell[3:10]+[cell[11],]
3287            if cell[-2]:
3288                A = G2lat.cell2A(cell[3:9])
3289                G2frame.HKL = G2lat.GenHBravais(dmin,cell[2],A)
3290                for hkl in G2frame.HKL:
3291                    hkl.insert(4,G2lat.Dsp2pos(Inst,hkl[3])+controls[1])
3292                G2frame.HKL = np.array(G2frame.HKL)
3293            table.append(row)
3294        UnitCellsTable = G2G.Table(table,rowLabels=rowLabels,colLabels=colLabels,types=Types)
3295        gridDisplay = G2G.GSGrid(G2frame.dataDisplay)
3296        gridDisplay.SetTable(UnitCellsTable, True)
3297        G2frame.dataFrame.CopyCell.Enable(True)
3298        gridDisplay.Bind(wg.EVT_GRID_CELL_LEFT_CLICK,RefreshUnitCellsGrid)
3299        gridDisplay.Bind(wg.EVT_GRID_LABEL_LEFT_DCLICK,OnSortCells)
3300        gridDisplay.SetMargins(0,0)
3301        gridDisplay.SetRowLabelSize(0)
3302        gridDisplay.AutoSizeColumns(False)
3303        for r in range(gridDisplay.GetNumberRows()):
3304            for c in range(gridDisplay.GetNumberCols()):
3305                if c == 2:
3306                    gridDisplay.SetReadOnly(r,c,isReadOnly=False)
3307                else:
3308                    gridDisplay.SetReadOnly(r,c,isReadOnly=True)
3309        mainSizer.Add(gridDisplay,0,WACV)
3310    mainSizer.Layout()   
3311    G2frame.dataDisplay.SetSizer(mainSizer)
3312    G2frame.dataDisplay.SetAutoLayout(1)
3313    G2frame.dataDisplay.SetupScrolling()
3314    Size = mainSizer.Fit(G2frame.dataFrame)
3315    Size[0] += 25
3316    G2frame.dataDisplay.SetSize(Size)
3317    G2frame.dataFrame.setSizePosLeft(Size)   
3318   
3319################################################################################
3320#####  Reflection list
3321################################################################################           
3322       
3323def UpdateReflectionGrid(G2frame,data,HKLF=False,Name=''):
3324    '''respond to selection of PWDR Reflections data tree item by displaying
3325    a table of reflections in the data window.
3326    '''
3327    Controls = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.root, 'Controls'))
3328    dMin = 0.05
3329    if 'UsrReject' in Controls:
3330        dMin = Controls['UsrReject'].get('MinD',0.05)
3331    def OnPlotHKL(event):
3332        '''Plots a layer of reflections
3333        '''
3334        phaseName = G2frame.RefList
3335        if phaseName not in ['Unknown',]:
3336            pId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Phases')
3337            phaseId =  G2gd.GetPatternTreeItemId(G2frame,pId,phaseName)
3338            General = G2frame.PatternTree.GetItemPyData(phaseId)['General']
3339            Super = General.get('Super',0)
3340            SuperVec = General.get('SuperVec',[])
3341        else:
3342            Super = 0
3343            SuperVec = []       
3344        if 'list' in str(type(data)):   #single crystal data is 2 dict in list
3345            refList = data[1]['RefList']
3346        else:                           #powder data is a dict of dicts; each same structure as SC 2nd dict
3347            if 'RefList' in data[phaseName]:
3348                refList = np.array(data[phaseName]['RefList'])
3349            else:
3350                wx.MessageBox('No reflection list - do Refine first',caption='Reflection plotting')
3351                return
3352        FoMax = np.max(refList.T[8+Super])
3353        Hmin = np.array([int(np.min(refList.T[0])),int(np.min(refList.T[1])),int(np.min(refList.T[2]))])
3354        Hmax = np.array([int(np.max(refList.T[0])),int(np.max(refList.T[1])),int(np.max(refList.T[2]))])
3355        controls = {'Type' : 'Fo','ifFc' : True,'HKLmax' : Hmax,'HKLmin' : Hmin,
3356            'FoMax' : FoMax,'Zone' : '001','Layer' : 0,'Scale' : 1.0,'Super':Super,'SuperVec':SuperVec}
3357        G2plt.PlotSngl(G2frame,newPlot=True,Data=controls,hklRef=refList,Title=phaseName)
3358       
3359    def OnPlot3DHKL(event):
3360        '''Plots the reflections in 3D
3361        '''
3362        phaseName = G2frame.RefList
3363        if phaseName not in ['Unknown',]:
3364            pId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Phases')
3365            phaseId =  G2gd.GetPatternTreeItemId(G2frame,pId,phaseName)
3366            General = G2frame.PatternTree.GetItemPyData(phaseId)['General']
3367            Super = General.get('Super',0)
3368            SuperVec = General.get('SuperVec',[])
3369        else:
3370            Super = 0
3371            SuperVec = []       
3372        if 'list' in str(type(data)):   #single crystal data is 2 dict in list
3373            refList = data[1]['RefList']
3374        else:                           #powder data is a dict of dicts; each same structure as SC 2nd dict
3375            if 'RefList' in data[phaseName]:
3376                refList = np.array(data[phaseName]['RefList'])
3377            else:
3378                wx.MessageBox('No reflection list - do Refine first',caption='Reflection plotting')
3379                return
3380        refList.T[3+Super] = np.where(refList.T[4+Super]<dMin,-refList.T[3+Super],refList.T[3+Super])
3381        FoMax = np.max(refList.T[8+Super])
3382        Hmin = np.array([int(np.min(refList.T[0])),int(np.min(refList.T[1])),int(np.min(refList.T[2]))])
3383        Hmax = np.array([int(np.max(refList.T[0])),int(np.max(refList.T[1])),int(np.max(refList.T[2]))])
3384        Vpoint = np.array([int(np.mean(refList.T[0])),int(np.mean(refList.T[1])),int(np.mean(refList.T[2]))])
3385        controls = {'Type':'Fosq','Iscale':False,'HKLmax':Hmax,'HKLmin':Hmin,'Zone':False,'viewKey':'L',
3386            'FoMax' : FoMax,'Scale' : 1.0,'Drawing':{'viewPoint':[Vpoint,[]],'default':Vpoint[:],
3387            'backColor':[0,0,0],'depthFog':False,'Zclip':10.0,'cameraPos':10.,'Zstep':0.05,'viewUp':[0,1,0],
3388            'Scale':1.0,'oldxy':[],'viewDir':[0,0,1]},'Super':Super,'SuperVec':SuperVec}
3389        G2plt.Plot3DSngl(G2frame,newPlot=True,Data=controls,hklRef=refList,Title=phaseName)
3390       
3391    def MakeReflectionTable(phaseName):
3392        '''Returns a wx.grid table (G2G.Table) containing a list of all reflections
3393        for a phase.       
3394        '''
3395        if phaseName not in ['Unknown',]:
3396            pId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Phases')
3397            phaseId =  G2gd.GetPatternTreeItemId(G2frame,pId,phaseName)
3398            if not phaseId:         #phase deleted
3399                return None
3400            General = G2frame.PatternTree.GetItemPyData(phaseId)['General']
3401            Super = General.get('Super',0)
3402            SuperVec = General.get('SuperVec',[])
3403        else:
3404            Super = 0
3405            SuperVec = []       
3406        rowLabels = []
3407        if HKLF:
3408            refList = data[1]['RefList']
3409            refs = refList
3410        else:
3411            if len(data) > 1:
3412                G2frame.dataFrame.SelectPhase.Enable(True)
3413            try:            #patch for old reflection lists
3414                if not len(data[phaseName]):
3415                    return None
3416                refList = np.array(data[phaseName]['RefList'])
3417                I100 = refList.T[8+Super]*refList.T[11+Super]
3418            except TypeError:
3419                refList = np.array([refl[:11+Super] for refl in data[phaseName]])
3420                I100 = refList.T[8+Super]*np.array([refl[11+Super] for refl in data[phaseName]])
3421            Imax = np.max(I100)
3422            if Imax:
3423                I100 *= 100.0/Imax
3424            if 'C' in Inst['Type'][0]:
3425                refs = np.vstack((refList.T[:15+Super],I100)).T
3426            elif 'T' in Inst['Type'][0]:
3427                refs = np.vstack((refList.T[:18+Super],I100)).T
3428        rowLabels = [str(i) for i in range(len(refs))]
3429        Types = (4+Super)*[wg.GRID_VALUE_LONG,]+4*[wg.GRID_VALUE_FLOAT+':10,4',]+ \
3430            2*[wg.GRID_VALUE_FLOAT+':10,2',]+[wg.GRID_VALUE_FLOAT+':10,3',]+ \
3431            [wg.GRID_VALUE_FLOAT+':10,3',]
3432        if HKLF:
3433            colLabels = ['H','K','L','twin','d','Fosq','sig','Fcsq','FoTsq','FcTsq','phase','ExtC',]
3434            if 'T' in Inst['Type'][0]:
3435                colLabels = ['H','K','L','twin','d','Fosq','sig','Fcsq','FoTsq','FcTsq','phase','ExtC','wave','tbar']
3436                Types += 2*[wg.GRID_VALUE_FLOAT+':10,3',]
3437            if Super:
3438                colLabels.insert(3,'M')
3439        else:
3440            if 'C' in Inst['Type'][0]:
3441                colLabels = ['H','K','L','mul','d','pos','sig','gam','Fosq','Fcsq','phase','Icorr','Prfo','Trans','ExtP','I100']
3442                Types += 4*[wg.GRID_VALUE_FLOAT+':10,3',]
3443            elif 'T' in Inst['Type'][0]:
3444                colLabels = ['H','K','L','mul','d','pos','sig','gam','Fosq','Fcsq','phase','Icorr','alp','bet','wave','Prfo','Abs','Ext','I100']
3445                Types += 7*[wg.GRID_VALUE_FLOAT+':10,3',]
3446            if Super:
3447                colLabels.insert(3,'M')
3448        refs.T[3+Super] = np.where(refs.T[4+Super]<dMin,-refs.T[3+Super],refs.T[3+Super])
3449        return G2G.Table(refs,rowLabels=rowLabels,colLabels=colLabels,types=Types)
3450
3451    def ShowReflTable(phaseName):
3452        '''Posts a table of reflections for a phase, creating the table
3453        if needed using MakeReflectionTable
3454        '''
3455        def setBackgroundColors(im,it):
3456            for r in range(G2frame.refTable[phaseName].GetNumberRows()):
3457                if HKLF:
3458                    if float(G2frame.refTable[phaseName].GetCellValue(r,3+im)) <= 0.:
3459                        G2frame.refTable[phaseName].SetCellBackgroundColour(r,3+im,wx.RED)
3460                    Fosq = float(G2frame.refTable[phaseName].GetCellValue(r,5+im))
3461                    Fcsq = float(G2frame.refTable[phaseName].GetCellValue(r,7+im))
3462                    sig = float(G2frame.refTable[phaseName].GetCellValue(r,6+im))
3463                    rat = 11.
3464                    if sig:
3465                        rat = abs(Fosq-Fcsq)/sig
3466                    if  rat > 10.:
3467                        G2frame.refTable[phaseName].SetCellBackgroundColour(r,7+im,wx.RED)
3468                    elif rat > 3.0:
3469                        G2frame.refTable[phaseName].SetCellBackgroundColour(r,7+im,wx.Colour(255,255,0))
3470                else:   #PWDR
3471                    if float(G2frame.refTable[phaseName].GetCellValue(r,12+im+itof)) < 0.:
3472                        G2frame.refTable[phaseName].SetCellBackgroundColour(r,12+im+itof,wx.RED)
3473                    if float(G2frame.refTable[phaseName].GetCellValue(r,3+im)) < 0:
3474                        G2frame.refTable[phaseName].SetCellBackgroundColour(r,8+im,wx.RED)
3475                       
3476                                                 
3477        if not len(data[phaseName]):
3478            return          #deleted phase?
3479        G2frame.RefList = phaseName
3480        G2frame.dataFrame.SetLabel('Reflection List for '+phaseName)
3481        if HKLF:
3482            Status.SetStatusText('abs(DF)/sig > 10 red; > 3 yellow; twin < 0 (user rejected) red; twin=0 (sp. gp. absent) red')
3483        else:
3484            Status.SetStatusText('Prfo < 0. in red; if excluded Fosq in red & mul < 0')
3485        itof = 0
3486        if HKLF:
3487            im = data[1].get('Super',0)
3488        else:
3489            if 'T' in data[phaseName].get('Type',''):
3490                itof = 3
3491            im = data[phaseName].get('Super',0)
3492        # has this table already been displayed?
3493        if G2frame.refTable[phaseName].GetTable() is None:
3494            PeakTable = MakeReflectionTable(phaseName)
3495            G2frame.refTable[phaseName].SetTable(PeakTable, True)
3496            G2frame.refTable[phaseName].EnableEditing(False)
3497            G2frame.refTable[phaseName].SetMargins(0,0)
3498            G2frame.refTable[phaseName].AutoSizeColumns(False)
3499            setBackgroundColors(im,itof)
3500#        GSASIIpath.IPyBreak()
3501        refList = np.array([refl[:6+im] for refl in data[phaseName]['RefList']])
3502        G2frame.HKL = np.vstack((refList.T)).T    #build for plots
3503        # raise the tab (needed for 1st use and from OnSelectPhase)
3504        for PageNum in range(G2frame.dataDisplay.GetPageCount()):
3505            if phaseName == G2frame.dataDisplay.GetPageText(PageNum):
3506                G2frame.dataDisplay.SetSelection(PageNum)
3507                break
3508        else:
3509            print phaseName
3510            print phases
3511            raise Exception("how did we not find a phase name?")
3512       
3513    def OnPageChanged(event):
3514        '''Respond to a press on a phase tab by displaying the reflections. This
3515        routine is needed because the reflection table may not have been created yet.
3516        '''
3517        page = event.GetSelection()
3518        phaseName = G2frame.dataDisplay.GetPageText(page)
3519        ShowReflTable(phaseName)
3520
3521    def OnSelectPhase(event):
3522        '''For PWDR, selects a phase with a selection box. Called from menu.
3523        '''
3524        if len(phases) < 2: return
3525        dlg = wx.SingleChoiceDialog(G2frame,'Select','Phase',phases)
3526        try:
3527            if dlg.ShowModal() == wx.ID_OK:
3528                sel = dlg.GetSelection()
3529                ShowReflTable(phases[sel])
3530        finally:
3531            dlg.Destroy()
3532           
3533    if not data:
3534        print 'No phases, no reflections'
3535        return
3536    if HKLF:
3537        G2frame.RefList = 1
3538        phaseName = IsHistogramInAnyPhase(G2frame,Name)
3539        if not phaseName:
3540            phaseName = 'Unknown'
3541        phases = [phaseName]
3542    else:
3543        phaseName = G2frame.RefList
3544        phases = data.keys()
3545    if G2frame.dataDisplay:
3546        G2frame.dataFrame.Clear()
3547    Inst = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Instrument Parameters'))[0]
3548    if HKLF:
3549        G2gd.SetDataMenuBar(G2frame)
3550        G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.ReflMenu)
3551        if not G2frame.dataFrame.GetStatusBar():
3552            Status = G2frame.dataFrame.CreateStatusBar()   
3553        G2frame.Bind(wx.EVT_MENU, OnPlotHKL, id=G2gd.wxID_PWDHKLPLOT)
3554        G2frame.Bind(wx.EVT_MENU, OnPlot3DHKL, id=G2gd.wxID_PWD3DHKLPLOT)
3555        G2frame.dataFrame.SelectPhase.Enable(False)
3556    else:
3557        G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.ReflMenu)
3558        if not G2frame.dataFrame.GetStatusBar():
3559            Status = G2frame.dataFrame.CreateStatusBar()   
3560        G2frame.Bind(wx.EVT_MENU, OnSelectPhase, id=G2gd.wxID_SELECTPHASE)
3561        G2frame.Bind(wx.EVT_MENU, OnPlotHKL, id=G2gd.wxID_PWDHKLPLOT)
3562        G2frame.Bind(wx.EVT_MENU, OnPlot3DHKL, id=G2gd.wxID_PWD3DHKLPLOT)
3563        G2frame.dataFrame.SelectPhase.Enable(False)
3564           
3565    G2frame.dataDisplay = G2G.GSNoteBook(parent=G2frame.dataFrame,size=G2frame.dataFrame.GetClientSize())
3566    G2frame.refTable = {}
3567    for tabnum,phase in enumerate(phases):
3568        if len(data[phase]):
3569            G2frame.refTable[phase] = G2G.GSGrid(parent=G2frame.dataDisplay)
3570            G2frame.dataDisplay.AddPage(G2frame.refTable[phase],phase)
3571        else:       #cleanup deleted phase reflection lists
3572            del data[phase]
3573            if len(data):
3574                G2frame.RefList = data.keys()[0]
3575                phaseName = G2frame.RefList
3576            else:
3577                G2frame.RefList = ''
3578                phaseName = ''
3579#    if phaseName not in G2frame.refTable:
3580#        print phaseName
3581#        print phases
3582#        raise Exception("how did we get a invalid phase name?")   
3583    if phaseName:
3584        ShowReflTable(phaseName)
3585#    G2frame.refTable[phaseName].Fit()   #slow!!
3586#    size = G2frame.refTable[phaseName].GetSize()
3587#    G2frame.dataFrame.setSizePosLeft([size[0]+32,350])
3588    G2frame.dataFrame.setSizePosLeft([550,350])
3589    G2frame.dataDisplay.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CHANGED, OnPageChanged)
3590   
3591################################################################################
3592#####  SASD Substances
3593################################################################################
3594           
3595def UpdateSubstanceGrid(G2frame,data):
3596    '''respond to selection of SASD Substance data tree item.
3597    '''
3598    import Substances as substFile
3599   
3600    def OnLoadSubstance(event):
3601        names = substFile.Substances.keys()
3602        names.sort()
3603        dlg = wx.SingleChoiceDialog(G2frame, 'Which substance?', 'Select substance', names, wx.CHOICEDLG_STYLE)
3604        try:
3605            if dlg.ShowModal() == wx.ID_OK:
3606                name = names[dlg.GetSelection()]
3607            else:
3608                return
3609        finally:
3610            dlg.Destroy()
3611        data['Substances'][name] = {'Elements':{},'Volume':1.0,'Density':1.0,
3612            'Scatt density':0.0,'XAnom density':0.0,'XAbsorption':0.0}
3613        subst = substFile.Substances[name]
3614        ElList = subst['Elements'].keys()
3615        for El in ElList:
3616            Info = G2elem.GetAtomInfo(El.strip().capitalize())
3617            Info.update(subst['Elements'][El])
3618            data['Substances'][name]['Elements'][El] = Info
3619            if 'Volume' in subst:
3620                data['Substances'][name]['Volume'] = subst['Volume']
3621                data['Substances'][name]['Density'] = \
3622                    G2mth.Vol2Den(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])
3623            elif 'Density' in subst:
3624                data['Substances'][name]['Density'] = subst['Density']
3625                data['Substances'][name]['Volume'] = \
3626                    G2mth.Den2Vol(data['Substances'][name]['Elements'],data['Substances'][name]['Density'])
3627            else:
3628                data['Substances'][name]['Volume'] = G2mth.El2EstVol(data['Substances'][name]['Elements'])
3629                data['Substances'][name]['Density'] = \
3630                    G2mth.Vol2Den(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])
3631            data['Substances'][name]['Scatt density'] = \
3632                G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])[0]
3633            contrst,absorb = G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'],wave)         
3634            data['Substances'][name]['XAnom density'] = contrst
3635            data['Substances'][name]['XAbsorption'] = absorb
3636                         
3637        UpdateSubstanceGrid(G2frame,data)
3638       
3639    def OnCopySubstance(event):
3640        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
3641        histList = GetHistsLikeSelected(G2frame)
3642        if not histList:
3643            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
3644            return
3645        copyList = []
3646        dlg = G2G.G2MultiChoiceDialog(
3647            G2frame.dataFrame, 
3648            'Copy substances from\n'+hst[5:]+' to...',
3649            'Copy substances', histList)
3650        try:
3651            if dlg.ShowModal() == wx.ID_OK:
3652                for i in dlg.GetSelections(): 
3653                    copyList.append(histList[i])
3654        finally:
3655            dlg.Destroy()       
3656        for item in copyList:
3657            Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
3658            Inst = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Instrument Parameters'))[0]
3659            wave = G2mth.getWave(Inst)
3660            ndata = copy.deepcopy(data)
3661            for name in ndata['Substances'].keys():
3662                contrst,absorb = G2mth.XScattDen(ndata['Substances'][name]['Elements'],ndata['Substances'][name]['Volume'],wave)         
3663                ndata['Substances'][name]['XAnom density'] = contrst
3664                ndata['Substances'][name]['XAbsorption'] = absorb
3665            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Substances'),ndata)
3666   
3667    def OnAddSubstance(event):
3668        dlg = wx.TextEntryDialog(None,'Enter a name for this substance','Substance Name Entry','New substance',
3669            style=wx.OK)
3670        if dlg.ShowModal() == wx.ID_OK:
3671            Name = dlg.GetValue()
3672            data['Substances'][Name] = {'Elements':{},'Volume':1.0,'Density':1.0,
3673                'Scatt density':0.0,'XAnom density':0.,'XAbsorption':0.}
3674        dlg.Destroy()
3675        AddElement(Name)
3676        UpdateSubstanceGrid(G2frame,data)
3677       
3678    def OnDeleteSubstance(event):
3679        TextList = []
3680        for name in data['Substances']:
3681            if name != 'vacuum':
3682                TextList += [name,]
3683        if not TextList:
3684            return
3685        dlg = wx.SingleChoiceDialog(G2frame, 'Which substance?', 'Select substance to delete', TextList, wx.CHOICEDLG_STYLE)
3686        try:
3687            if dlg.ShowModal() == wx.ID_OK:
3688                name = TextList[dlg.GetSelection()]
3689            else:
3690                return
3691        finally:
3692            dlg.Destroy()
3693        del(data['Substances'][name])
3694        UpdateSubstanceGrid(G2frame,data)       
3695               
3696    def OnAddElement(event):       
3697        TextList = []
3698        for name in data['Substances']:
3699            if name != 'vacuum':
3700                TextList += [name,]
3701        if not TextList:
3702            return
3703        dlg = wx.SingleChoiceDialog(G2frame, 'Which substance?', 'Select substance', TextList, wx.CHOICEDLG_STYLE)
3704        try:
3705            if dlg.ShowModal() == wx.ID_OK:
3706                name = TextList[dlg.GetSelection()]
3707            else:
3708                return
3709        finally:
3710            dlg.Destroy()
3711        AddElement(name)
3712        UpdateSubstanceGrid(G2frame,data)
3713       
3714    def AddElement(name):
3715        ElList = data['Substances'][name]['Elements'].keys()
3716        dlg = G2elemGUI.PickElements(G2frame,ElList)
3717        if dlg.ShowModal() == wx.ID_OK:
3718            for El in dlg.Elem:
3719                El = El.strip().capitalize()
3720                Info = G2elem.GetAtomInfo(El)
3721                Info.update({'Num':1})
3722                data['Substances'][name]['Elements'][El] = Info
3723            data['Substances'][name]['Volume'] = G2mth.El2EstVol(data['Substances'][name]['Elements'])
3724            data['Substances'][name]['Density'] = \
3725                G2mth.Vol2Den(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])
3726            data['Substances'][name]['Scatt density'] = \
3727                G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])[0]
3728            contrst,absorb = G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'],wave)         
3729            data['Substances'][name]['XAnom density'] = contrst
3730            data['Substances'][name]['XAbsorption'] = absorb
3731        dlg.Destroy()
3732       
3733    def OnDeleteElement(event):
3734        TextList = []
3735        for name in data['Substances']:
3736            if name != 'vacuum':
3737                TextList += [name,]
3738        if not TextList:
3739            return
3740        dlg = wx.SingleChoiceDialog(G2frame, 'Which substance?', 'Select substance', TextList, wx.CHOICEDLG_STYLE)
3741        try:
3742            if dlg.ShowModal() == wx.ID_OK:
3743                name = TextList[dlg.GetSelection()]
3744            else:
3745                return
3746        finally:
3747            dlg.Destroy()
3748        ElList = data['Substances'][name]['Elements'].keys()
3749        if len(ElList):
3750            DE = G2elemGUI.DeleteElement(G2frame,ElList)
3751            if DE.ShowModal() == wx.ID_OK:
3752                El = DE.GetDeleteElement().strip().upper()
3753                del(data['Substances'][name]['Elements'][El])
3754                data['Substances'][name]['Volume'] = G2mth.El2EstVol(data['Substances'][name]['Elements'])
3755                data['Substances'][name]['Density'] = \
3756                    G2mth.Vol2Den(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])
3757                data['Substances'][name]['Scatt density'] = \
3758                    G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])[0]
3759                contrst,absorb = G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'],wave)         
3760                data['Substances'][name]['XAnom density'] = contrst
3761                data['Substances'][name]['XAbsorption'] = absorb
3762        UpdateSubstanceGrid(G2frame,data)
3763               
3764    def SubstSizer():
3765       
3766        def OnValueChange(event):
3767            event.Skip()
3768            Obj = event.GetEventObject()
3769            if len(Indx[Obj.GetId()]) == 3:
3770                name,El,keyId = Indx[Obj.GetId()]
3771                try:
3772                    value = max(0,float(Obj.GetValue()))
3773                except ValueError:
3774                    value = 0
3775                    Obj.SetValue('%.2f'%(value))
3776                data['Substances'][name]['Elements'][El][keyId] = value
3777                data['Substances'][name]['Volume'] = G2mth.El2EstVol(data['Substances'][name]['Elements'])
3778                data['Substances'][name]['Density'] = \
3779                    G2mth.Vol2Den(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])
3780            else:
3781                name,keyId = Indx[Obj.GetId()]
3782                try:
3783                    value = max(0,float(Obj.GetValue()))
3784                except ValueError:
3785                    value = 1.0
3786                data['Substances'][name][keyId] = value
3787                if keyId in 'Volume':
3788                    data['Substances'][name]['Density'] = \
3789                        G2mth.Vol2Den(data['Substances'][name]['Elements'],value)
3790                elif keyId in 'Density':
3791                    data['Substances'][name]['Volume'] = \
3792                        G2mth.Den2Vol(data['Substances'][name]['Elements'],value)
3793            data['Substances'][name]['Scatt density'] = \
3794                G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])[0]
3795            contrst,absorb = G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'],wave)         
3796            data['Substances'][name]['XAnom density'] = contrst
3797            data['Substances'][name]['XAbsorption'] = absorb
3798            wx.CallAfter(UpdateSubstanceGrid,G2frame,data)
3799       
3800        Indx = {}
3801        substSizer = wx.BoxSizer(wx.VERTICAL)
3802        substSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Substance list: wavelength: %.5fA'%(wave)),
3803            0,WACV)
3804        for name in data['Substances']:
3805            G2G.HorizontalLine(substSizer,G2frame.dataDisplay)   
3806            substSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Data for '+name+':'),
3807                0,WACV)
3808            if name == 'vacuum':
3809                substSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label='        Not applicable'),
3810                    0,WACV)
3811            else:   
3812                elSizer = wx.FlexGridSizer(0,6,5,5)
3813                Substance = data['Substances'][name]
3814                Elems = Substance['Elements']
3815                for El in Elems:    #do elements as pull downs for isotopes for neutrons
3816                    elSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' '+El+': '),
3817                        0,WACV)
3818                    num = wx.TextCtrl(G2frame.dataDisplay,value='%.2f'%(Elems[El]['Num']),style=wx.TE_PROCESS_ENTER)
3819                    Indx[num.GetId()] = [name,El,'Num']
3820                    num.Bind(wx.EVT_TEXT_ENTER,OnValueChange)       
3821                    num.Bind(wx.EVT_KILL_FOCUS,OnValueChange)
3822                    elSizer.Add(num,0,WACV)
3823                substSizer.Add(elSizer,0)
3824                vdsSizer = wx.FlexGridSizer(0,4,5,5)
3825                vdsSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Volume: '),
3826                    0,WACV)
3827                vol = wx.TextCtrl(G2frame.dataDisplay,value='%.3f'%(Substance['Volume']),style=wx.TE_PROCESS_ENTER)
3828                Indx[vol.GetId()] = [name,'Volume']
3829                vol.Bind(wx.EVT_TEXT_ENTER,OnValueChange)       
3830                vol.Bind(wx.EVT_KILL_FOCUS,OnValueChange)
3831                vdsSizer.Add(vol,0,WACV)               
3832                vdsSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Density: '),
3833                    0,WACV)
3834                den = wx.TextCtrl(G2frame.dataDisplay,value='%.3f'%(Substance['Density']),style=wx.TE_PROCESS_ENTER)
3835                Indx[den.GetId()] = [name,'Density']
3836                den.Bind(wx.EVT_TEXT_ENTER,OnValueChange)       
3837                den.Bind(wx.EVT_KILL_FOCUS,OnValueChange)
3838                vdsSizer.Add(den,0,WACV)
3839                substSizer.Add(vdsSizer,0)
3840                substSizer.Add(wx.StaticText(G2frame.dataDisplay,
3841                    label=' Scattering density  : %.2f *10%scm%s'%(Substance['Scatt density'],Pwr10,Pwrm2)),
3842                    0,WACV)               
3843                substSizer.Add(wx.StaticText(G2frame.dataDisplay,       #allow neutrons here into NAnom density & NAbsorption
3844                    label=' Anomalous density : %.2f *10%scm%s'%(Substance['XAnom density'],Pwr10,Pwrm2)),
3845                    0,WACV)               
3846                substSizer.Add(wx.StaticText(G2frame.dataDisplay,
3847                    label=' X-ray absorption   : %.2f cm%s'%(Substance['XAbsorption'],Pwrm1)),
3848                    0,WACV)               
3849        return substSizer
3850           
3851    Inst = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Instrument Parameters'))[0]
3852    wave = G2mth.getWave(Inst)
3853    if G2frame.dataDisplay:
3854        G2frame.dataFrame.DestroyChildren()  # is this a ScrolledWindow? If so, bad!
3855    G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.SubstanceMenu)
3856    if not G2frame.dataFrame.GetStatusBar():
3857        Status = G2frame.dataFrame.CreateStatusBar()
3858    G2frame.dataDisplay = wxscroll.ScrolledPanel(G2frame.dataFrame)
3859    G2frame.dataFrame.SetLabel('Substances')
3860    G2frame.dataFrame.Bind(wx.EVT_MENU, OnLoadSubstance, id=G2gd.wxID_LOADSUBSTANCE)   
3861    G2frame.dataFrame.Bind(wx.EVT_MENU, OnAddSubstance, id=G2gd.wxID_ADDSUBSTANCE)
3862    G2frame.dataFrame.Bind(wx.EVT_MENU, OnCopySubstance, id=G2gd.wxID_COPYSUBSTANCE)
3863    G2frame.dataFrame.Bind(wx.EVT_MENU, OnDeleteSubstance, id=G2gd.wxID_DELETESUBSTANCE)   
3864    G2frame.dataFrame.Bind(wx.EVT_MENU, OnAddElement, id=G2gd.wxID_ELEMENTADD)
3865    G2frame.dataFrame.Bind(wx.EVT_MENU, OnDeleteElement, id=G2gd.wxID_ELEMENTDELETE)
3866    mainSizer = wx.BoxSizer(wx.VERTICAL)
3867    mainSizer.Add(SubstSizer(),0)
3868
3869    mainSizer.Layout()   
3870    G2frame.dataDisplay.SetSizer(mainSizer)
3871    G2frame.dataDisplay.SetAutoLayout(1)
3872    G2frame.dataDisplay.SetupScrolling()
3873    Size = mainSizer.Fit(G2frame.dataFrame)
3874    Size[0] += 25
3875    G2frame.dataDisplay.SetSize(Size)
3876    G2frame.dataFrame.setSizePosLeft(Size)   
3877       
3878################################################################################
3879#####  SASD Models
3880################################################################################           
3881       
3882def UpdateModelsGrid(G2frame,data):
3883    '''respond to selection of SASD Models data tree item.
3884    '''
3885    #patches
3886    if 'Current' not in data:
3887        data['Current'] = 'Size dist.'
3888    if 'logBins' not in data['Size']:
3889        data['Size']['logBins'] = True
3890    if 'MinMaxDiam' in data['Size']:
3891        data['Size']['MinDiam'] = 50.
3892        data['Size']['MaxDiam'] = 10000.
3893        del data['Size']['MinMaxDiam']
3894    if isinstance(data['Size']['MaxEnt']['Sky'],float):
3895        data['Size']['MaxEnt']['Sky'] = -3
3896    if 'Power' not in data['Size']['IPG']:
3897        data['Size']['IPG']['Power'] = -1
3898    if 'Matrix' not in data['Particle']:
3899        data['Particle']['Matrix'] = {'Name':'vacuum','VolFrac':[0.0,False]}
3900    if 'BackFile' not in data:
3901        data['BackFile'] = ''
3902    #end patches
3903   
3904    def RefreshPlots(newPlot=False):
3905        PlotText = G2frame.G2plotNB.nb.GetPageText(G2frame.G2plotNB.nb.GetSelection())
3906        if 'Powder' in PlotText:
3907            G2plt.PlotPatterns(G2frame,plotType='SASD',newPlot=newPlot)
3908        elif 'Size' in PlotText:
3909            G2plt.PlotSASDSizeDist(G2frame)
3910               
3911    def OnAddModel(event):
3912        if data['Current'] == 'Particle fit':
3913            material = 'vacuum'
3914            if len(data['Particle']['Levels']):
3915                material = data['Particle']['Levels'][-1]['Controls']['Material']
3916            data['Particle']['Levels'].append({
3917                'Controls':{'FormFact':'Sphere','DistType':'LogNormal','Material':material,
3918                    'FFargs':{},'SFargs':{},'NumPoints':50,'Cutoff':0.01,'Contrast':0.0,
3919                    'SlitSmear':[0.0,False],'StrFact':'Dilute'},    #last 2 not used - future?
3920                'LogNormal':{'Volume':[0.05,False],'Mean':[1000.,False],'StdDev':[0.5,False],'MinSize':[10.,False],},
3921                'Gaussian':{'Volume':[0.05,False],'Mean':[1000.,False],'StdDev':[300.,False],},
3922                'LSW':{'Volume':[0.05,False],'Mean':[1000.0,False],},
3923                'Schulz-Zimm':{'Volume':[0.05,False],'Mean':[1000.,False],'StdDev':[300.,False],},
3924                'Unified':{'G':[1.e3,False],'Rg':[100,False],'B':[1.e-5,False],'P':[4,False],'Cutoff':[1e-5,False],},
3925                'Porod':{'B':[1.e-4,False],'P':[4,False],'Cutoff':[1e-5,False],},
3926                'Monodisperse':{'Volume':[0.05,False],'Radius':[100,False],},   #OK for spheres
3927                'Bragg':{'PkInt':[100,False],'PkPos':[0.2,False],
3928                    'PkSig':[10,False],'PkGam':[10,False],},        #reasonable 31A peak
3929                })
3930            G2sasd.ModelFxn(Profile,ProfDict,Limits,Sample,data)
3931            RefreshPlots(True)
3932                   
3933        wx.CallAfter(UpdateModelsGrid,G2frame,data)
3934       
3935    def OnCopyModel(event):
3936        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
3937        histList = GetHistsLikeSelected(G2frame)
3938        if not histList:
3939            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
3940            return
3941        copyList = []
3942        dlg = G2G.G2MultiChoiceDialog(
3943            G2frame.dataFrame, 
3944            'Copy models from\n'+hst[5:]+' to...',
3945            'Copy models', histList)
3946        try:
3947            if dlg.ShowModal() == wx.ID_OK:
3948                for i in dlg.GetSelections(): 
3949                    copyList.append(histList[i])
3950        finally:
3951            dlg.Destroy()       
3952        for item in copyList:
3953            Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
3954            newdata = copy.deepcopy(data)
3955            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Models'),newdata)
3956            if newdata['BackFile']:
3957                Profile = G2frame.PatternTree.GetItemPyData(Id)[1]
3958                BackId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,newdata['BackFile'])
3959                BackSample = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,BackId, 'Sample Parameters'))
3960                Profile[5] = BackSample['Scale'][0]*G2frame.PatternTree.GetItemPyData(BackId)[1][1]
3961        UpdateModelsGrid(G2frame,newdata) 
3962        wx.CallAfter(UpdateModelsGrid,G2frame,data)
3963        RefreshPlots(True)
3964               
3965    def OnCopyFlags(event):
3966        thisModel = copy.deepcopy(data)
3967        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
3968        histList = GetHistsLikeSelected(G2frame)
3969        if not histList:
3970            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
3971            return
3972        dlg = G2G.G2MultiChoiceDialog(
3973            G2frame.dataFrame, 
3974            'Copy sample ref. flags from\n'+str(hst[5:])+' to...',
3975            'Copy sample flags', histList)
3976        distChoice = ['LogNormal','Gaussian','LSW','Schulz-Zimm','Bragg','Unified',
3977            'Porod','Monodisperse',]
3978        parmOrder = ['Volume','Radius','Mean','StdDev','G','Rg','B','P',
3979            'Cutoff','PkInt','PkPos','PkSig','PkGam','VolFr','Dist',]
3980        try:
3981            if dlg.ShowModal() == wx.ID_OK:
3982                result = dlg.GetSelections()
3983                for i in result: 
3984                    item = histList[i]
3985                    Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
3986                    newModel = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Models'))
3987                    newModel['Back'][1] = copy.copy(thisModel['Back'][1])
3988                    for ilev,level in enumerate(newModel['Particle']['Levels']):
3989                        for form in level:
3990                            if form in distChoice:
3991                                thisForm = thisModel['Particle']['Levels'][ilev][form]                               
3992                                for item in parmOrder:
3993                                    if item in thisForm:
3994                                       level[form][item][1] = copy.copy(thisForm[item][1])
3995                            elif form == 'Controls':
3996                                thisForm = thisModel['Particle']['Levels'][ilev][form]['SFargs']
3997                                for item in parmOrder:
3998                                    if item in thisForm:
3999                                        level[form]['SFargs'][item][1] = copy.copy(thisForm[item][1])
4000        finally:
4001            dlg.Destroy()
4002               
4003    def OnFitModelAll(event):
4004        choices = G2gd.GetPatternTreeDataNames(G2frame,['SASD',])
4005        sel = []
4006        dlg = G2G.G2MultiChoiceDialog(G2frame.dataFrame, 'Sequential SASD refinement',
4007             'Select dataset to include',choices)
4008        dlg.SetSelections(sel)
4009        names = []
4010        if dlg.ShowModal() == wx.ID_OK:
4011            for sel in dlg.GetSelections():
4012                names.append(choices[sel])
4013        dlg.Destroy()
4014        SeqResult = {}
4015        Reverse = False
4016        CopyForward = False
4017        choice = ['Reverse sequence','Copy from prev.']
4018        dlg = wx.MultiChoiceDialog(G2frame.dataFrame,'Sequential controls','Select controls',choice)
4019        if dlg.ShowModal() == wx.ID_OK:
4020            for sel in dlg.GetSelections():
4021                if sel:
4022                    CopyForward = True
4023                else:
4024                    Reverse = True
4025        dlg.Destroy()
4026        dlg = wx.ProgressDialog('SASD Sequential fit','Data set name = '+names[0],len(names), 
4027            style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE|wx.PD_REMAINING_TIME|wx.PD_CAN_ABORT)
4028        wx.BeginBusyCursor()
4029        if Reverse:
4030            names.reverse()
4031        try:
4032            for i,name in enumerate(names):
4033                print ' Sequential fit for ',name
4034                GoOn = dlg.Update(i,newmsg='Data set name = '+name)[0]
4035                if not GoOn:
4036                    break
4037                Id =  G2gd.GetPatternTreeItemId(G2frame,G2frame.root,name)
4038                if i and CopyForward:
4039                    G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Models'),JModel)
4040                IProfDict,IProfile = G2frame.PatternTree.GetItemPyData(Id)[:2]
4041                IModel = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Models'))
4042                ISample = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Sample Parameters'))
4043                ILimits = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Limits'))
4044                IfOK,result,varyList,sig,Rvals,covMatrix,parmDict,Msg = G2sasd.ModelFit(IProfile,IProfDict,ILimits,ISample,IModel)
4045                JModel = copy.deepcopy(IModel)
4046                if not IfOK:
4047                    G2frame.ErrorDialog('Failed sequential refinement for data '+name,
4048                        ' Msg: '+Msg+'\nYou need to rethink your selection of parameters\n'+    \
4049                        ' Model restored to previous version for'+name)
4050                    SeqResult['histNames'] = names[:i]
4051                    dlg.Destroy()
4052                    break
4053                else:
4054                    G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Models'),copy.deepcopy(IModel))
4055               
4056                G2sasd.ModelFxn(IProfile,IProfDict,ILimits,ISample,IModel)
4057                SeqResult[name] = {'variables':result[0],'varyList':varyList,'sig':sig,'Rvals':Rvals,
4058                    'covMatrix':covMatrix,'title':name,'parmDict':parmDict}
4059            else:
4060                dlg.Destroy()
4061                print ' ***** Small angle sequential refinement successful *****'
4062        finally:
4063            wx.EndBusyCursor()   
4064        if Reverse:
4065            names.reverse()
4066        SeqResult['histNames'] = names
4067        Id =  G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Sequential SASD results')
4068        if Id:
4069            G2frame.PatternTree.SetItemPyData(Id,SeqResult)
4070        else:
4071            Id = G2frame.PatternTree.AppendItem(parent=G2frame.root,text='Sequential SASD results')
4072            G2frame.PatternTree.SetItemPyData(Id,SeqResult)
4073        G2frame.PatternTree.SelectItem(Id)
4074       
4075    def OnFitModel(event):
4076        if data['Current'] == 'Size dist.':
4077            if not any(Sample['Contrast']):
4078                G2frame.ErrorDialog('No contrast; your sample is a vacuum!',
4079                    'You need to define a scattering substance!\n'+    \
4080                    ' Do Substances and then Sample parameters')
4081                return
4082            G2sasd.SizeDistribution(Profile,ProfDict,Limits,Sample,data)
4083            G2plt.PlotSASDSizeDist(G2frame)
4084            RefreshPlots(True)
4085           
4086        elif data['Current'] == 'Particle fit':
4087            SaveState()
4088            Results = G2sasd.ModelFit(Profile,ProfDict,Limits,Sample,data)
4089            if not Results[0]:
4090                    G2frame.ErrorDialog('Failed refinement',
4091                        ' Msg: '+Results[-1]+'\nYou need to rethink your selection of parameters\n'+    \
4092                        ' Model restored to previous version')
4093            G2sasd.ModelFxn(Profile,ProfDict,Limits,Sample,data)
4094            RefreshPlots(True)
4095            wx.CallAfter(UpdateModelsGrid,G2frame,data)
4096           
4097    def OnUnDo(event):
4098        DoUnDo()
4099        data = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,
4100            G2frame.PatternId,'Models'))
4101        G2frame.dataFrame.SasdUndo.Enable(False)
4102        UpdateModelsGrid(G2frame,data)
4103        G2sasd.ModelFxn(Profile,ProfDict,Limits,Sample,data)
4104        RefreshPlots(True)
4105
4106    def DoUnDo():
4107        print 'Undo last refinement'
4108        file = open(G2frame.undosasd,'rb')
4109        PatternId = G2frame.PatternId
4110        G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Models'),cPickle.load(file))
4111        print ' Models recovered'
4112        file.close()
4113       
4114    def SaveState():
4115        G2frame.undosasd = os.path.join(G2frame.dirname,'GSASIIsasd.save')
4116        file = open(G2frame.undosasd,'wb')
4117        PatternId = G2frame.PatternId
4118        for item in ['Models']:
4119            cPickle.dump(G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId,item)),file,1)
4120        file.close()
4121        G2frame.dataFrame.SasdUndo.Enable(True)
4122       
4123    def OnSelectFit(event):
4124        data['Current'] = fitSel.GetValue()
4125        wx.CallAfter(UpdateModelsGrid,G2frame,data)
4126       
4127    def OnCheckBox(event):
4128        Obj = event.GetEventObject()
4129        item,ind = Indx[Obj.GetId()]
4130        item[ind] = Obj.GetValue()
4131       
4132    def OnIntVal(event):
4133        event.Skip()
4134        Obj = event.GetEventObject()
4135        item,ind,minVal = Indx[Obj.GetId()]
4136        try:
4137            value = int(Obj.GetValue())
4138            if value <= minVal:
4139                raise ValueError
4140        except ValueError:
4141            value = item[ind]
4142        Obj.SetValue(str(value))
4143        item[ind] = value
4144
4145    def SizeSizer():
4146       
4147        def OnShape(event):
4148            data['Size']['Shape'][0] = partsh.GetValue()
4149            wx.CallAfter(UpdateModelsGrid,G2frame,data)
4150           
4151        def OnMethod(event):
4152            data['Size']['Method'] = method.GetValue()
4153            wx.CallAfter(UpdateModelsGrid,G2frame,data)
4154           
4155        def OnPartVal(event):
4156            event.Skip()
4157            try:
4158                val = max(0.0,float(partprm.GetValue()))
4159            except ValueError:
4160                val = 1
4161            data['Size']['Shape'][1] = val
4162            partprm.SetValue('%.3f'%(val))
4163           
4164        sizeSizer = wx.BoxSizer(wx.VERTICAL)
4165        sizeSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Size distribution parameters: '),0,WACV)
4166        binSizer = wx.FlexGridSizer(0,7,5,5)
4167        binSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' No. size bins: '),0,WACV)
4168        bins = ['50','100','150','200']
4169        nbins = wx.ComboBox(G2frame.dataDisplay,value=str(data['Size']['Nbins']),choices=bins,
4170            style=wx.CB_READONLY|wx.CB_DROPDOWN)
4171        Indx[nbins.GetId()] = [data['Size'],'Nbins',0]
4172        nbins.Bind(wx.EVT_COMBOBOX,OnIntVal)       
4173        binSizer.Add(nbins,0,WACV)
4174        binSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Min diam.: '),0,WACV)
4175        minDias = ['10','25','50','100','150','200']
4176        mindiam = wx.ComboBox(G2frame.dataDisplay,value=str(data['Size']['MinDiam']),choices=minDias,
4177            style=wx.CB_DROPDOWN)
4178        mindiam.Bind(wx.EVT_LEAVE_WINDOW,OnIntVal)
4179        mindiam.Bind(wx.EVT_TEXT_ENTER,OnIntVal)       
4180        mindiam.Bind(wx.EVT_KILL_FOCUS,OnIntVal)
4181        Indx[mindiam.GetId()] = [data['Size'],'MinDiam',0]
4182        binSizer.Add(mindiam,0,WACV)
4183        binSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Max diam.: '),0,WACV)
4184        maxDias = [str(