source: trunk/GSASIIpwdGUI.py @ 2412

Last change on this file since 2412 was 2412, checked in by vondreele, 7 years ago

fixes to PDF stuff

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