source: trunk/GSASIIpwdGUI.py @ 2356

Last change on this file since 2356 was 2356, checked in by vondreele, 6 years ago

revision to RDF calculation/plot

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 241.5 KB
Line 
1# -*- coding: utf-8 -*-
2#GSASIIpwdGUI - powder data display routines
3########### SVN repository information ###################
4# $Date: 2016-07-01 16:52:49 +0000 (Fri, 01 Jul 2016) $
5# $Author: vondreele $
6# $Revision: 2356 $
7# $URL: trunk/GSASIIpwdGUI.py $
8# $Id: GSASIIpwdGUI.py 2356 2016-07-01 16:52:49Z 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: 2356 $")
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 = 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 = G2frame.PeakTable.GetData()
717                G2frame.PatternTree.SetItemPyData(G2frame.PickId,data['peaks'][:-nDel])
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        if event.GetKeyCode() == wx.WXK_DELETE:
1223            row = G2frame.dataDisplay.GetSelectedRows()[0]
1224            if row > 1: #can't delete limits!
1225                del(data[row])
1226                wx.CallAfter(UpdateLimitsGrid,G2frame,data,plottype)
1227                G2plt.PlotPatterns(G2frame,plotType=plottype)
1228                       
1229    def RefreshLimitsGrid(event):
1230        event.StopPropagation()
1231        data = G2frame.LimitsTable.GetData()
1232        old = data[0]
1233        new = data[1]
1234        new[0] = max(old[0],new[0])
1235        new[1] = max(new[0],min(old[1],new[1]))
1236        excl = []
1237        if len(data) > 2:
1238            excl = data[2:]
1239            for item in excl:
1240                item[0] = max(old[0],item[0])
1241                item[1] = max(item[0],min(old[1],item[1]))
1242        data = [old,new]+excl
1243        G2frame.LimitsTable.SetData(data)
1244        G2plt.PlotPatterns(G2frame,plotType=plottype)
1245       
1246    def OnLimitCopy(event):
1247        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
1248        histList = GetHistsLikeSelected(G2frame)
1249        if not histList:
1250            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
1251            return
1252        copyList = []
1253        dlg = G2G.G2MultiChoiceDialog(
1254            G2frame.dataFrame, 
1255            'Copy limits from\n'+str(hst[5:])+' to...',
1256            'Copy limits', histList)
1257        try:
1258            if dlg.ShowModal() == wx.ID_OK:
1259                for i in dlg.GetSelections(): 
1260                    item = histList[i]
1261                    Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
1262                    G2frame.PatternTree.SetItemPyData(
1263                        G2gd.GetPatternTreeItemId(G2frame,Id,'Limits'),copy.copy(data))
1264        finally:
1265            dlg.Destroy()
1266           
1267    def OnAddExcl(event):
1268        G2frame.ifGetExclude = True
1269        print 'Add excluded region'
1270       
1271    G2frame.LimitsTable = []
1272    colLabels = ['Tmin','Tmax']
1273    rowLabels = ['original','changed']
1274    for i in range(len(data)-2):
1275        rowLabels.append('exclude')
1276    Types = 2*[wg.GRID_VALUE_FLOAT+':12,5',]
1277    G2frame.LimitsTable = G2G.Table(data,rowLabels=rowLabels,colLabels=colLabels,types=Types)
1278    G2frame.dataFrame.SetLabel('Limits')
1279    G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.LimitMenu)
1280    if not G2frame.dataFrame.GetStatusBar():
1281        Status = G2frame.dataFrame.CreateStatusBar()
1282    G2frame.Bind(wx.EVT_MENU,OnLimitCopy,id=G2gd.wxID_LIMITCOPY)
1283    G2frame.Bind(wx.EVT_MENU,OnAddExcl,id=G2gd.wxID_ADDEXCLREGION)   
1284    G2frame.dataDisplay = G2G.GSGrid(parent=G2frame.dataFrame)
1285    G2frame.dataDisplay.SetTable(G2frame.LimitsTable, True)   
1286    G2frame.dataDisplay.SetCellStyle(0,0,VERY_LIGHT_GREY,True)
1287    G2frame.dataDisplay.SetCellStyle(0,1,VERY_LIGHT_GREY,True)
1288    G2frame.dataDisplay.Bind(wg.EVT_GRID_CELL_CHANGE, RefreshLimitsGrid)               
1289    G2frame.dataDisplay.Bind(wx.EVT_KEY_DOWN, KeyEditPeakGrid)
1290    G2frame.dataDisplay.SetMargins(0,0)
1291    G2frame.dataDisplay.AutoSizeColumns(False)
1292    G2frame.dataFrame.setSizePosLeft([230,260])                               
1293    G2frame.dataFrame.SendSizeEvent()
1294   
1295################################################################################
1296#####  Instrument parameters
1297################################################################################           
1298       
1299def UpdateInstrumentGrid(G2frame,data):
1300    '''respond to selection of PWDR/SASD Instrument Parameters
1301    data tree item.
1302    '''
1303    if 'Bank' not in data:  #get it from name; absent for default parms selection
1304        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
1305        if 'Bank' in hst:
1306            bank = int(hst.split('Bank')[1].split('_')[0])
1307            data['Bank'] = [bank,bank,0]
1308        else:
1309            data['Bank'] = [1,1,0]
1310
1311    def keycheck(keys):
1312        good = []
1313        for key in keys:
1314            if key in ['Type','Bank','U','V','W','X','Y','SH/L','I(L2)/I(L1)','alpha',
1315                'beta-0','beta-1','beta-q','sig-0','sig-1','sig-2','sig-q','Polariz.',
1316                'Lam','Azimuth','2-theta','fltPath','difC','difA','difB','Zero','Lam1','Lam2']:
1317                good.append(key)
1318        return good
1319       
1320    def updateData(inst,ref):
1321        data = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,
1322            G2frame.PatternId,'Instrument Parameters'))[0]
1323        for item in data:
1324            try:
1325                data[item] = [data[item][0],inst[item],ref[item]]
1326            except KeyError:
1327                try:
1328                    data[item] = [data[item][0],inst[item]]
1329                except KeyError:
1330                    pass        #skip 'Polariz.' for N-data
1331   
1332    def RefreshInstrumentGrid(event,doAnyway=False):
1333        if doAnyway or event.GetRow() == 1:
1334            peaks = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Peak List'))
1335            newpeaks = []
1336            for peak in peaks['peaks']:
1337                newpeaks.append(G2mth.setPeakparms(data,Inst2,peak[0],peak[2]))
1338            peaks['peaks'] = newpeaks
1339            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Peak List'),peaks)
1340           
1341    def OnCalibrate(event):
1342        Pattern = G2frame.PatternTree.GetItemPyData(G2frame.PatternId)
1343        xye = ma.array(ma.getdata(Pattern[1]))
1344        cw = np.diff(xye[0])
1345        IndexPeaks = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Index Peak List'))
1346        if not len(IndexPeaks[0]):
1347            G2frame.ErrorDialog('Can not calibrate','Index Peak List empty')
1348            return
1349        if not np.any(IndexPeaks[1]):
1350            G2frame.ErrorDialog('Can not calibrate','Peak positions not refined')
1351            return False
1352        Ok = False
1353        for peak in IndexPeaks[0]:
1354            if peak[2] and peak[3]:
1355                Ok = True
1356        if not Ok:
1357            G2frame.ErrorDialog('Can not calibrate','Index Peak List not indexed')
1358            return           
1359        if G2pwd.DoCalibInst(IndexPeaks,data):
1360            UpdateInstrumentGrid(G2frame,data)
1361            XY = []
1362            Sigs = []
1363            for ip,peak in enumerate(IndexPeaks[0]):
1364                if peak[2] and peak[3]:
1365                    binwid = cw[np.searchsorted(xye[0],peak[0])]
1366                    XY.append([peak[-1],peak[0],binwid])
1367                    Sigs.append(IndexPeaks[1][ip])
1368            if len(XY):
1369                XY = np.array(XY)
1370                G2plt.PlotCalib(G2frame,data,XY,Sigs,newPlot=True)
1371        else:
1372            G2frame.ErrorDialog('Can not calibrate','Nothing selected for refinement')
1373
1374    def OnLoad(event):
1375        '''Loads instrument parameters from a G2 .instprm file
1376        in response to the Instrument Parameters-Operations/Load Profile menu
1377        If instprm file has multiple banks each with header #Bank n: ..., this
1378        finds matching bank no. to load - rejects nonmatches.
1379       
1380        Note that similar code is found in ReadPowderInstprm (GSASII.py)
1381        '''
1382        data = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,
1383            G2frame.PatternId,'Instrument Parameters'))[0]
1384        bank = data['Bank'][0]
1385        pth = G2G.GetImportPath(G2frame)
1386        if not pth: pth = '.'
1387        dlg = wx.FileDialog(G2frame, 'Choose GSAS-II instrument parameters file', pth, '', 
1388            'instrument parameter files (*.instprm)|*.instprm',wx.OPEN)
1389        try:
1390            if dlg.ShowModal() == wx.ID_OK:
1391                filename = dlg.GetPath()
1392                File = open(filename,'r')
1393                S = File.readline()
1394                newItems = []
1395                newVals = []
1396                Found = False
1397                while S:
1398                    if S[0] == '#':
1399                        if Found:
1400                            break
1401                        if 'Bank' in S:
1402                            if bank == int(S.split(':')[0].split()[1]):
1403                                S = File.readline()
1404                                continue
1405                            else:
1406                                S = File.readline()
1407                                while S and '#Bank' not in S:
1408                                    S = File.readline()
1409                                continue
1410                        else:   #a non #Bank file
1411                            S = File.readline()
1412                            continue
1413                    Found = True
1414                    [item,val] = S[:-1].split(':')
1415                    newItems.append(item)
1416                    try:
1417                        newVals.append(float(val))
1418                    except ValueError:
1419                        newVals.append(val)                       
1420                    S = File.readline()               
1421                File.close()
1422                if Found:
1423                    Inst,Inst2 = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId,'Instrument Parameters'))
1424                    if 'Bank' not in Inst:  #patch for old .instprm files - may cause faults for TOF data
1425                        Inst['Bank'] = [1,1,0]
1426                    data = G2IO.makeInstDict(newItems,newVals,len(newVals)*[False,])
1427                    G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId,'Instrument Parameters'),[data,Inst2])
1428                    RefreshInstrumentGrid(event,doAnyway=True)          #to get peaks updated
1429                else:
1430                    G2frame.ErrorDialog('No match','Bank %d not in %s'%(bank,filename),G2frame.dataFrame)
1431                UpdateInstrumentGrid(G2frame,data)
1432                G2plt.PlotPeakWidths(G2frame)
1433        finally:
1434            dlg.Destroy()
1435       
1436    def OnSave(event):
1437        '''Respond to the Instrument Parameters Operations/Save Profile menu
1438        item: writes current parameters to a .instprm file
1439        It does not write Bank n: on # line & thus can be used any time w/o clash of bank nos.
1440        '''
1441        pth = G2G.GetExportPath(G2frame)
1442        dlg = wx.FileDialog(G2frame, 'Choose GSAS-II instrument parameters file', pth, '', 
1443            'instrument parameter files (*.instprm)|*.instprm',wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT)
1444        try:
1445            if dlg.ShowModal() == wx.ID_OK:
1446                filename = dlg.GetPath()
1447                # make sure extension is .instprm
1448                filename = os.path.splitext(filename)[0]+'.instprm'
1449                File = open(filename,'w')
1450                File.write("#GSAS-II instrument parameter file; do not add/delete items!\n")
1451                for item in data:
1452                    File.write(item+':'+str(data[item][1])+'\n')
1453                File.close()
1454        finally:
1455            dlg.Destroy()
1456           
1457    def OnSaveAll(event):
1458        '''Respond to the Instrument Parameters Operations/Save all Profile menu & writes
1459        selected inst parms. across multiple banks into a single file
1460        Each block starts with #Bank n: GSAS-II instrument... where n is bank no.
1461        item: writes parameters from selected PWDR entries to a .instprm file
1462        '''
1463        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
1464        histList = GetHistsLikeSelected(G2frame)
1465        histList.insert(0,hst)
1466        saveList = []
1467        dlg = G2G.G2MultiChoiceDialog(
1468            G2frame.dataFrame, 
1469            'Save instrument parameters from',
1470            'Save instrument parameters', histList)
1471        try:
1472            if dlg.ShowModal() == wx.ID_OK:
1473                for i in dlg.GetSelections():
1474                    saveList.append(histList[i])
1475        finally:
1476            dlg.Destroy()
1477        pth = G2G.GetExportPath(G2frame)
1478        dlg = wx.FileDialog(G2frame, 'Choose GSAS-II instrument parameters file', pth, '', 
1479            'instrument parameter files (*.instprm)|*.instprm',wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT)
1480        try:
1481            if dlg.ShowModal() == wx.ID_OK:
1482                filename = dlg.GetPath()
1483                # make sure extension is .instprm
1484                filename = os.path.splitext(filename)[0]+'.instprm'
1485                File = open(filename,'w')
1486                for hist in saveList:
1487                    Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,hist)
1488                    inst = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Instrument Parameters'))[0]
1489                    if 'Bank' not in inst:  #patch
1490                        bank = 1
1491                        if 'Bank' in hist:
1492                            bank = int(hist.split('Bank')[1])
1493                        inst['Bank'] = [bank,bank,0]
1494                    bank = inst['Bank'][0]               
1495                    File.write("#Bank %d: GSAS-II instrument parameter file; do not add/delete items!\n"%(bank))
1496                    for item in inst:
1497                        File.write(item+':'+str(inst[item][1])+'\n')                                   
1498                File.close()
1499        finally:
1500            dlg.Destroy()
1501                                               
1502    def OnReset(event):
1503        insVal.update(insDef)
1504        updateData(insVal,insRef)
1505        RefreshInstrumentGrid(event,doAnyway=True)          #to get peaks updated
1506        UpdateInstrumentGrid(G2frame,data)
1507        G2plt.PlotPeakWidths(G2frame)
1508       
1509    def OnInstFlagCopy(event):
1510        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
1511        histList = GetHistsLikeSelected(G2frame)
1512        if not histList:
1513            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
1514            return
1515        keys = data.keys()
1516        try:
1517            keys.remove('Source')
1518        except ValueError:
1519            pass
1520        flags = dict(zip(keys,[data[key][2] for key in keys]))
1521        instType = data['Type'][0]
1522        copyList = []
1523        dlg = G2G.G2MultiChoiceDialog(
1524            G2frame.dataFrame, 
1525            'Copy inst ref. flags from\n'+hst[5:],
1526            'Copy refinement flags', histList)
1527        try:
1528            if dlg.ShowModal() == wx.ID_OK:
1529                for i in dlg.GetSelections():
1530                    copyList.append(histList[i])
1531        finally:
1532            dlg.Destroy()
1533        for item in copyList:
1534            Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
1535            instData = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Instrument Parameters'))[0]
1536            if len(data) == len(instData) and instType == instData['Type'][0]:   #don't mix data types or lam & lam1/lam2 parms!
1537                for item in instData:
1538                    if item not in ['Source',]:
1539                        instData[item][2] = copy.copy(flags[item])
1540            else:
1541                print item+' not copied - instrument parameters not commensurate'
1542       
1543    def OnInstCopy(event):
1544        #need fix for dictionary
1545        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
1546        histList = GetHistsLikeSelected(G2frame)
1547        if not histList:
1548            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
1549            return
1550        copyList = []
1551        instType = data['Type'][0]
1552        dlg = G2G.G2MultiChoiceDialog(
1553            G2frame.dataFrame, 
1554            'Copy inst params from\n'+hst,
1555            'Copy parameters', histList)
1556        try:
1557            if dlg.ShowModal() == wx.ID_OK:
1558                for i in dlg.GetSelections(): 
1559                    copyList.append(histList[i])
1560        finally:
1561            dlg.Destroy()
1562        for item in copyList:
1563            Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
1564            instData = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Instrument Parameters'))[0]
1565            if len(data) == len(instData) and instType == instData['Type'][0]:  #don't mix data types or lam & lam1/lam2 parms!
1566                instData.update(data)
1567            else:
1568                print item+' not copied - instrument parameters not commensurate'
1569                         
1570    def AfterChange(invalid,value,tc):
1571        if invalid: return
1572        updateData(insVal,insRef)
1573       
1574    def OnItemRef(event):
1575        Obj = event.GetEventObject()
1576        item = RefObj[Obj.GetId()]
1577        insRef[item] = Obj.GetValue()
1578        updateData(insVal,insRef)
1579
1580    def OnCopy1Val(event):
1581        '''Select one instrument parameter value to edit and copy to many histograms
1582        optionally allow values to be edited in a table
1583        '''
1584        updateData(insVal,insRef)
1585        G2G.SelectEdit1Var(G2frame,data,labelLst,elemKeysLst,dspLst,refFlgElem)
1586        insVal.update({key:data[key][1] for key in instkeys})
1587        insRef.update({key:data[key][2] for key in instkeys})
1588        wx.CallAfter(MakeParameterWindow)
1589       
1590    def lblWdef(lbl,dec,val):
1591        'Label parameter showing the default value'
1592        fmt = "%15."+str(dec)+"f"
1593        return " " + lbl + " (" + (fmt % val).strip() + "): "
1594
1595    def RefineBox(item):
1596        'Define a refine checkbox with binding'
1597        wid = wx.CheckBox(G2frame.dataDisplay,label=' Refine?  ')
1598        wid.SetValue(bool(insRef[item]))
1599        RefObj[wid.GetId()] = item
1600        wid.Bind(wx.EVT_CHECKBOX, OnItemRef)
1601        return wid
1602
1603    def OnLamPick(event):
1604        data['Source'][1] = lamType = event.GetEventObject().GetValue()
1605        if 'P' in insVal['Type']:
1606            insVal['Lam1'] = waves[lamType][0]
1607            insVal['Lam2'] = waves[lamType][1]
1608        elif 'S' in insVal['Type'] and 'synch' not in lamType:
1609            insVal['Lam'] = meanwaves[lamType]
1610        updateData(insVal,insRef)
1611        i,j= wx.__version__.split('.')[0:2]
1612        if int(i)+int(j)/10. > 2.8:
1613            pass # repaint crashes wxpython 2.9
1614            wx.CallLater(100, MakeParameterWindow)
1615            #wx.CallAfter(MakeParameterWindow)
1616        else:
1617            wx.CallAfter(MakeParameterWindow)
1618
1619    def MakeParameterWindow():
1620        'Displays the Instrument parameters in the datadisplay frame'
1621        if G2frame.dataDisplay:
1622            G2frame.dataFrame.Clear()
1623        G2frame.dataFrame.SetLabel('Instrument Parameters')
1624        G2frame.dataDisplay = wx.Panel(G2frame.dataFrame)
1625        mainSizer = wx.BoxSizer(wx.VERTICAL)
1626        instSizer = wx.FlexGridSizer(0,6,5,5)
1627        subSizer = wx.BoxSizer(wx.HORIZONTAL)
1628        text = ' Histogram Type: %s  Bank: %d'%(insVal['Type'],insVal['Bank'])
1629        subSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,text),0,WACV)
1630        mainSizer.Add(subSizer)
1631        labelLst[:],elemKeysLst[:],dspLst[:],refFlgElem[:] = [],[],[],[]
1632        if 'P' in insVal['Type']:                   #powder data
1633            if 'C' in insVal['Type']:               #constant wavelength
1634                labelLst.append('Azimuth angle')
1635                elemKeysLst.append(['Azimuth',1])
1636                dspLst.append([10,2])
1637                refFlgElem.append(None)                   
1638                if 'Lam1' in insVal:
1639                    subSizer = wx.BoxSizer(wx.HORIZONTAL)
1640                    subSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' Azimuth: '),0,WACV)
1641                    txt = '%7.2f'%(insVal['Azimuth'])
1642                    subSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,txt.strip()),0,WACV)
1643                    subSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,'   Ka1/Ka2: '),0,WACV)
1644                    txt = u%8.6f/%8.6f\xc5'%(insVal['Lam1'],insVal['Lam2'])
1645                    subSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,txt.strip()),0,WACV)
1646                    waveSizer = wx.BoxSizer(wx.HORIZONTAL)
1647                    waveSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,'  Source type: '),0,WACV)
1648                    # PATCH?: for now at least, Source is not saved anywhere before here
1649                    if 'Source' not in data: data['Source'] = ['CuKa','?']
1650                    choice = ['TiKa','CrKa','FeKa','CoKa','CuKa','MoKa','AgKa']
1651                    lamPick = wx.ComboBox(G2frame.dataDisplay,value=data['Source'][1],choices=choice,style=wx.CB_READONLY|wx.CB_DROPDOWN)
1652                    lamPick.Bind(wx.EVT_COMBOBOX, OnLamPick)
1653                    waveSizer.Add(lamPick,0)
1654                    subSizer.Add(waveSizer,0)
1655                    mainSizer.Add(subSizer)
1656                    instSizer.Add(wx.StaticText(
1657                        G2frame.dataDisplay,-1,
1658                        lblWdef('I(L2)/I(L1)',4,insDef['I(L2)/I(L1)'])),
1659                        0,WACV)
1660                    key = 'I(L2)/I(L1)'
1661                    labelLst.append(key)
1662                    elemKeysLst.append([key,1])
1663                    dspLst.append([10,4])
1664                    refFlgElem.append([key,2])                   
1665                    ratVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,insVal,key,nDig=(10,4),typeHint=float,OnLeave=AfterChange)
1666                    instSizer.Add(ratVal,0)
1667                    instSizer.Add(RefineBox(key),0,WACV)
1668                    instSizer.Add((5,5),0)
1669                    instSizer.Add((5,5),0)
1670                    instSizer.Add((5,5),0)               
1671                else: # single wavelength
1672                    instSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' Azimuth: '),0,WACV)
1673                    txt = '%7.2f'%(insVal['Azimuth'])
1674                    instSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,txt.strip()),0,WACV)
1675                    instSizer.Add((5,5),0)
1676                    key = 'Lam'
1677                    instSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,u' Lam (\xc5): (%10.6f)'%(insDef[key])),
1678                        0,WACV)
1679                    waveVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,insVal,key,nDig=(10,6),typeHint=float,OnLeave=AfterChange)
1680                    labelLst.append(u'Lam (\xc5)')
1681                    elemKeysLst.append([key,1])
1682                    dspLst.append([10,6])
1683                    instSizer.Add(waveVal,0,WACV)
1684                    refFlgElem.append([key,2])                   
1685                    instSizer.Add(RefineBox(key),0,WACV)
1686#                    if ifHisto:
1687#                        refFlgElem.append([key,2])                   
1688#                        instSizer.Add(RefineBox(key),0,WACV)
1689#                    else:
1690#                        refFlgElem.append(None)                   
1691#                        instSizer.Add((5,5),0)
1692                for item in ['Zero','Polariz.']:
1693                    if item in insDef:
1694                        labelLst.append(item)
1695                        elemKeysLst.append([item,1])
1696                        dspLst.append([10,4])
1697                        instSizer.Add(
1698                            wx.StaticText(G2frame.dataDisplay,-1,lblWdef(item,4,insDef[item])),
1699                            0,WACV)
1700                        itemVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,insVal,item,nDig=(10,4),typeHint=float,OnLeave=AfterChange)
1701                        instSizer.Add(itemVal,0,WACV)
1702                        refFlgElem.append([item,2])
1703                        instSizer.Add(RefineBox(item),0,WACV)
1704#                        if ifHisto:
1705#                            refFlgElem.append([item,2])
1706#                            instSizer.Add(RefineBox(item),0,WACV)
1707#                        else:
1708#                            refFlgElem.append(None)                   
1709#                            instSizer.Add((5,5),0)
1710                    else:                           #skip Polariz. for neutrons
1711                        instSizer.Add((5,5),0)
1712                        instSizer.Add((5,5),0)
1713                        instSizer.Add((5,5),0)
1714                for item in ['U','V','W','','X','Y','SH/L']:
1715                    if item == '':
1716                        instSizer.Add((5,5),0)
1717                        instSizer.Add((5,5),0)
1718                        instSizer.Add((5,5),0)
1719                        continue
1720                    nDig = (10,3)
1721                    if item == 'SH/L':
1722                        nDig = (10,5)
1723                    labelLst.append(item)
1724                    elemKeysLst.append([item,1])
1725                    dspLst.append(nDig)
1726                    refFlgElem.append([item,2])
1727                    instSizer.Add(
1728                        wx.StaticText(G2frame.dataDisplay,-1,lblWdef(item,nDig[1],insDef[item])),
1729                        0,WACV)
1730                    itemVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,insVal,item,nDig=nDig,typeHint=float,OnLeave=AfterChange)
1731                    instSizer.Add(itemVal,0,WACV)
1732                    instSizer.Add(RefineBox(item),0,WACV)
1733            elif 'T' in insVal['Type']:                                   #time of flight (neutrons)
1734                subSizer = wx.BoxSizer(wx.HORIZONTAL)
1735                subSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' Fligth path: '),0,WACV)
1736                txt = '%8.3f'%(insVal['fltPath'])
1737                subSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,txt.strip()),0,WACV)
1738                labelLst.append('flight path')
1739                elemKeysLst.append(['fltpath',1])
1740                dspLst.append([10,2])
1741                refFlgElem.append(None)                   
1742                subSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,'  2-theta: '),0,WACV)
1743                txt = '%7.2f'%(insVal['2-theta'])
1744                subSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,txt.strip()),0,WACV)
1745                labelLst.append('2-theta')
1746                elemKeysLst.append(['2-theta',1])
1747                dspLst.append([10,2])
1748                refFlgElem.append(None)                   
1749                if 'Pdabc' in Inst2:
1750                    Items = ['sig-0','sig-1','sig-2','sig-q','X','Y']
1751                    subSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,'  difC: '),0,WACV)
1752                    txt = '%8.2f'%(insVal['difC'])
1753                    subSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,txt.strip()),0,WACV)
1754                    labelLst.append('difC')
1755                    elemKeysLst.append(['difC',1])
1756                    dspLst.append([10,2])
1757                    refFlgElem.append(None)
1758                    subSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,'  alpha, beta: fixed by table'),0,WACV)
1759                else:
1760                    Items = ['difC','difA','difB','Zero','alpha','beta-0','beta-1','beta-q','sig-0','sig-1','sig-2','sig-q','X','Y']
1761                mainSizer.Add((5,5),0)
1762                mainSizer.Add(subSizer)
1763                mainSizer.Add((5,5),0)
1764                for item in Items:
1765                    if item == '':
1766                        instSizer.Add((5,5),0)
1767                        instSizer.Add((5,5),0)
1768                        instSizer.Add((5,5),0)
1769                        continue
1770                    nDig = (10,3)
1771                    fmt = '%10.3f'
1772                    if 'beta' in item:
1773                        fmt = '%12.6g'
1774                        nDig = (12,6)
1775                    Fmt = ' %s: ('+fmt+')'
1776                    instSizer.Add(
1777                            wx.StaticText(G2frame.dataDisplay,-1,lblWdef(item,nDig[1],insDef[item])),
1778                            0,WACV)
1779                    itemVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,insVal,item,nDig=nDig,typeHint=float,OnLeave=AfterChange)
1780                    instSizer.Add(itemVal,0,WACV)
1781                    labelLst.append(item)
1782                    elemKeysLst.append([item,1])
1783                    dspLst.append(nDig)
1784                    refFlgElem.append([item,2])
1785                    instSizer.Add(RefineBox(item),0,WACV)
1786            elif 'PKS' in insVal['Type']:   #peak positions only
1787                key = 'Lam'
1788                instSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,u' Lam (\xc5): (%10.6f)'%(insDef[key])),
1789                    0,WACV)
1790                waveVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,insVal,key,nDig=(10,6),typeHint=float,OnLeave=AfterChange)
1791                labelLst.append(u'Lam (\xc5)')
1792                elemKeysLst.append([key,1])
1793                dspLst.append([10,6])
1794                instSizer.Add(waveVal,0,WACV)
1795                refFlgElem.append([key,2])                   
1796#                    instSizer.Add(RefineBox(key),0,WACV)
1797                for item in ['Zero',]:
1798                    if item in insDef:
1799                        labelLst.append(item)
1800                        elemKeysLst.append([item,1])
1801                        dspLst.append([10,4])
1802                        instSizer.Add(
1803                            wx.StaticText(G2frame.dataDisplay,-1,lblWdef(item,4,insDef[item])),
1804                            0,WACV)
1805                        itemVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,insVal,item,nDig=(10,4),typeHint=float,OnLeave=AfterChange)
1806                        instSizer.Add(itemVal,0,WACV)
1807                        refFlgElem.append([item,2])
1808#                        instSizer.Add(RefineBox(item),0,WACV)
1809               
1810               
1811        elif 'S' in insVal['Type']:                       #single crystal data
1812            if 'C' in insVal['Type']:               #constant wavelength
1813                instSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,u' Lam (\xc5): (%10.6f)'%(insDef['Lam'])),
1814                    0,WACV)
1815                waveVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,insVal,'Lam',nDig=(10,6),typeHint=float,OnLeave=AfterChange)
1816                instSizer.Add(waveVal,0,WACV)
1817                labelLst.append(u'Lam (\xc5)')
1818                waveSizer = wx.BoxSizer(wx.HORIZONTAL)
1819                waveSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,'  Source type: '),0,WACV)
1820                # PATCH?: for now at least, Source is not saved anywhere before here
1821                if 'Source' not in data: data['Source'] = ['CuKa','?']
1822                choice = ['synchrotron','TiKa','CrKa','FeKa','CoKa','CuKa','MoKa','AgKa']
1823                lamPick = wx.ComboBox(G2frame.dataDisplay,value=data['Source'][1],choices=choice,style=wx.CB_READONLY|wx.CB_DROPDOWN)
1824                lamPick.Bind(wx.EVT_COMBOBOX, OnLamPick)
1825                waveSizer.Add(lamPick,0,WACV)
1826                instSizer.Add(waveSizer,0,WACV)
1827                elemKeysLst.append(['Lam',1])
1828                dspLst.append([10,6])
1829                refFlgElem.append(None)
1830            else:                                   #time of flight (neutrons)
1831                pass                                #for now
1832        elif 'L' in insVal['Type']:
1833            if 'C' in insVal['Type']:       
1834                instSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,u' Lam (\xc5): (%10.6f)'%(insDef['Lam'])),
1835                    0,WACV)
1836                waveVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,insVal,'Lam',nDig=(10,6),typeHint=float,OnLeave=AfterChange)
1837                instSizer.Add(waveVal,0,WACV)
1838                labelLst.append(u'Lam (\xc5)')
1839                elemKeysLst.append(['Lam',1])
1840                dspLst.append([10,6])
1841                refFlgElem.append(None)
1842                instSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,'  Azimuth: %7.2f'%(insVal['Azimuth'])),0,WACV)
1843                labelLst.append('Azimuth angle')
1844                elemKeysLst.append(['Azimuth',1])
1845                dspLst.append([10,2])
1846                refFlgElem.append(None)                   
1847            else:                                   #time of flight (neutrons)
1848                pass                                #for now
1849
1850        mainSizer.Add(instSizer,0)
1851        mainSizer.Layout()   
1852        G2frame.dataDisplay.SetSizer(mainSizer)
1853        G2frame.dataFrame.setSizePosLeft(mainSizer.Fit(G2frame.dataFrame))
1854        G2frame.dataFrame.SendSizeEvent()  # this causes a frame repaint, even if the size does not change!
1855        # end of MakeParameterWindow
1856               
1857    # beginning of UpdateInstrumentGrid code   
1858    #patch: make sure all parameter items are lists
1859    patched = 0
1860    for key in data:
1861        if type(data[key]) is tuple:
1862            data[key] = list(data[key])
1863            patched += 1
1864    if patched: print patched,' instrument parameters changed from tuples'
1865    #end of patch
1866    labelLst,elemKeysLst,dspLst,refFlgElem = [],[],[],[]
1867    instkeys = keycheck(data.keys())
1868    if 'P' in data['Type'][0]:          #powder data
1869        insVal = dict(zip(instkeys,[data[key][1] for key in instkeys]))
1870        insDef = dict(zip(instkeys,[data[key][0] for key in instkeys]))
1871        insRef = dict(zip(instkeys,[data[key][2] for key in instkeys]))
1872        if 'NC' in data['Type'][0]:
1873            del(insDef['Polariz.'])
1874            del(insVal['Polariz.'])
1875            del(insRef['Polariz.'])
1876    elif 'S' in data['Type'][0]:                               #single crystal data
1877        insVal = dict(zip(instkeys,[data[key][1] for key in instkeys]))
1878        insDef = dict(zip(instkeys,[data[key][0] for key in instkeys]))
1879        insRef = {}
1880    elif 'L' in data['Type'][0]:                               #low angle 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    ValObj = {}
1885    RefObj = {}
1886    waves = {'CuKa':[1.54051,1.54433],'TiKa':[2.74841,2.75207],'CrKa':[2.28962,2.29351],
1887        'FeKa':[1.93597,1.93991],'CoKa':[1.78892,1.79278],'MoKa':[0.70926,0.713543],
1888        'AgKa':[0.559363,0.563775]}
1889    meanwaves = {'CuKa':1.5418,'TiKa':2.7496,'CrKa':2.2909,'FeKa':1.9373,
1890        'CoKa':1.7902,'MoKa':0.7107,'AgKa':0.5608}
1891    Inst2 = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,
1892            G2frame.PatternId,'Instrument Parameters'))[1]       
1893    try:
1894        histoName = G2frame.PatternTree.GetItemPyData(G2frame.PatternId)[-1]
1895        ifHisto = IsHistogramInAnyPhase(G2frame,histoName)
1896    except TypeError:       #PKS data never used in a phase as data
1897        ifhisto = False
1898    G2gd.SetDataMenuBar(G2frame)
1899    #patch
1900    if 'P' in insVal['Type']:                   #powder data
1901        if 'C' in insVal['Type']:               #constant wavelength
1902            if 'Azimuth' not in insVal:
1903                insVal['Azimuth'] = 0.0
1904                insDef['Azimuth'] = 0.0
1905                insRef['Azimuth'] = False
1906#        if 'T' in insVal['Type']:
1907#            if 'difB' not in insVal:
1908#                insVal['difB'] = 0.0
1909#                insDef['difB'] = 0.0
1910#                insRef['difB'] = False
1911    #end of patch
1912    if 'P' in insVal['Type']:                   #powder data menu commands
1913        G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.InstMenu)
1914        if not G2frame.dataFrame.GetStatusBar():
1915            Status = G2frame.dataFrame.CreateStatusBar()           
1916            Status.SetStatusText('NB: Azimuth is used for polarization only')
1917        G2frame.Bind(wx.EVT_MENU,OnCalibrate,id=G2gd.wxID_INSTCALIB)
1918        G2frame.Bind(wx.EVT_MENU,OnLoad,id=G2gd.wxID_INSTLOAD)
1919        G2frame.Bind(wx.EVT_MENU,OnSave,id=G2gd.wxID_INSTSAVE)
1920        G2frame.Bind(wx.EVT_MENU,OnSaveAll,id=G2gd.wxID_INSTSAVEALL)
1921        G2frame.Bind(wx.EVT_MENU,OnReset,id=G2gd.wxID_INSTPRMRESET)
1922        G2frame.Bind(wx.EVT_MENU,OnInstCopy,id=G2gd.wxID_INSTCOPY)
1923        G2frame.Bind(wx.EVT_MENU,OnInstFlagCopy,id=G2gd.wxID_INSTFLAGCOPY)
1924        #G2frame.Bind(wx.EVT_MENU,OnWaveChange,id=G2gd.wxID_CHANGEWAVETYPE)       
1925        G2frame.Bind(wx.EVT_MENU,OnCopy1Val,id=G2gd.wxID_INST1VAL)
1926    elif 'L' in insVal['Type']:                   #SASD data menu commands
1927        G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.SASDInstMenu)
1928        if not G2frame.dataFrame.GetStatusBar():
1929            Status = G2frame.dataFrame.CreateStatusBar()
1930        G2frame.Bind(wx.EVT_MENU,OnInstCopy,id=G2gd.wxID_INSTCOPY)
1931    MakeParameterWindow()
1932       
1933   
1934################################################################################
1935#####  Sample parameters
1936################################################################################           
1937       
1938def UpdateSampleGrid(G2frame,data):
1939    '''respond to selection of PWDR/SASD Sample Parameters
1940    data tree item.
1941    '''
1942
1943    def OnSampleSave(event):
1944        '''Respond to the Sample Parameters Operations/Save menu
1945        item: writes current parameters to a .samprm file
1946        '''
1947        pth = G2G.GetExportPath(G2frame)
1948        dlg = wx.FileDialog(G2frame, 'Choose GSAS-II sample parameters file', pth, '', 
1949            'sample parameter files (*.samprm)|*.samprm',wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT)
1950        try:
1951            if dlg.ShowModal() == wx.ID_OK:
1952                filename = dlg.GetPath()
1953                # make sure extension is .samprm
1954                filename = os.path.splitext(filename)[0]+'.samprm'
1955                File = open(filename,'w')
1956                File.write("#GSAS-II sample parameter file\n")
1957                File.write("'Type':'"+str(data['Type'])+"'\n")
1958                File.write("'Gonio. radius':"+str(data['Gonio. radius'])+"\n")
1959                if data.get('InstrName'):
1960                    File.write("'InstrName':'"+str(data['InstrName'])+"'\n")
1961                File.close()
1962        finally:
1963            dlg.Destroy()
1964           
1965    def OnSampleLoad(event):
1966        '''Loads sample parameters from a G2 .samprm file
1967        in response to the Sample Parameters-Operations/Load menu
1968       
1969        Note that similar code is found in ReadPowderInstprm (GSASII.py)
1970        '''
1971        pth = G2G.GetImportPath(G2frame)
1972        if not pth: pth = '.'
1973        dlg = wx.FileDialog(G2frame, 'Choose GSAS-II sample parameters file', pth, '', 
1974            'sample parameter files (*.samprm)|*.samprm',wx.OPEN)
1975        try:
1976            if dlg.ShowModal() == wx.ID_OK:
1977                filename = dlg.GetPath()
1978                File = open(filename,'r')
1979                S = File.readline()
1980                newItems = {}
1981                while S:
1982                    if S[0] == '#':
1983                        S = File.readline()
1984                        continue
1985                    [item,val] = S[:-1].split(':')
1986                    newItems[item.strip("'")] = eval(val)
1987                    S = File.readline()               
1988                File.close()
1989                data.update(newItems)
1990                G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId,'Sample Parameters'),data)
1991                UpdateSampleGrid(G2frame,data)
1992        finally:
1993            dlg.Destroy()
1994           
1995    def OnAllSampleLoad(event):
1996        filename = ''
1997        pth = G2G.GetImportPath(G2frame)
1998        if not pth: pth = '.'
1999        dlg = wx.FileDialog(G2frame, 'Choose multihistogram metadata text file', pth, '', 
2000            'metadata file (*.*)|*.*',wx.OPEN)
2001        try:
2002            if dlg.ShowModal() == wx.ID_OK:
2003                filename = dlg.GetPath()
2004                File = open(filename,'r')
2005                S = File.readline()
2006                newItems = []
2007                itemNames = []
2008                Comments = []
2009                while S:
2010                    if S[0] == '#':
2011                        Comments.append(S)
2012                        S = File.readline()
2013                        continue
2014                    S = S.replace(',',' ').replace('\t',' ')
2015                    Stuff = S[:-1].split()
2016                    itemNames.append(Stuff[0])
2017                    newItems.append(Stuff[1:])
2018                    S = File.readline()               
2019                File.close()
2020        finally:
2021            dlg.Destroy()
2022        if not filename:
2023            G2frame.ErrorDialog('Nothing to do','No file selected')
2024            return
2025        dataDict = dict(zip(itemNames,newItems))
2026        ifany = False
2027        Controls = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Controls'))
2028        Names = [' ','Phi','Chi','Omega','Time','Temperature','Pressure']
2029        freeNames = {}
2030        for name in ['FreePrm1','FreePrm2','FreePrm3']:
2031            freeNames[Controls[name]] = name
2032            Names.append(Controls[name])
2033        dlg = G2G.G2ColumnIDDialog( G2frame,' Choose multihistogram metadata columns:',
2034            'Select columns',Comments,Names,np.array(newItems).T)
2035        try:
2036            if dlg.ShowModal() == wx.ID_OK:
2037                colNames,newData = dlg.GetSelection()
2038                dataDict = dict(zip(itemNames,newData.T))
2039                for item in colNames:
2040                    if item != ' ':
2041                        ifany = True
2042        finally:
2043            dlg.Destroy()
2044        if not ifany:
2045            G2frame.ErrorDialog('Nothing to do','No columns identified')
2046            return
2047        histList = [G2frame.PatternTree.GetItemText(G2frame.PatternId),]
2048        histList += GetHistsLikeSelected(G2frame)
2049        colIds = {}
2050        for i,name in enumerate(colNames):
2051            if name != ' ':
2052                colIds[name] = i
2053        for hist in histList:
2054            name = hist.split()[1]  #this is file name
2055            newItems = {}
2056            for item in colIds:
2057                key = freeNames.get(item,item)
2058                newItems[key] = float(dataDict[name][colIds[item]])
2059            Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,hist)
2060            sampleData = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Sample Parameters'))
2061            sampleData.update(newItems)       
2062        UpdateSampleGrid(G2frame,data)       
2063   
2064    def OnSetScale(event):
2065        histList = []
2066        item, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)
2067        while item:
2068            name = G2frame.PatternTree.GetItemText(item)
2069            if 'SASD' in name and name != histName:
2070                histList.append(name)
2071            item, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)
2072        if not len(histList):      #nothing to copy to!
2073            return
2074        dlg = wx.SingleChoiceDialog(G2frame,'Select reference histogram for scaling',
2075            'Reference histogram',histList)
2076        try:
2077            if dlg.ShowModal() == wx.ID_OK:
2078                sel = dlg.GetSelection()
2079                refHist = histList[sel]
2080        finally:
2081            dlg.Destroy()
2082        Limits = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Limits'))
2083        Profile = G2frame.PatternTree.GetItemPyData(G2frame.PatternId)[1]
2084        Data = [Profile,Limits,data]
2085        refId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,refHist)
2086        refSample = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,refId, 'Sample Parameters'))
2087        refLimits = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,refId, 'Limits'))
2088        refProfile = G2frame.PatternTree.GetItemPyData(refId)[1]
2089        refData = [refProfile,refLimits,refSample]
2090        G2sasd.SetScale(Data,refData)
2091        G2plt.PlotPatterns(G2frame,plotType='SASD',newPlot=True)
2092        UpdateSampleGrid(G2frame,data)       
2093       
2094    def OnSampleCopy(event):
2095        histType,copyNames = SetCopyNames(histName,data['Type'],
2096            addNames = ['Omega','Chi','Phi','Gonio. radius','InstrName'])
2097        copyDict = {}
2098        for parm in copyNames:
2099            copyDict[parm] = data[parm]
2100        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
2101        histList = GetHistsLikeSelected(G2frame)
2102        if not histList:
2103            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
2104            return
2105        dlg = G2G.G2MultiChoiceDialog(
2106            G2frame.dataFrame,
2107            'Copy sample params from\n'+str(hst[5:])+' to...',
2108            'Copy sample parameters', histList)
2109        try:
2110            if dlg.ShowModal() == wx.ID_OK:
2111                result = dlg.GetSelections()
2112                for i in result: 
2113                    item = histList[i]
2114                    Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
2115                    sampleData = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Sample Parameters'))
2116                    sampleData.update(copy.deepcopy(copyDict))
2117        finally:
2118            dlg.Destroy()
2119
2120    def OnSampleCopySelected(event):
2121        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
2122        Controls = G2frame.PatternTree.GetItemPyData(
2123            G2gd.GetPatternTreeItemId(G2frame,G2frame.root, 'Controls'))
2124        histList = GetHistsLikeSelected(G2frame)
2125        if not histList:
2126            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
2127            return
2128        # Assemble a list of item labels
2129        TextTable = {key:label for key,label,dig in
2130                     SetupSampleLabels(hst,data.get('Type'),Inst['Type'][0])
2131                     }
2132        # get flexible labels
2133        TextTable.update({
2134            key:Controls[key] for key in Controls if key.startswith('FreePrm')
2135            })
2136        # add a few extra
2137        TextTable.update({
2138            'Type':'Diffractometer type',
2139            'InstrName':'Instrument Name',
2140            })
2141        # Assemble a list of dict entries that would be labeled in the Sample
2142        # params data window (drop ranId and items not used).
2143        keyList = [i for i in data.keys() if i in TextTable]
2144        keyText = [TextTable[i] for i in keyList]
2145        # sort both lists together, ordered by keyText
2146        keyText, keyList = zip(*sorted(zip(keyText,keyList))) # sort lists
2147        selectedKeys = []
2148        dlg = G2G.G2MultiChoiceDialog(
2149            G2frame.dataFrame,
2150            'Select which sample parameters\nto copy',
2151            'Select sample parameters', keyText)
2152        try:
2153            if dlg.ShowModal() == wx.ID_OK:
2154                selectedKeys = [keyList[i] for i in dlg.GetSelections()]
2155        finally:
2156            dlg.Destroy()
2157        if not selectedKeys: return # nothing to copy
2158        copyDict = {}
2159        for parm in selectedKeys:
2160            copyDict[parm] = data[parm]
2161        dlg = G2G.G2MultiChoiceDialog(
2162            G2frame.dataFrame,
2163            'Copy sample params from\n'+str(hst[5:])+' to...',
2164            'Copy sample parameters', histList)
2165        try:
2166            if dlg.ShowModal() == wx.ID_OK:
2167                result = dlg.GetSelections()
2168                for i in result: 
2169                    item = histList[i]
2170                    Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
2171                    sampleData = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Sample Parameters'))
2172                    sampleData.update(copy.deepcopy(copyDict))
2173        finally:
2174            dlg.Destroy()           
2175        G2plt.PlotPatterns(G2frame,plotType=hst[:4],newPlot=False)
2176
2177    def OnSampleFlagCopy(event):
2178        histType,copyNames = SetCopyNames(histName,data['Type'])
2179        flagDict = {}
2180        for parm in copyNames:
2181            flagDict[parm] = data[parm][1]
2182        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
2183        histList = GetHistsLikeSelected(G2frame)
2184        if not histList:
2185            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
2186            return
2187        dlg = G2G.G2MultiChoiceDialog(
2188            G2frame.dataFrame, 
2189            'Copy sample ref. flags from\n'+str(hst[5:])+' to...',
2190            'Copy sample flags', histList)
2191        try:
2192            if dlg.ShowModal() == wx.ID_OK:
2193                result = dlg.GetSelections()
2194                for i in result: 
2195                    item = histList[i]
2196                    Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
2197                    sampleData = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Sample Parameters'))
2198                    for name in copyNames:
2199                        sampleData[name][1] = copy.copy(flagDict[name])
2200        finally:
2201            dlg.Destroy()
2202
2203    def OnHistoChange():
2204        '''Called when the histogram type is changed to refresh the window
2205        '''
2206        #wx.CallAfter(UpdateSampleGrid,G2frame,data)
2207        wx.CallLater(100,UpdateSampleGrid,G2frame,data)
2208       
2209    def SetNameVal():
2210        inst = instNameVal.GetValue()
2211        data['InstrName'] = inst.strip()
2212
2213    def OnNameVal(event):
2214        event.Skip()
2215        wx.CallAfter(SetNameVal)
2216       
2217    def AfterChange(invalid,value,tc):
2218        if invalid:
2219            return
2220        if tc.key == 0 and 'SASD' in histName:          #a kluge for Scale!
2221            G2plt.PlotPatterns(G2frame,plotType='SASD',newPlot=True)
2222        elif tc.key == 'Thick':
2223            wx.CallAfter(UpdateSampleGrid,G2frame,data)           
2224           
2225    def OnMaterial(event):
2226        Obj = event.GetEventObject()
2227        id,key = Info[Obj.GetId()]
2228        if key == 'Name':
2229            data['Materials'][id][key] = Obj.GetValue()
2230        elif key == 'VolFrac':
2231            try:
2232                value = min(max(0.,float(Obj.GetValue())),1.)
2233            except ValueError:
2234                value = data['Materials'][id][key]
2235            data['Materials'][id][key] = value
2236            data['Materials'][not id][key] = 1.-value
2237        wx.CallAfter(UpdateSampleGrid,G2frame,data)
2238
2239    def OnCopy1Val(event):
2240        'Select one value to copy to many histograms and optionally allow values to be edited in a table'
2241        G2G.SelectEdit1Var(G2frame,data,labelLst,elemKeysLst,dspLst,refFlgElem)
2242        wx.CallAfter(UpdateSampleGrid,G2frame,data)
2243       
2244    ######## DEBUG #######################################################
2245    #import GSASIIpwdGUI
2246    #reload(GSASIIpwdGUI)
2247    #reload(G2gd)
2248    ######################################################################
2249    Inst = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(
2250            G2frame,G2frame.PatternId, 'Instrument Parameters'))[0]
2251    histName = G2frame.PatternTree.GetItemText(G2frame.PatternId)
2252    if G2frame.dataDisplay:
2253        G2frame.dataFrame.Clear()
2254    G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.SampleMenu)
2255    G2frame.dataFrame.SetLabel('Sample Parameters')
2256    G2frame.Bind(wx.EVT_MENU, OnSetScale, id=G2gd.wxID_SETSCALE)
2257    G2frame.Bind(wx.EVT_MENU, OnSampleCopy, id=G2gd.wxID_SAMPLECOPY)
2258    G2frame.Bind(wx.EVT_MENU, OnSampleCopySelected, id=G2gd.wxID_SAMPLECOPYSOME)
2259    G2frame.Bind(wx.EVT_MENU, OnSampleFlagCopy, id=G2gd.wxID_SAMPLEFLAGCOPY)
2260    G2frame.Bind(wx.EVT_MENU, OnSampleSave, id=G2gd.wxID_SAMPLESAVE)
2261    G2frame.Bind(wx.EVT_MENU, OnSampleLoad, id=G2gd.wxID_SAMPLELOAD)
2262    G2frame.Bind(wx.EVT_MENU, OnCopy1Val, id=G2gd.wxID_SAMPLE1VAL)
2263    G2frame.Bind(wx.EVT_MENU, OnAllSampleLoad, id=G2gd.wxID_ALLSAMPLELOAD)
2264    if 'SASD' in histName:
2265        G2frame.dataFrame.SetScale.Enable(True)
2266    if not G2frame.dataFrame.GetStatusBar():
2267        Status = G2frame.dataFrame.CreateStatusBar()   
2268    G2frame.dataDisplay = wx.Panel(G2frame.dataFrame)
2269    Controls = G2frame.PatternTree.GetItemPyData(
2270        G2gd.GetPatternTreeItemId(G2frame,G2frame.root, 'Controls'))
2271#patch
2272    if 'ranId' not in data:
2273        data['ranId'] = ran.randint(0,sys.maxint)
2274    if not 'Gonio. radius' in data:
2275        data['Gonio. radius'] = 200.0
2276    if not 'Omega' in data:
2277        data.update({'Omega':0.0,'Chi':0.0,'Phi':0.0})
2278    if 'Azimuth' not in data:
2279        data['Azimuth'] = 0.0
2280    if type(data['Temperature']) is int:
2281        data['Temperature'] = float(data['Temperature'])
2282    if 'Time' not in data:
2283        data['Time'] = 0.0
2284    if 'FreePrm1' not in Controls:
2285        Controls['FreePrm1'] = 'Sample humidity (%)'
2286    if 'FreePrm2' not in Controls:
2287        Controls['FreePrm2'] = 'Sample voltage (V)'
2288    if 'FreePrm3' not in Controls:
2289        Controls['FreePrm3'] = 'Applied load (MN)'
2290    if 'FreePrm1' not in data:
2291        data['FreePrm1'] = 0.
2292    if 'FreePrm2' not in data:
2293        data['FreePrm2'] = 0.
2294    if 'FreePrm3' not in data:
2295        data['FreePrm3'] = 0.
2296    if 'SurfRoughA' not in data and 'PWDR' in histName:
2297        data['SurfRoughA'] = [0.,False]
2298        data['SurfRoughB'] = [0.,False]
2299    if 'Trans' not in data and 'SASD' in histName:
2300        data['Trans'] = 1.0
2301    if 'SlitLen' not in data and 'SASD' in histName:
2302        data['SlitLen'] = 0.0
2303    if 'Shift' not in data:
2304        data['Shift'] = [0.0,False]
2305    if 'Transparency' not in data:
2306        data['Transparency'] = [0.0,False]
2307    data['InstrName'] = data.get('InstrName','')
2308#patch end
2309    labelLst,elemKeysLst,dspLst,refFlgElem = [],[],[],[]
2310    parms = SetupSampleLabels(histName,data.get('Type'),Inst['Type'][0])
2311    mainSizer = wx.BoxSizer(wx.VERTICAL)
2312    topSizer = wx.BoxSizer(wx.HORIZONTAL)
2313    topSizer.Add((-1,-1),1,wx.EXPAND,1)
2314    topSizer.Add(wx.StaticText(G2frame.dataDisplay,label='Sample and Experimental Parameters'))
2315    topSizer.Add((-1,-1),1,wx.EXPAND,1)
2316    mainSizer.Add(topSizer,0,wx.EXPAND,1)
2317    nameSizer = wx.BoxSizer(wx.HORIZONTAL)
2318    nameSizer.Add(wx.StaticText(G2frame.dataDisplay,wx.ID_ANY,' Instrument Name'),
2319                0,WACV)
2320    nameSizer.Add((-1,-1),1,wx.EXPAND,1)
2321    instNameVal = wx.TextCtrl(G2frame.dataDisplay,wx.ID_ANY,data['InstrName'],
2322                              size=(200,-1),style=wx.TE_PROCESS_ENTER)       
2323    nameSizer.Add(instNameVal)
2324    instNameVal.Bind(wx.EVT_CHAR,OnNameVal)
2325    mainSizer.Add(nameSizer,0,wx.EXPAND,1)
2326    mainSizer.Add((5,5),0)
2327    labelLst.append('Instrument Name')
2328    elemKeysLst.append(['InstrName'])
2329    dspLst.append(None)
2330    refFlgElem.append(None)
2331
2332    if 'PWDR' in histName:
2333        nameSizer = wx.BoxSizer(wx.HORIZONTAL)
2334        nameSizer.Add(wx.StaticText(G2frame.dataDisplay,wx.ID_ANY,' Diffractometer type: '),
2335                    0,WACV)
2336        if 'T' in Inst['Type'][0]:
2337            choices = ['Debye-Scherrer',]
2338        else:
2339            choices = ['Debye-Scherrer','Bragg-Brentano',]
2340        histoType = G2G.G2ChoiceButton(G2frame.dataDisplay,choices,
2341                    strLoc=data,strKey='Type',
2342                    onChoice=OnHistoChange)
2343        nameSizer.Add(histoType)
2344        mainSizer.Add(nameSizer,0,wx.EXPAND,1)
2345        mainSizer.Add((5,5),0)
2346
2347    parmSizer = wx.FlexGridSizer(0,2,5,0)
2348    for key,lbl,nDig in parms:
2349        labelLst.append(lbl.strip().strip(':').strip())
2350        dspLst.append(nDig)
2351        if 'list' in str(type(data[key])):
2352            parmRef = G2G.G2CheckBox(G2frame.dataDisplay,' '+lbl,data[key],1)
2353            parmSizer.Add(parmRef,0,WACV|wx.EXPAND)
2354            parmVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,data[key],0,
2355                nDig=nDig,typeHint=float,OnLeave=AfterChange)
2356            elemKeysLst.append([key,0])
2357            refFlgElem.append([key,1])
2358        else:
2359            parmSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' '+lbl),
2360                0,WACV|wx.EXPAND)
2361            parmVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,data,key,
2362                typeHint=float,OnLeave=AfterChange)
2363            elemKeysLst.append([key])
2364            refFlgElem.append(None)
2365        parmSizer.Add(parmVal,1,wx.EXPAND)
2366    Info = {}
2367       
2368    for key in ('FreePrm1','FreePrm2','FreePrm3'):
2369        parmVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,Controls,key,typeHint=str,
2370                                        notBlank=False)
2371        parmSizer.Add(parmVal,1,wx.EXPAND)
2372        parmVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,data,key,typeHint=float)
2373        parmSizer.Add(parmVal,1,wx.EXPAND)
2374        labelLst.append(Controls[key])
2375        dspLst.append(None)
2376        elemKeysLst.append([key])
2377        refFlgElem.append(None)
2378       
2379    mainSizer.Add(parmSizer,1,wx.EXPAND)
2380    mainSizer.Add((0,5),0)   
2381    if 'SASD' in histName:
2382        rho = [0.,0.]
2383        anomrho = [0.,0.]
2384        mu = 0.
2385        subSizer = wx.FlexGridSizer(0,4,5,5)
2386        Substances = G2frame.PatternTree.GetItemPyData(
2387            G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Substances'))
2388        for id,item in enumerate(data['Materials']):
2389            subSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Material: '),0,WACV)
2390            matsel = wx.ComboBox(G2frame.dataDisplay,value=item['Name'],choices=Substances['Substances'].keys(),
2391                style=wx.CB_READONLY|wx.CB_DROPDOWN)
2392            Info[matsel.GetId()] = [id,'Name']
2393            matsel.Bind(wx.EVT_COMBOBOX,OnMaterial)       
2394            subSizer.Add(matsel,0,WACV)
2395            subSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Volume fraction: '),0,WACV)
2396            volfrac = wx.TextCtrl(G2frame.dataDisplay,value=str('%.3f'%(item['VolFrac'])),style=wx.TE_PROCESS_ENTER)
2397            Info[volfrac.GetId()] = [id,'VolFrac']
2398            volfrac.Bind(wx.EVT_TEXT_ENTER,OnMaterial)
2399            volfrac.Bind(wx.EVT_KILL_FOCUS,OnMaterial)
2400            subSizer.Add(volfrac,0,WACV)
2401            material = Substances['Substances'][item['Name']]
2402            mu += item['VolFrac']*material.get('XAbsorption',0.)
2403            rho[id] = material['Scatt density']
2404            anomrho[id] = material.get('XAnom density',0.)
2405        data['Contrast'] = [(rho[1]-rho[0])**2,(anomrho[1]-anomrho[0])**2]
2406        mainSizer.Add(subSizer,0)
2407        conSizer = wx.BoxSizer(wx.HORIZONTAL)
2408        conSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Contrast: %10.2f '%(data['Contrast'][0])),0,WACV)
2409        conSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Anom. Contrast: %10.2f '%(data['Contrast'][1])),0,WACV)
2410        mut =  mu*data['Thick']
2411        conSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Transmission (calc): %10.3f  '%(np.exp(-mut))),0,WACV)
2412        mainSizer.Add(conSizer,0)
2413   
2414    mainSizer.Layout()   
2415    G2frame.dataDisplay.SetSizer(mainSizer)
2416    Size = mainSizer.Fit(G2frame.dataFrame)
2417    G2frame.dataDisplay.SetSize(Size)
2418    G2frame.dataFrame.setSizePosLeft(Size)
2419               
2420################################################################################
2421#####  Indexing Peaks
2422################################################################################           
2423       
2424def UpdateIndexPeaksGrid(G2frame, data):
2425    '''respond to selection of PWDR Index Peak List data
2426    tree item.
2427    '''
2428    bravaisSymb = ['Fm3m','Im3m','Pm3m','R3-H','P6/mmm','I4/mmm',
2429        'P4/mmm','Fmmm','Immm','Cmmm','Pmmm','C2/m','P2/m','P1']
2430    IndexId = G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Index Peak List')
2431    Inst = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Instrument Parameters'))[0]
2432    limitId = G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Limits')
2433    Limits = G2frame.PatternTree.GetItemPyData(limitId)
2434    def RefreshIndexPeaksGrid(event):
2435        r,c =  event.GetRow(),event.GetCol()
2436        peaks = G2frame.IndexPeaksTable.GetData()
2437        if c == 2:
2438            if peaks[r][c]:
2439                peaks[r][c] = False
2440            else:
2441                peaks[r][c] = True
2442            G2frame.IndexPeaksTable.SetData(peaks)
2443            G2frame.PatternTree.SetItemPyData(IndexId,[peaks,data[1]])
2444            G2frame.dataDisplay.ForceRefresh()
2445            if 'PKS' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
2446                G2plt.PlotPowderLines(G2frame)
2447            else:
2448                G2plt.PlotPatterns(G2frame,plotType='PWDR')
2449           
2450    def OnReload(event):
2451        peaks = []
2452        sigs = []
2453        Peaks = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Peak List'))
2454        for ip,peak in enumerate(Peaks['peaks']):
2455            dsp = G2lat.Pos2dsp(Inst,peak[0])
2456            peaks.append([peak[0],peak[2],True,False,0,0,0,dsp,0.0])    #SS?
2457            try:
2458                sig = Peaks['sigDict']['pos'+str(ip)]
2459            except KeyError:
2460                sig = 0.
2461            sigs.append(sig)
2462        data = [peaks,sigs]
2463        G2frame.PatternTree.SetItemPyData(IndexId,data)
2464        UpdateIndexPeaksGrid(G2frame,data)
2465       
2466    def KeyEditPickGrid(event):
2467        colList = G2frame.dataDisplay.GetSelectedCols()
2468        rowList = G2frame.dataDisplay.GetSelectedRows()
2469        data = G2frame.PatternTree.GetItemPyData(IndexId)
2470        if event.GetKeyCode() == wx.WXK_RETURN:
2471            event.Skip(True)
2472        elif event.GetKeyCode() == wx.WXK_CONTROL:
2473            event.Skip(True)
2474        elif event.GetKeyCode() == wx.WXK_SHIFT:
2475            event.Skip(True)
2476        elif colList:
2477            G2frame.dataDisplay.ClearSelection()
2478            key = event.GetKeyCode()
2479            for col in colList:
2480                if G2frame.IndexPeaksTable.GetColLabelValue(col) in ['use',]:
2481                    if key == 89: #'Y'
2482                        for row in range(G2frame.IndexPeaksTable.GetNumberRows()): data[0][row][col]=True
2483                    elif key == 78:  #'N'
2484                        for row in range(G2frame.IndexPeaksTable.GetNumberRows()): data[0][row][col]=False
2485                    elif key == 83: # 'S'
2486                        for row in range(G2frame.IndexPeaksTable.GetNumberRows()): data[0][row][col] = not data[0][row][col]
2487                       
2488           
2489    if G2frame.dataDisplay:
2490        G2frame.dataFrame.Clear()
2491    if not G2frame.dataFrame.GetStatusBar():
2492        Status = G2frame.dataFrame.CreateStatusBar()
2493    if 'PWD' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
2494        G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.IndPeaksMenu)
2495        G2frame.Bind(wx.EVT_MENU, OnReload, id=G2gd.wxID_INDXRELOAD)
2496    G2frame.dataFrame.IndexPeaks.Enable(False)
2497    G2frame.IndexPeaksTable = []
2498    if len(data[0]):
2499        G2frame.dataFrame.IndexPeaks.Enable(True)
2500        Unit = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Unit Cells List'))
2501        if Unit:
2502            if len(Unit) == 4:  #patch
2503                Unit.append({})
2504            controls,bravais,cellist,dmin,ssopt = Unit
2505            if 'T' in Inst['Type'][0]:   #TOF - use other limit!
2506                dmin = G2lat.Pos2dsp(Inst,Limits[1][0])
2507            else:
2508                dmin = G2lat.Pos2dsp(Inst,Limits[1][1])
2509            G2frame.HKL = []
2510            if ssopt.get('Use',False):
2511                cell = controls[6:12]
2512                A = G2lat.cell2A(cell)
2513                ibrav = bravaisSymb.index(controls[5])
2514                spc = controls[13]
2515                SGData = G2spc.SpcGroup(spc)[1]
2516                SSGData = G2spc.SSpcGroup(SGData,ssopt['ssSymb'])[1]
2517                Vec = ssopt['ModVec']
2518                maxH = ssopt['maxH']
2519                G2frame.HKL = G2pwd.getHKLMpeak(dmin,Inst,SGData,SSGData,Vec,maxH,A)
2520                G2frame.HKL = np.array(G2frame.HKL)
2521                data[0] = G2indx.IndexSSPeaks(data[0],G2frame.HKL)[1]
2522            else:        #select cell from table - no SS
2523                for i,cell in enumerate(cellist):
2524                    if cell[-2]:
2525                        ibrav = cell[2]
2526                        A = G2lat.cell2A(cell[3:9])
2527                        G2frame.HKL = G2lat.GenHBravais(dmin,ibrav,A)
2528                        for hkl in G2frame.HKL:
2529                            hkl.insert(4,G2lat.Dsp2pos(Inst,hkl[3]))
2530                        G2frame.HKL = np.array(G2frame.HKL)
2531                        data[0] = G2indx.IndexPeaks(data[0],G2frame.HKL)[1]
2532                        break
2533    rowLabels = []
2534    for i in range(len(data[0])): rowLabels.append(str(i+1))
2535    colLabels = ['position','intensity','use','indexed','h','k','l','d-obs','d-calc']
2536    Types = [wg.GRID_VALUE_FLOAT+':10,4',wg.GRID_VALUE_FLOAT+':10,1',]+2*[wg.GRID_VALUE_BOOL,]+ \
2537        3*[wg.GRID_VALUE_LONG,]+2*[wg.GRID_VALUE_FLOAT+':10,5',]
2538    if len(data[0]) and len(data[0][0]) > 9:
2539        colLabels = ['position','intensity','use','indexed','h','k','l','m','d-obs','d-calc']
2540        Types = [wg.GRID_VALUE_FLOAT+':10,4',wg.GRID_VALUE_FLOAT+':10,1',]+2*[wg.GRID_VALUE_BOOL,]+ \
2541            4*[wg.GRID_VALUE_LONG,]+2*[wg.GRID_VALUE_FLOAT+':10,5',]
2542    G2frame.PatternTree.SetItemPyData(IndexId,data)
2543    G2frame.IndexPeaksTable = G2G.Table(data[0],rowLabels=rowLabels,colLabels=colLabels,types=Types)
2544    G2frame.dataFrame.SetLabel('Index Peak List')
2545    G2frame.dataDisplay = G2G.GSGrid(parent=G2frame.dataFrame)               
2546    G2frame.dataDisplay.SetTable(G2frame.IndexPeaksTable, True)
2547    XY = []
2548    Sigs = []
2549    for r in range(G2frame.dataDisplay.GetNumberRows()):
2550        for c in range(G2frame.dataDisplay.GetNumberCols()):
2551            if c == 2:
2552                G2frame.dataDisplay.SetReadOnly(r,c,isReadOnly=False)
2553            else:
2554                G2frame.dataDisplay.SetReadOnly(r,c,isReadOnly=True)
2555        if data[0][r][2] and data[0][r][3]:
2556            XY.append([data[0][r][-1],data[0][r][0]])
2557            try:
2558                sig = data[1][r]
2559            except IndexError:
2560                sig = 0.
2561            Sigs.append(sig)
2562    G2frame.dataDisplay.Bind(wg.EVT_GRID_CELL_LEFT_CLICK, RefreshIndexPeaksGrid)
2563    G2frame.dataDisplay.Bind(wx.EVT_KEY_DOWN, KeyEditPickGrid)                 
2564    G2frame.dataDisplay.SetMargins(0,0)
2565    G2frame.dataDisplay.AutoSizeColumns(False)
2566    G2frame.dataFrame.setSizePosLeft([490,300])
2567    if len(XY):
2568        XY = np.array(XY)
2569        G2plt.PlotCalib(G2frame,Inst,XY,Sigs,newPlot=True)
2570    G2frame.dataFrame.SendSizeEvent()
2571     
2572################################################################################
2573#####  Unit cells
2574################################################################################           
2575       
2576def UpdateUnitCellsGrid(G2frame, data):
2577    '''respond to selection of PWDR Unit Cells data tree item.
2578    '''
2579    UnitCellsId = G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Unit Cells List')
2580    SPGlist = G2spc.spglist
2581    bravaisSymb = ['Fm3m','Im3m','Pm3m','R3-H','P6/mmm','I4/mmm','P4/mmm',
2582        'Fmmm','Immm','Cmmm','Pmmm','C2/m','P2/m','P1']
2583    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',
2584        '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']
2585    Inst = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Instrument Parameters'))[0]
2586    Limits = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Limits'))[1]
2587    if 'C' in Inst['Type'][0] or 'PKS' in Inst['Type'][0]:
2588        wave = G2mth.getWave(Inst)
2589        dmin = G2lat.Pos2dsp(Inst,Limits[1])
2590    else:
2591        difC = Inst['difC'][1]
2592        dmin = G2lat.Pos2dsp(Inst,Limits[0])
2593   
2594    def SetLattice(controls):
2595        ibrav = bravaisSymb.index(controls[5])
2596        if controls[5] in ['Fm3m','Im3m','Pm3m']:
2597            controls[7] = controls[8] = controls[6]
2598            controls[9] = controls[10] = controls[11] = 90.
2599        elif controls[5] in ['R3m','P6/mmm','I4/mmm','P4/mmm']:
2600            controls[7] = controls[6]
2601            controls[9] = controls[10] = controls[11] = 90.
2602            if controls[5] in ['R3-H','P6/mmm']:
2603                controls[11] = 120.
2604        elif controls[5] in ['Fmmm','Immm','Cmmm','Pmmm']:
2605            controls[9] = controls[10] = controls[11] = 90.
2606        elif controls[5] in ['C2/m','P2/m']:
2607            controls[9] = controls[11] = 90.  # b unique
2608        if len(controls) < 13: controls.append(0)
2609        controls[12] = G2lat.calc_V(G2lat.cell2A(controls[6:12]))
2610        return ibrav
2611       
2612    def OnNcNo(event):
2613        controls[2] = NcNo.GetValue()
2614       
2615    def OnIfX20(event):
2616        G2frame.ifX20 = x20.GetValue()
2617       
2618    def OnStartVol(event):
2619        try:
2620            stVol = int(float(startVol.GetValue()))
2621            if stVol < 25:
2622                raise ValueError
2623        except ValueError:
2624            stVol = 25
2625        controls[3] = stVol
2626        startVol.SetValue("%d"%(stVol))
2627       
2628    def OnBravais(event):
2629        Obj = event.GetEventObject()
2630        bravais[bravList.index(Obj.GetId())] = Obj.GetValue()
2631       
2632    def OnZero(event):
2633        try:
2634            Zero = min(5.0,max(-5.0,float(zero.GetValue())))
2635        except ValueError:
2636            Zero = 0.0
2637        controls[1] = Zero
2638        zero.SetValue("%.4f"%(Zero))
2639       
2640    def OnZeroVar(event):
2641        controls[0] = zeroVar.GetValue()
2642       
2643    def OnSSopt(event):
2644        if controls[5] in ['Fm3m','Im3m','Pm3m']:
2645            SSopt.SetValue(False)
2646            G2frame.ErrorDialog('Cubic lattice', 'Superlattice not allowed for a cubic lattice')
2647            return
2648        ssopt['Use'] = SSopt.GetValue()
2649        if 'ssSymb' not in ssopt:
2650            ssopt.update({'ssSymb':'(abg)','ModVec':[0.1,0.1,0.1],'maxH':1})
2651        wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)
2652       
2653    def OnSelMG(event):
2654        ssopt['ssSymb'] = selMG.GetValue()
2655        Vec = ssopt['ModVec']
2656        modS = G2spc.splitSSsym(ssopt['ssSymb'])[0]
2657        ssopt['ModVec'] = G2spc.SSGModCheck(Vec,modS)[0]
2658        print ' Selecting: ',controls[13],ssopt['ssSymb'], 'maxH:',ssopt['maxH']
2659        OnHklShow(event)
2660        wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)
2661       
2662    def OnModVal(event):
2663        Obj = event.GetEventObject()
2664        ObjId = Obj.GetId()
2665        Id = Indx[ObjId]
2666        try:
2667            value = min(0.98,max(-0.98,float(Obj.GetValue())))
2668        except ValueError:
2669            value = ssopt['ModVec'][Id]
2670        Obj.SetValue('%.4f'%(value))
2671        ssopt['ModVec'][Id] = value
2672        OnHklShow(event)
2673       
2674    def OnMoveMod(event):
2675        Obj = event.GetEventObject()
2676        ObjId = Obj.GetId()
2677        Id,valObj = Indx[ObjId]
2678        move = Obj.GetValue()*0.01
2679        Obj.SetValue(0)
2680        value = min(0.98,max(-0.98,float(valObj.GetValue())+move))
2681        valObj.SetValue('%.4f'%(value)) 
2682        ssopt['ModVec'][Id] = value
2683        OnHklShow(event)
2684       
2685    def OnMaxMH(event):
2686        ssopt['maxH'] = int(maxMH.GetValue())
2687        print ' Selecting: ',controls[13],ssopt['ssSymb'], 'maxH:',ssopt['maxH']
2688        OnHklShow(event)
2689       
2690    def OnFindMV(event):
2691        Peaks = np.copy(peaks[0])
2692        print ' Trying: ',controls[13],ssopt['ssSymb'], 'maxH:',1
2693        dlg = wx.ProgressDialog('Elapsed time','Modulation vector search',
2694            style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE)
2695        try:
2696            ssopt['ModVec'],result = G2indx.findMV(Peaks,controls,ssopt,Inst,dlg)
2697            if len(result[0]) == 2:
2698                G2plt.PlotXYZ(G2frame,result[2],1./result[3],labelX='a',labelY='g',
2699                    newPlot=True,Title='Modulation vector search')
2700        finally:
2701            dlg.Destroy()
2702        OnHklShow(event)
2703        wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)
2704       
2705    def OnBravSel(event):
2706        brav = bravSel.GetString(bravSel.GetSelection())
2707        controls[5] = brav
2708        controls[13] = SPGlist[brav][0]       
2709        wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)
2710       
2711    def OnSpcSel(event):
2712        controls[13] = spcSel.GetString(spcSel.GetSelection())
2713        G2frame.dataFrame.RefineCell.Enable(True)
2714        OnHklShow(event)
2715       
2716    def SetCellValue(Obj,ObjId,value):
2717        ibrav = bravaisSymb.index(controls[5])
2718        if controls[5] in ['Fm3m','Im3m','Pm3m']:
2719            controls[6] = controls[7] = controls[8] = value
2720            controls[9] = controls[10] = controls[11] = 90.0
2721            Obj.SetValue("%.5f"%(controls[6]))
2722        elif controls[5] in ['R3-H','P6/mmm','I4/mmm','P4/mmm']:
2723            if ObjId == 0:
2724                controls[6] = controls[7] = value
2725                Obj.SetValue("%.5f"%(controls[6]))
2726            else:
2727                controls[8] = value
2728                Obj.SetValue("%.5f"%(controls[8]))
2729            controls[9] = controls[10] = controls[11] = 90.0
2730            if controls[5] in ['R3-H','P6/mmm']:
2731                controls[11] = 120.
2732        elif controls[5] in ['Fmmm','Immm','Cmmm','Pmmm']:
2733            controls[6+ObjId] = value
2734            Obj.SetValue("%.5f"%(controls[6+ObjId]))
2735            controls[9] = controls[10] = controls[11] = 90.0
2736        elif controls[5] in ['C2/m','P2/m']:
2737            controls[9] = controls[11] = 90.0
2738            if ObjId != 3:
2739                controls[6+ObjId] = value
2740                Obj.SetValue("%.5f"%(controls[6+ObjId]))
2741            else:
2742                controls[10] = value
2743                Obj.SetValue("%.3f"%(controls[10]))
2744        else:
2745            controls[6+ObjId] = value
2746            if ObjId < 3:
2747                Obj.SetValue("%.5f"%(controls[6+ObjId]))
2748            else:
2749                Obj.SetValue("%.3f"%(controls[6+ObjId]))
2750        controls[12] = G2lat.calc_V(G2lat.cell2A(controls[6:12]))
2751        volVal.SetValue("%.3f"%(controls[12]))
2752       
2753    def OnMoveCell(event):
2754        Obj = event.GetEventObject()
2755        ObjId = cellList.index(Obj.GetId())
2756        valObj = valDict[Obj.GetId()]
2757        if ObjId/2 < 3:
2758            move = Obj.GetValue()*0.01
2759        else:
2760            move = Obj.GetValue()*0.1
2761        Obj.SetValue(0)
2762        value = float(valObj.GetValue())+move 
2763        SetCellValue(valObj,ObjId/2,value)
2764        OnHklShow(event)
2765       
2766    def OnExportCells(event):
2767        pth = G2G.GetExportPath(G2frame)
2768        dlg = wx.FileDialog(G2frame, 'Choose Indexing Result csv file', pth, '', 
2769            'indexing result file (*.csv)|*.csv',wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT)
2770        try:
2771            if dlg.ShowModal() == wx.ID_OK:
2772                filename = dlg.GetPath()
2773                filename = os.path.splitext(filename)[0]+'.csv'
2774                File = open(filename,'w')
2775                names = 'M20,X20,Bravais,a,b,c,alpha,beta,gamma,volume\n'
2776                File.write(names)
2777                fmt = '%.2f,%d,%s,%.4f,%.4f,%.4f,%.2f,%.2f,%.2f,%.3f\n'
2778                for cell in cells:
2779                    File.write(fmt%(cell[0],cell[1],bravaisSymb[cell[2]], cell[3],cell[4],cell[5], cell[6],cell[7],cell[8],cell[9]))
2780                File.close()
2781        finally:
2782            dlg.Destroy()
2783       
2784    def OnCellChange(event):
2785        Obj = event.GetEventObject()
2786        ObjId = cellList.index(Obj.GetId())
2787        try:
2788            value = max(1.0,float(Obj.GetValue()))
2789        except ValueError:
2790            if ObjId/2 < 3:               #bad cell edge - reset
2791                value = controls[6+ObjId/2]
2792            else:                       #bad angle
2793                value = 90.
2794        SetCellValue(Obj,ObjId/2,value)
2795        wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)
2796       
2797    def OnHklShow(event):
2798        PatternId = G2frame.PatternId
2799        PickId = G2frame.PickId   
2800        peaks = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Index Peak List'))
2801        limits = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Limits'))[1]
2802        controls,bravais,cells,dminx,ssopt = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Unit Cells List'))
2803        cell = controls[6:12]
2804        A = G2lat.cell2A(cell)
2805#        ibrav = bravaisSymb.index(controls[5])
2806        spc = controls[13]
2807        SGData = G2spc.SpcGroup(spc)[1]
2808        if ssopt.get('Use',False):
2809            SSGData = G2spc.SSpcGroup(SGData,ssopt['ssSymb'])[1]
2810            Vec = ssopt['ModVec']
2811            maxH = ssopt['maxH']
2812            G2frame.HKL = G2pwd.getHKLMpeak(dmin,Inst,SGData,SSGData,Vec,maxH,A)
2813            peaks = [G2indx.IndexSSPeaks(peaks[0],G2frame.HKL)[1],peaks[1]]   #keep esds from peak fit
2814            M20,X20 = G2indx.calc_M20SS(peaks[0],G2frame.HKL)
2815        else:
2816            if len(peaks[0]):
2817#                dmin = peaks[0][-1][7]
2818                G2frame.HKL = G2pwd.getHKLpeak(dmin,SGData,A,Inst)
2819                peaks = [G2indx.IndexPeaks(peaks[0],G2frame.HKL)[1],peaks[1]]   #keep esds from peak fit
2820                M20,X20 = G2indx.calc_M20(peaks[0],G2frame.HKL)
2821            else:
2822                M20 = X20 = 0.
2823                G2frame.HKL = G2pwd.getHKLpeak(dmin,SGData,A,Inst)
2824        G2frame.HKL = np.array(G2frame.HKL)
2825        if len(G2frame.HKL):
2826            print ' new M20,X20: %.2f %d fraction found: %.3f'%(M20,X20,float(len(peaks[0]))/len(G2frame.HKL))
2827        G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Index Peak List'),peaks)
2828        if 'PKS' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
2829            G2plt.PlotPowderLines(G2frame)
2830        else:
2831            G2plt.PlotPatterns(G2frame)
2832           
2833    def OnSortCells(event):
2834        controls,bravais,cells,dminx,ssopt = G2frame.PatternTree.GetItemPyData(UnitCellsId)
2835        c =  event.GetCol()
2836        if colLabels[c] == 'M20':
2837            cells = G2indx.sortM20(cells)
2838        elif colLabels[c] in ['X20','Bravais','a','b','c','alpha','beta','gamma','Volume']:
2839            if c == 1:
2840                c += 1  #X20 before Use
2841            cells = G2indx.sortCells(cells,c-1)     #an extra column (Use) not in cells
2842        else:
2843            return
2844        data = [controls,bravais,cells,dmin,ssopt]
2845        G2frame.PatternTree.SetItemPyData(UnitCellsId,data)
2846        wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)
2847       
2848    def CopyUnitCell(event):
2849        controls,bravais,cells,dminx,ssopt = G2frame.PatternTree.GetItemPyData(UnitCellsId)
2850        for Cell in cells:
2851            if Cell[-2]:
2852                break
2853        cell = Cell[2:9]
2854        controls[4] = 1
2855        controls[5] = bravaisSymb[cell[0]]
2856        controls[6:12] = cell[1:8]
2857        controls[12] = G2lat.calc_V(G2lat.cell2A(controls[6:12]))
2858        controls[13] = spaceGroups[bravaisSymb.index(controls[5])]
2859        G2frame.PatternTree.SetItemPyData(UnitCellsId,[controls,bravais,cells,dmin,ssopt])
2860        G2frame.dataFrame.RefineCell.Enable(True)
2861        wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)       
2862               
2863    def RefineCell(event):
2864       
2865        def cellPrint(ibrav,A):
2866            cell = G2lat.A2cell(A)
2867            Vol = G2lat.calc_V(A)
2868            if ibrav in ['Fm3m','Im3m','Pm3m']:
2869                print " %s%10.6f" % ('a =',cell[0])
2870            elif ibrav in ['R3-H','P6/mmm','I4/mmm','P4/mmm']:
2871                print " %s%10.6f %s%10.6f %s%12.3f" % ('a =',cell[0],' c =',cell[2],' volume =',Vol)
2872            elif ibrav in ['P4/mmm','Fmmm','Immm','Cmmm','Pmmm']:
2873                print " %s%10.6f %s%10.6f %s%10.6f %s%12.3f" % ('a =',cell[0],'b =',cell[1],'c =',cell[2],' volume =',Vol)
2874            elif ibrav in ['C2/m','P2/m']:
2875                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)
2876            else:
2877                print " %s%10.6f %s%10.6f %s%10.6f" % ('a =',cell[0],'b =',cell[1],'c =',cell[2])
2878                print " %s%8.3f %s%8.3f %s%8.3f %s%12.3f" % ('alpha =',cell[3],'beta =',cell[4],'gamma =',cell[5],' volume =',Vol)
2879               
2880        def vecPrint(Vec):
2881            print ' %s %10.5f %10.5f %10.5f'%('Modulation vector:',Vec[0],Vec[1],Vec[2])
2882             
2883        PatternId = G2frame.PatternId
2884        PickId = G2frame.PickId   
2885        peaks = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Index Peak List'))
2886        if not len(peaks[0]):
2887            G2frame.ErrorDialog('No peaks!', 'Nothing to refine!')
2888            return       
2889        print ' Refine cell'
2890        controls,bravais,cells,dminx,ssopt = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Unit Cells List'))
2891        cell = controls[6:12]
2892        A = G2lat.cell2A(cell)
2893        ibrav = bravaisSymb.index(controls[5])
2894        SGData = G2spc.SpcGroup(controls[13])[1]
2895        if 'C' in Inst['Type'][0] or 'PKS' in Inst['Type'][0]:
2896            if ssopt.get('Use',False):
2897                vecFlags = [True if x in ssopt['ssSymb'] else False for x in ['a','b','g']]
2898                SSGData = G2spc.SSpcGroup(SGData,ssopt['ssSymb'])[1]
2899                G2frame.HKL = G2pwd.getHKLMpeak(dmin,Inst,SGData,SSGData,ssopt['ModVec'],ssopt['maxH'],A)
2900                peaks = [G2indx.IndexSSPeaks(peaks[0],G2frame.HKL)[1],peaks[1]]   #put peak fit esds back in peaks
2901                Lhkl,M20,X20,Aref,Vec,Zero = \
2902                    G2indx.refinePeaksZSS(peaks[0],wave,Inst,SGData,SSGData,ssopt['maxH'],ibrav,A,ssopt['ModVec'],vecFlags,controls[1],controls[0])
2903            else:
2904                G2frame.HKL = G2pwd.getHKLpeak(dmin,SGData,A,Inst)
2905                peaks = [G2indx.IndexPeaks(peaks[0],G2frame.HKL)[1],peaks[1]]   #put peak fit esds back in peaks
2906                Lhkl,M20,X20,Aref,Zero = G2indx.refinePeaksZ(peaks[0],wave,ibrav,A,controls[1],controls[0])
2907        else:   
2908            if ssopt.get('Use',False):
2909                vecFlags = [True if x in ssopt['ssSymb'] else False for x in ['a','b','g']]
2910                SSGData = G2spc.SSpcGroup(SGData,ssopt['ssSymb'])[1]
2911                G2frame.HKL = G2pwd.getHKLMpeak(dmin,Inst,SGData,SSGData,ssopt['ModVec'],ssopt['maxH'],A)
2912                peaks = [G2indx.IndexSSPeaks(peaks[0],G2frame.HKL)[1],peaks[1]]   #put peak fit esds back in peaks
2913                Lhkl,M20,X20,Aref,Vec,Zero = \
2914                    G2indx.refinePeaksTSS(peaks[0],difC,Inst,SGData,SSGData,ssopt['maxH'],ibrav,A,ssopt['ModVec'],vecFlags,controls[1],controls[0])
2915            else:
2916                G2frame.HKL = G2pwd.getHKLpeak(dmin,SGData,A,Inst)
2917                peaks = [G2indx.IndexPeaks(peaks[0],G2frame.HKL)[1],peaks[1]]   #put peak fit esds back in peaks
2918                Lhkl,M20,X20,Aref,Zero = G2indx.refinePeaksT(peaks[0],difC,ibrav,A,controls[1],controls[0])           
2919        G2frame.HKL = np.array(G2frame.HKL)
2920        controls[1] = Zero
2921        controls[6:12] = G2lat.A2cell(Aref)
2922        controls[12] = G2lat.calc_V(Aref)
2923        cells = G2frame.PatternTree.GetItemPyData(UnitCellsId)[2]
2924        for cell in cells:
2925            cell[-2] = False
2926        cells.insert(0,[M20,X20,ibrav]+controls[6:13]+[True,False])
2927        if ssopt.get('Use',False):
2928            ssopt['ModVec'] = Vec
2929            G2frame.HKL = G2pwd.getHKLMpeak(dmin,Inst,SGData,SSGData,ssopt['ModVec'],ssopt['maxH'],A)
2930        else:
2931            G2frame.HKL = G2pwd.getHKLpeak(dmin,SGData,A,Inst)
2932        data = [controls,bravais,cells,dmin,ssopt]
2933        G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Unit Cells List'),data)
2934        print " %s%10.3f" % ('refinement M20 = ',M20)
2935        print ' unindexed lines = ',X20
2936        cellPrint(controls[5],Aref)
2937        ip = 4
2938        if ssopt.get('Use',False):
2939            vecPrint(Vec)
2940            ip = 5
2941        for hkl in G2frame.HKL:
2942            hkl[ip] = G2lat.Dsp2pos(Inst,hkl[ip-1])+controls[1]
2943        G2frame.HKL = np.array(G2frame.HKL)
2944        if 'PKS' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
2945            G2plt.PlotPowderLines(G2frame)
2946        else:
2947            G2plt.PlotPatterns(G2frame)
2948        wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)
2949       
2950    def OnIndexPeaks(event):
2951        PatternId = G2frame.PatternId   
2952        print 'Peak Indexing'
2953        keepcells = []
2954        try:
2955            controls,bravais,cells,dminx,ssopt = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Unit Cells List'))
2956            for cell in cells:
2957                if cell[11]:
2958                    cell[10] = False    #clear selection flag on keepers
2959                    keepcells.append(cell)
2960        except IndexError:
2961            pass
2962        except ValueError:
2963            G2frame.ErrorDialog('Error','Need to set controls in Unit Cell List first')
2964            return
2965        if ssopt.get('Use',False):
2966            G2frame.ErrorDialog('Super lattice error','Indexing not available for super lattices')
2967            return
2968        if True not in bravais:
2969            G2frame.ErrorDialog('Error','No Bravais lattices selected')
2970            return
2971        if not len(peaks[0]):
2972            G2frame.ErrorDialog('Error','Index Peak List is empty')
2973            return
2974        if len(peaks[0][0]) > 9:
2975            G2frame.ErrorDialog('Error','You need to reload Index Peaks List first')
2976            return
2977        G2frame.dataFrame.CopyCell.Enable(False)
2978        G2frame.dataFrame.RefineCell.Enable(False)
2979        dlg = wx.ProgressDialog("Generated reflections",'0 '+" cell search for "+bravaisNames[ibrav],101, 
2980#            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
2981            style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE|wx.PD_REMAINING_TIME|wx.PD_CAN_ABORT)
2982        OK,dmin,newcells = G2indx.DoIndexPeaks(peaks[0],controls,bravais,dlg,G2frame.ifX20)
2983        dlg.Destroy()
2984        cells = keepcells+newcells
2985        cells = G2indx.sortM20(cells)
2986        if OK:
2987            cells[0][10] = True         #select best M20
2988            data = [controls,bravais,cells,dmin,ssopt]
2989            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Unit Cells List'),data)
2990            bestCell = cells[0]
2991            if bestCell[0] > 10.:
2992                G2frame.HKL = G2lat.GenHBravais(dmin,bestCell[2],G2lat.cell2A(bestCell[3:9]))
2993                for hkl in G2frame.HKL:
2994                    hkl.insert(4,G2lat.Dsp2pos(Inst,hkl[3])+controls[1])
2995                G2frame.HKL = np.array(G2frame.HKL)
2996                if 'PKS' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
2997                    G2plt.PlotPowderLines(G2frame)
2998                else:
2999                    G2plt.PlotPatterns(G2frame)
3000            G2frame.dataFrame.CopyCell.Enable(True)
3001            G2frame.dataFrame.IndexPeaks.Enable(True)
3002            G2frame.dataFrame.MakeNewPhase.Enable(True)
3003            G2frame.ifX20 = True
3004            wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)
3005               
3006    def RefreshUnitCellsGrid(event):
3007        data = G2frame.PatternTree.GetItemPyData(UnitCellsId)
3008        cells,dminx = data[2:4]
3009        r,c =  event.GetRow(),event.GetCol()
3010        if cells:
3011            if c == 2:
3012                for i in range(len(cells)):
3013                    cells[i][-2] = False
3014                    UnitCellsTable.SetValue(i,c,False)
3015                UnitCellsTable.SetValue(r,c,True)
3016                gridDisplay.ForceRefresh()
3017                cells[r][-2] = True
3018                ibrav = cells[r][2]
3019                A = G2lat.cell2A(cells[r][3:9])
3020                G2frame.HKL = G2lat.GenHBravais(dmin,ibrav,A)
3021                for hkl in G2frame.HKL:
3022                    hkl.insert(4,G2lat.Dsp2pos(Inst,hkl[3])+controls[1])
3023                G2frame.HKL = np.array(G2frame.HKL)
3024                if 'PKS' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
3025                    G2plt.PlotPowderLines(G2frame)
3026                else:
3027                    G2plt.PlotPatterns(G2frame)
3028            elif c == 11:
3029                if UnitCellsTable.GetValue(r,c):
3030                    UnitCellsTable.SetValue(r,c,False)
3031                    cells[r][c] = False
3032                else:
3033                    cells[r][c] = True
3034                    UnitCellsTable.SetValue(r,c,True)
3035                gridDisplay.ForceRefresh()
3036            G2frame.PatternTree.SetItemPyData(UnitCellsId,data)
3037       
3038    def MakeNewPhase(event):
3039        if not G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Phases'):
3040            sub = G2frame.PatternTree.AppendItem(parent=G2frame.root,text='Phases')
3041        else:
3042            sub = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Phases')
3043        PhaseName = ''
3044        dlg = wx.TextEntryDialog(None,'Enter a name for this phase','Phase Name Entry','New phase',
3045            style=wx.OK)
3046        try:
3047            if dlg.ShowModal() == wx.ID_OK:
3048                PhaseName = dlg.GetValue()
3049                cells = G2frame.PatternTree.GetItemPyData(UnitCellsId)[2]
3050                for Cell in cells:
3051                    if Cell[-2]:
3052                        break
3053                cell = Cell[2:10]       
3054                sub = G2frame.PatternTree.AppendItem(parent=sub,text=PhaseName)
3055                E,SGData = G2spc.SpcGroup(controls[13])
3056                G2frame.PatternTree.SetItemPyData(sub, \
3057                    G2IO.SetNewPhase(Name=PhaseName,SGData=SGData,cell=cell[1:],Super=ssopt))
3058                Status.SetStatusText('Change space group from '+str(controls[13])+' if needed')
3059        finally:
3060            dlg.Destroy()
3061           
3062    if G2frame.dataDisplay:
3063        G2frame.dataFrame.DestroyChildren()
3064    G2frame.dataDisplay = wxscroll.ScrolledPanel(G2frame.dataFrame)
3065    G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.IndexMenu)
3066    if not G2frame.dataFrame.GetStatusBar():
3067        Status = G2frame.dataFrame.CreateStatusBar()
3068    G2frame.Bind(wx.EVT_MENU, OnIndexPeaks, id=G2gd.wxID_INDEXPEAKS)
3069    G2frame.Bind(wx.EVT_MENU, CopyUnitCell, id=G2gd.wxID_COPYCELL)
3070    G2frame.Bind(wx.EVT_MENU, RefineCell, id=G2gd.wxID_REFINECELL)
3071    G2frame.Bind(wx.EVT_MENU, MakeNewPhase, id=G2gd.wxID_MAKENEWPHASE)
3072    G2frame.Bind(wx.EVT_MENU, OnExportCells, id=G2gd.wxID_EXPORTCELLS)
3073       
3074    controls,bravais,cells,dminx,ssopt = data
3075    if len(controls) < 13:              #add cell volume if missing
3076        controls.append(G2lat.calc_V(G2lat.cell2A(controls[6:12])))
3077    if len(controls) < 14:              #add space group used in indexing
3078        controls.append(spaceGroups[bravaisSymb.index(controls[5])])
3079    G2frame.PatternTree.SetItemPyData(UnitCellsId,data)            #update with volume
3080    bravaisNames = ['Cubic-F','Cubic-I','Cubic-P','Trigonal-R','Trigonal/Hexagonal-P',
3081        'Tetragonal-I','Tetragonal-P','Orthorhombic-F','Orthorhombic-I','Orthorhombic-C',
3082        'Orthorhombic-P','Monoclinic-C','Monoclinic-P','Triclinic']
3083    cellGUIlist = [[[0,1,2],4,zip([" Unit cell: a = "," Vol = "],["%.5f","%.3f"],[True,False],[0,0])],
3084    [[3,4,5,6],6,zip([" Unit cell: a = "," c = "," Vol = "],["%.5f","%.5f","%.3f"],[True,True,False],[0,2,0])],
3085    [[7,8,9,10],8,zip([" Unit cell: a = "," b = "," c = "," Vol = "],["%.5f","%.5f","%.5f","%.3f"],
3086        [True,True,True,False],[0,1,2,0])],
3087    [[11,12],10,zip([" Unit cell: a = "," b = "," c = "," beta = "," Vol = "],
3088        ["%.5f","%.5f","%.5f","%.3f","%.3f"],[True,True,True,True,False],[0,1,2,4,0])],
3089    [[13,],8,zip([" Unit cell: a = "," b = "," c = "," Vol = "," alpha = "," beta = "," gamma = "],
3090        ["%.5f","%.5f","%.5f","%.3f","%.3f","%.3f","%.3f"],
3091        [True,True,True,False,True,True,True],[0,1,2,0,3,4,5])]]
3092   
3093    G2frame.dataFrame.SetLabel('Unit Cells List')
3094    G2frame.dataFrame.IndexPeaks.Enable(False)
3095    peaks = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Index Peak List'))
3096    if peaks:
3097        G2frame.dataFrame.IndexPeaks.Enable(True)
3098    G2frame.dataFrame.RefineCell.Enable(False)
3099    if controls[12] > 1.0:                               #if a "real" volume (i.e. not default)
3100        G2frame.dataFrame.RefineCell.Enable(True)   
3101    G2frame.dataFrame.CopyCell.Enable(False)
3102    G2frame.dataFrame.MakeNewPhase.Enable(False)       
3103    G2frame.dataFrame.ExportCells.Enable(False)
3104    if cells:
3105        G2frame.dataFrame.CopyCell.Enable(True)
3106        G2frame.dataFrame.MakeNewPhase.Enable(True)
3107        G2frame.dataFrame.ExportCells.Enable(True)
3108    mainSizer = wx.BoxSizer(wx.VERTICAL)
3109    mainSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Indexing controls: '),0,WACV)
3110    mainSizer.Add((5,5),0)
3111    littleSizer = wx.FlexGridSizer(0,5,5,5)
3112    littleSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Max Nc/Nobs '),0,WACV)
3113    NcNo = wx.SpinCtrl(G2frame.dataDisplay)
3114    NcNo.SetRange(2,8)
3115    NcNo.SetValue(controls[2])
3116    NcNo.Bind(wx.EVT_SPINCTRL,OnNcNo)
3117    littleSizer.Add(NcNo,0,WACV)
3118    littleSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Start Volume '),0,WACV)
3119    startVol = wx.TextCtrl(G2frame.dataDisplay,value=str('%d'%(controls[3])),style=wx.TE_PROCESS_ENTER)
3120    startVol.Bind(wx.EVT_TEXT_ENTER,OnStartVol)
3121    startVol.Bind(wx.EVT_KILL_FOCUS,OnStartVol)
3122    littleSizer.Add(startVol,0,WACV)
3123    x20 = wx.CheckBox(G2frame.dataDisplay,label='Use M20/(X20+1)?')
3124    x20.SetValue(G2frame.ifX20)
3125    x20.Bind(wx.EVT_CHECKBOX,OnIfX20)
3126    littleSizer.Add(x20,0,WACV)
3127    mainSizer.Add(littleSizer,0)
3128    mainSizer.Add((5,5),0)
3129    mainSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Select Bravais Lattices for indexing: '),
3130        0,WACV)
3131    mainSizer.Add((5,5),0)
3132    littleSizer = wx.FlexGridSizer(0,7,5,5)
3133    bravList = []
3134    bravs = zip(bravais,bravaisNames)
3135    for brav,bravName in bravs:
3136        bravCk = wx.CheckBox(G2frame.dataDisplay,label=bravName)
3137        bravList.append(bravCk.GetId())
3138        bravCk.SetValue(brav)
3139        bravCk.Bind(wx.EVT_CHECKBOX,OnBravais)
3140        littleSizer.Add(bravCk,0,WACV)
3141    mainSizer.Add(littleSizer,0)
3142    mainSizer.Add((5,5),0)
3143   
3144    mainSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Cell Test & Refinement: '),0,WACV)
3145    mainSizer.Add((5,5),0)
3146    littleSizer = wx.BoxSizer(wx.HORIZONTAL)
3147    littleSizer.Add(wx.StaticText(G2frame.dataDisplay,label=" Bravais lattice "),0,WACV)
3148    bravSel = wx.Choice(G2frame.dataDisplay,choices=bravaisSymb)
3149    bravSel.SetSelection(bravaisSymb.index(controls[5]))
3150    bravSel.Bind(wx.EVT_CHOICE,OnBravSel)
3151    littleSizer.Add(bravSel,0,WACV)
3152    littleSizer.Add(wx.StaticText(G2frame.dataDisplay,label=" Space group "),0,WACV)
3153    spcSel = wx.Choice(G2frame.dataDisplay,choices=SPGlist[controls[5]])
3154    spcSel.SetSelection(SPGlist[controls[5]].index(controls[13]))
3155    spcSel.Bind(wx.EVT_CHOICE,OnSpcSel)
3156    littleSizer.Add(spcSel,0,WACV)
3157    if ssopt.get('Use',False):        #zero for super lattice doesn't work!
3158        controls[0] = False
3159    else:
3160        littleSizer.Add(wx.StaticText(G2frame.dataDisplay,label=" Zero offset"),0,WACV)
3161        zero = wx.TextCtrl(G2frame.dataDisplay,value="%.4f"%(controls[1]),style=wx.TE_PROCESS_ENTER)
3162        zero.Bind(wx.EVT_TEXT_ENTER,OnZero)
3163        zero.Bind(wx.EVT_KILL_FOCUS,OnZero)
3164        littleSizer.Add(zero,0,WACV)
3165        zeroVar = wx.CheckBox(G2frame.dataDisplay,label="Refine?")
3166        zeroVar.SetValue(controls[0])
3167        zeroVar.Bind(wx.EVT_CHECKBOX,OnZeroVar)
3168        littleSizer.Add(zeroVar,0,WACV)
3169    SSopt = wx.CheckBox(G2frame.dataDisplay,label="Super lattice?")
3170    SSopt.SetValue(ssopt.get('Use',False))
3171    SSopt.Bind(wx.EVT_CHECKBOX,OnSSopt)
3172    littleSizer.Add(SSopt,0,WACV)
3173    hklShow = wx.Button(G2frame.dataDisplay,label="Show hkl positions")
3174    hklShow.Bind(wx.EVT_BUTTON,OnHklShow)
3175    littleSizer.Add(hklShow,0,WACV)
3176    mainSizer.Add(littleSizer,0)
3177   
3178    mainSizer.Add((5,5),0)
3179    ibrav = SetLattice(controls)
3180    for cellGUI in cellGUIlist:
3181        if ibrav in cellGUI[0]:
3182            useGUI = cellGUI
3183    cellList = []
3184    valDict = {}
3185    littleSizer = wx.FlexGridSizer(0,useGUI[1],5,5)
3186    for txt,fmt,ifEdit,Id in useGUI[2]:
3187        littleSizer.Add(wx.StaticText(G2frame.dataDisplay,label=txt),0,WACV)
3188        if ifEdit:          #a,b,c,etc.
3189            cellVal = wx.TextCtrl(G2frame.dataDisplay,value=(fmt%(controls[6+Id])),style=wx.TE_PROCESS_ENTER)
3190            cellVal.Bind(wx.EVT_TEXT_ENTER,OnCellChange)       
3191            cellVal.Bind(wx.EVT_KILL_FOCUS,OnCellChange)
3192            valSizer = wx.BoxSizer(wx.HORIZONTAL)
3193            valSizer.Add(cellVal,0,WACV)
3194            cellSpin = wx.SpinButton(G2frame.dataDisplay,style=wx.SP_VERTICAL,size=wx.Size(20,20))
3195            cellSpin.SetValue(0)
3196            cellSpin.SetRange(-1,1)
3197            cellSpin.Bind(wx.EVT_SPIN, OnMoveCell)
3198            valSizer.Add(cellSpin,0,WACV)
3199            littleSizer.Add(valSizer,0,WACV)
3200            cellList.append(cellVal.GetId())
3201            cellList.append(cellSpin.GetId())
3202            valDict[cellSpin.GetId()] = cellVal
3203        else:               #volume
3204            volVal = wx.TextCtrl(G2frame.dataDisplay,value=(fmt%(controls[12])),style=wx.TE_READONLY)
3205            volVal.SetBackgroundColour(VERY_LIGHT_GREY)
3206            littleSizer.Add(volVal,0,WACV)
3207    mainSizer.Add(littleSizer,0)
3208    if ssopt.get('Use',False):        #super lattice display
3209        indChoice = ['1','2','3','4',]
3210        SpSg = controls[13]
3211        ssChoice = G2spc.ssdict[SpSg]
3212        if ssopt['ssSymb'] not in ssChoice:
3213            ssopt['ssSymb'] = ssChoice[0]
3214        ssSizer = wx.BoxSizer(wx.HORIZONTAL)
3215        ssSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Supersymmetry space group: '+SpSg+' '),0,WACV)
3216        selMG = wx.ComboBox(G2frame.dataDisplay,value=ssopt['ssSymb'],
3217                choices=ssChoice,style=wx.CB_READONLY|wx.CB_DROPDOWN)
3218        selMG.Bind(wx.EVT_COMBOBOX, OnSelMG)
3219        ssSizer.Add(selMG,0,WACV)
3220        ssSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Mod. vector: '),0,WACV)
3221        modS = G2spc.splitSSsym(ssopt['ssSymb'])[0]
3222        ssopt['ModVec'],ifShow = G2spc.SSGModCheck(ssopt['ModVec'],modS)
3223        Indx = {}
3224        for i,[val,show] in enumerate(zip(ssopt['ModVec'],ifShow)):
3225            if show:
3226                valSizer = wx.BoxSizer(wx.HORIZONTAL)
3227                modVal = wx.TextCtrl(G2frame.dataDisplay,value=('%.4f'%(val)),
3228                    size=wx.Size(50,20),style=wx.TE_PROCESS_ENTER)
3229                modVal.Bind(wx.EVT_TEXT_ENTER,OnModVal)       
3230                modVal.Bind(wx.EVT_KILL_FOCUS,OnModVal)
3231                valSizer.Add(modVal,0,WACV)
3232                modSpin = wx.SpinButton(G2frame.dataDisplay,style=wx.SP_VERTICAL,size=wx.Size(20,20))
3233                modSpin.SetValue(0)
3234                modSpin.SetRange(-1,1)
3235                modSpin.Bind(wx.EVT_SPIN, OnMoveMod)
3236                valSizer.Add(modSpin,0,WACV)
3237                ssSizer.Add(valSizer,0,WACV)
3238                Indx[modVal.GetId()] = i
3239                Indx[modSpin.GetId()] = [i,modVal]
3240            else:
3241                modVal = wx.TextCtrl(G2frame.dataDisplay,value=('%.3f'%(val)),
3242                    size=wx.Size(50,20),style=wx.TE_READONLY)
3243                modVal.SetBackgroundColour(VERY_LIGHT_GREY)
3244                ssSizer.Add(modVal,0,WACV)
3245        ssSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Max. M: '),0,WACV)
3246        maxMH = wx.ComboBox(G2frame.dataDisplay,value=str(ssopt['maxH']),
3247            choices=indChoice,style=wx.CB_READONLY|wx.CB_DROPDOWN)
3248        maxMH.Bind(wx.EVT_COMBOBOX, OnMaxMH)
3249        ssSizer.Add(maxMH,0,WACV)
3250        findMV = wx.Button(G2frame.dataDisplay,label="Find mod. vec.?")
3251        findMV.Bind(wx.EVT_BUTTON,OnFindMV)
3252        ssSizer.Add(findMV,0,WACV)
3253        mainSizer.Add(ssSizer,0)
3254
3255    if cells:
3256        mainSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label='\n Indexing Result:'),0,WACV)
3257        rowLabels = []
3258        colLabels = ['M20','X20','use','Bravais','a','b','c','alpha','beta','gamma','Volume','Keep']
3259        Types = [wg.GRID_VALUE_FLOAT+':10,2',wg.GRID_VALUE_NUMBER,wg.GRID_VALUE_BOOL,wg.GRID_VALUE_STRING,]+ \
3260            3*[wg.GRID_VALUE_FLOAT+':10,5',]+3*[wg.GRID_VALUE_FLOAT+':10,3',]+ \
3261            [wg.GRID_VALUE_FLOAT+':10,2',wg.GRID_VALUE_BOOL]
3262        numRows = len(cells)
3263        table = []
3264        for cell in cells:
3265            rowLabels.append('')
3266            row = cell[0:2]+[cell[-2]]+[bravaisSymb[cell[2]]]+cell[3:10]+[cell[11],]
3267            if cell[-2]:
3268                A = G2lat.cell2A(cell[3:9])
3269                G2frame.HKL = G2lat.GenHBravais(dmin,cell[2],A)
3270                for hkl in G2frame.HKL:
3271                    hkl.insert(4,G2lat.Dsp2pos(Inst,hkl[3])+controls[1])
3272                G2frame.HKL = np.array(G2frame.HKL)
3273            table.append(row)
3274        UnitCellsTable = G2G.Table(table,rowLabels=rowLabels,colLabels=colLabels,types=Types)
3275        gridDisplay = G2G.GSGrid(G2frame.dataDisplay)
3276        gridDisplay.SetTable(UnitCellsTable, True)
3277        G2frame.dataFrame.CopyCell.Enable(True)
3278        gridDisplay.Bind(wg.EVT_GRID_CELL_LEFT_CLICK,RefreshUnitCellsGrid)
3279        gridDisplay.Bind(wg.EVT_GRID_LABEL_LEFT_DCLICK,OnSortCells)
3280        gridDisplay.SetMargins(0,0)
3281        gridDisplay.SetRowLabelSize(0)
3282        gridDisplay.AutoSizeColumns(False)
3283        for r in range(gridDisplay.GetNumberRows()):
3284            for c in range(gridDisplay.GetNumberCols()):
3285                if c == 2:
3286                    gridDisplay.SetReadOnly(r,c,isReadOnly=False)
3287                else:
3288                    gridDisplay.SetReadOnly(r,c,isReadOnly=True)
3289        mainSizer.Add(gridDisplay,0,WACV)
3290    mainSizer.Layout()   
3291    G2frame.dataDisplay.SetSizer(mainSizer)
3292    G2frame.dataDisplay.SetAutoLayout(1)
3293    G2frame.dataDisplay.SetupScrolling()
3294    Size = mainSizer.Fit(G2frame.dataFrame)
3295    Size[0] += 25
3296    G2frame.dataDisplay.SetSize(Size)
3297    G2frame.dataFrame.setSizePosLeft(Size)   
3298   
3299################################################################################
3300#####  Reflection list
3301################################################################################           
3302       
3303def UpdateReflectionGrid(G2frame,data,HKLF=False,Name=''):
3304    '''respond to selection of PWDR Reflections data tree item by displaying
3305    a table of reflections in the data window.
3306    '''
3307    Controls = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.root, 'Controls'))
3308    dMin = 0.05
3309    if 'UsrReject' in Controls:
3310        dMin = Controls['UsrReject'].get('MinD',0.05)
3311    def OnPlotHKL(event):
3312        '''Plots a layer of reflections
3313        '''
3314        phaseName = G2frame.RefList
3315        if phaseName not in ['Unknown',]:
3316            pId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Phases')
3317            phaseId =  G2gd.GetPatternTreeItemId(G2frame,pId,phaseName)
3318            General = G2frame.PatternTree.GetItemPyData(phaseId)['General']
3319            Super = General.get('Super',0)
3320            SuperVec = General.get('SuperVec',[])
3321        else:
3322            Super = 0
3323            SuperVec = []       
3324        if 'list' in str(type(data)):   #single crystal data is 2 dict in list
3325            refList = data[1]['RefList']
3326        else:                           #powder data is a dict of dicts; each same structure as SC 2nd dict
3327            if 'RefList' in data[phaseName]:
3328                refList = np.array(data[phaseName]['RefList'])
3329            else:
3330                wx.MessageBox('No reflection list - do Refine first',caption='Reflection plotting')
3331                return
3332        FoMax = np.max(refList.T[8+Super])
3333        Hmin = np.array([int(np.min(refList.T[0])),int(np.min(refList.T[1])),int(np.min(refList.T[2]))])
3334        Hmax = np.array([int(np.max(refList.T[0])),int(np.max(refList.T[1])),int(np.max(refList.T[2]))])
3335        controls = {'Type' : 'Fo','ifFc' : True,'HKLmax' : Hmax,'HKLmin' : Hmin,
3336            'FoMax' : FoMax,'Zone' : '001','Layer' : 0,'Scale' : 1.0,'Super':Super,'SuperVec':SuperVec}
3337        G2plt.PlotSngl(G2frame,newPlot=True,Data=controls,hklRef=refList,Title=phaseName)
3338       
3339    def OnPlot3DHKL(event):
3340        '''Plots the reflections in 3D
3341        '''
3342        phaseName = G2frame.RefList
3343        if phaseName not in ['Unknown',]:
3344            pId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Phases')
3345            phaseId =  G2gd.GetPatternTreeItemId(G2frame,pId,phaseName)
3346            General = G2frame.PatternTree.GetItemPyData(phaseId)['General']
3347            Super = General.get('Super',0)
3348            SuperVec = General.get('SuperVec',[])
3349        else:
3350            Super = 0
3351            SuperVec = []       
3352        if 'list' in str(type(data)):   #single crystal data is 2 dict in list
3353            refList = data[1]['RefList']
3354        else:                           #powder data is a dict of dicts; each same structure as SC 2nd dict
3355            if 'RefList' in data[phaseName]:
3356                refList = np.array(data[phaseName]['RefList'])
3357            else:
3358                wx.MessageBox('No reflection list - do Refine first',caption='Reflection plotting')
3359                return
3360        refList.T[3+Super] = np.where(refList.T[4+Super]<dMin,-refList.T[3+Super],refList.T[3+Super])
3361        FoMax = np.max(refList.T[8+Super])
3362        Hmin = np.array([int(np.min(refList.T[0])),int(np.min(refList.T[1])),int(np.min(refList.T[2]))])
3363        Hmax = np.array([int(np.max(refList.T[0])),int(np.max(refList.T[1])),int(np.max(refList.T[2]))])
3364        Vpoint = np.array([int(np.mean(refList.T[0])),int(np.mean(refList.T[1])),int(np.mean(refList.T[2]))])
3365        controls = {'Type':'Fosq','Iscale':False,'HKLmax':Hmax,'HKLmin':Hmin,'Zone':False,'viewKey':'L',
3366            'FoMax' : FoMax,'Scale' : 1.0,'Drawing':{'viewPoint':[Vpoint,[]],'default':Vpoint[:],
3367            'backColor':[0,0,0],'depthFog':False,'Zclip':10.0,'cameraPos':10.,'Zstep':0.05,'viewUp':[0,1,0],
3368            'Scale':1.0,'oldxy':[],'viewDir':[0,0,1]},'Super':Super,'SuperVec':SuperVec}
3369        G2plt.Plot3DSngl(G2frame,newPlot=True,Data=controls,hklRef=refList,Title=phaseName)
3370       
3371    def MakeReflectionTable(phaseName):
3372        '''Returns a wx.grid table (G2G.Table) containing a list of all reflections
3373        for a phase.       
3374        '''
3375        if phaseName not in ['Unknown',]:
3376            pId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Phases')
3377            phaseId =  G2gd.GetPatternTreeItemId(G2frame,pId,phaseName)
3378            General = G2frame.PatternTree.GetItemPyData(phaseId)['General']
3379            Super = General.get('Super',0)
3380            SuperVec = General.get('SuperVec',[])
3381        else:
3382            Super = 0
3383            SuperVec = []       
3384        rowLabels = []
3385        if HKLF:
3386            refList = data[1]['RefList']
3387            refs = refList
3388        else:
3389            if len(data) > 1:
3390                G2frame.dataFrame.SelectPhase.Enable(True)
3391            try:            #patch for old reflection lists
3392                if not len(data[phaseName]):
3393                    return None
3394                refList = np.array(data[phaseName]['RefList'])
3395                I100 = refList.T[8+Super]*refList.T[11+Super]
3396            except TypeError:
3397                refList = np.array([refl[:11+Super] for refl in data[phaseName]])
3398                I100 = refList.T[8+Super]*np.array([refl[11+Super] for refl in data[phaseName]])
3399            Imax = np.max(I100)
3400            if Imax:
3401                I100 *= 100.0/Imax
3402            if 'C' in Inst['Type'][0]:
3403                refs = np.vstack((refList.T[:15+Super],I100)).T
3404            elif 'T' in Inst['Type'][0]:
3405                refs = np.vstack((refList.T[:18+Super],I100)).T
3406            G2frame.HKL = np.vstack((refList.T[:6+Super])).T    #build for plots
3407        rowLabels = [str(i) for i in range(len(refs))]
3408        Types = (4+Super)*[wg.GRID_VALUE_LONG,]+4*[wg.GRID_VALUE_FLOAT+':10,4',]+ \
3409            2*[wg.GRID_VALUE_FLOAT+':10,2',]+[wg.GRID_VALUE_FLOAT+':10,3',]+ \
3410            [wg.GRID_VALUE_FLOAT+':10,3',]
3411        if HKLF:
3412            colLabels = ['H','K','L','twin','d','Fosq','sig','Fcsq','FoTsq','FcTsq','phase','ExtC',]
3413            if 'T' in Inst['Type'][0]:
3414                colLabels = ['H','K','L','twin','d','Fosq','sig','Fcsq','FoTsq','FcTsq','phase','ExtC','wave','tbar']
3415                Types += 2*[wg.GRID_VALUE_FLOAT+':10,3',]
3416            if Super:
3417                colLabels.insert(3,'M')
3418        else:
3419            if 'C' in Inst['Type'][0]:
3420                colLabels = ['H','K','L','mul','d','pos','sig','gam','Fosq','Fcsq','phase','Icorr','Prfo','Trans','ExtP','I100']
3421                Types += 4*[wg.GRID_VALUE_FLOAT+':10,3',]
3422            elif 'T' in Inst['Type'][0]:
3423                colLabels = ['H','K','L','mul','d','pos','sig','gam','Fosq','Fcsq','phase','Icorr','alp','bet','wave','Prfo','Abs','Ext','I100']
3424                Types += 7*[wg.GRID_VALUE_FLOAT+':10,3',]
3425            if Super:
3426                colLabels.insert(3,'M')
3427        refs.T[3+Super] = np.where(refs.T[4+Super]<dMin,-refs.T[3+Super],refs.T[3+Super])
3428        return G2G.Table(refs,rowLabels=rowLabels,colLabels=colLabels,types=Types)
3429
3430    def ShowReflTable(phaseName):
3431        '''Posts a table of reflections for a phase, creating the table
3432        if needed using MakeReflectionTable
3433        '''
3434        def setBackgroundColors(im,it):
3435            for r in range(G2frame.refTable[phaseName].GetNumberRows()):
3436                if HKLF:
3437                    if float(G2frame.refTable[phaseName].GetCellValue(r,3+im)) <= 0.:
3438                        G2frame.refTable[phaseName].SetCellBackgroundColour(r,3+im,wx.RED)
3439                    Fosq = float(G2frame.refTable[phaseName].GetCellValue(r,5+im))
3440                    Fcsq = float(G2frame.refTable[phaseName].GetCellValue(r,7+im))
3441                    sig = float(G2frame.refTable[phaseName].GetCellValue(r,6+im))
3442                    rat = 11.
3443                    if sig:
3444                        rat = abs(Fosq-Fcsq)/sig
3445                    if  rat > 10.:
3446                        G2frame.refTable[phaseName].SetCellBackgroundColour(r,7+im,wx.RED)
3447                    elif rat > 3.0:
3448                        G2frame.refTable[phaseName].SetCellBackgroundColour(r,7+im,wx.Colour(255,255,0))
3449                else:   #PWDR
3450                    if float(G2frame.refTable[phaseName].GetCellValue(r,12+im+itof)) < 0.:
3451                        G2frame.refTable[phaseName].SetCellBackgroundColour(r,12+im+itof,wx.RED)
3452                    if float(G2frame.refTable[phaseName].GetCellValue(r,3+im)) < 0:
3453                        G2frame.refTable[phaseName].SetCellBackgroundColour(r,8+im,wx.RED)
3454                       
3455                                                 
3456        G2frame.RefList = phaseName
3457        G2frame.dataFrame.SetLabel('Reflection List for '+phaseName)
3458        if HKLF:
3459            Status.SetStatusText('abs(DF)/sig > 10 red; > 3 yellow; twin < 0 (user rejected) red; twin=0 (sp. gp. absent) red')
3460        else:
3461            Status.SetStatusText('Prfo < 0. in red; if excluded Fosq in red & mul < 0')
3462        itof = 0
3463        if HKLF:
3464            im = data[1].get('Super',0)
3465        else:
3466            if 'T' in data[phaseName].get('Type',''):
3467                itof = 3
3468            im = data[phaseName].get('Super',0)
3469        # has this table already been displayed?
3470        if G2frame.refTable[phaseName].GetTable() is None:
3471            PeakTable = MakeReflectionTable(phaseName)
3472            G2frame.refTable[phaseName].SetTable(PeakTable, True)
3473            G2frame.refTable[phaseName].EnableEditing(False)
3474            G2frame.refTable[phaseName].SetMargins(0,0)
3475            G2frame.refTable[phaseName].AutoSizeColumns(False)
3476            setBackgroundColors(im,itof)
3477        # raise the tab (needed for 1st use and from OnSelectPhase)
3478        for PageNum in range(G2frame.dataDisplay.GetPageCount()):
3479            if phaseName == G2frame.dataDisplay.GetPageText(PageNum):
3480                G2frame.dataDisplay.SetSelection(PageNum)
3481                break
3482        else:
3483            print phaseName
3484            print phases
3485            raise Exception("how did we not find a phase name?")
3486       
3487    def OnPageChanged(event):
3488        '''Respond to a press on a phase tab by displaying the reflections. This
3489        routine is needed because the reflection table may not have been created yet.
3490        '''
3491        page = event.GetSelection()
3492        phaseName = G2frame.dataDisplay.GetPageText(page)
3493        ShowReflTable(phaseName)
3494
3495    def OnSelectPhase(event):
3496        '''For PWDR, selects a phase with a selection box. Called from menu.
3497        '''
3498        if len(phases) < 2: return
3499        dlg = wx.SingleChoiceDialog(G2frame,'Select','Phase',phases)
3500        try:
3501            if dlg.ShowModal() == wx.ID_OK:
3502                sel = dlg.GetSelection()
3503                ShowReflTable(phases[sel])
3504        finally:
3505            dlg.Destroy()
3506           
3507    if not data:
3508        print 'No phases, no reflections'
3509        return
3510    if HKLF:
3511        G2frame.RefList = 1
3512        phaseName = IsHistogramInAnyPhase(G2frame,Name)
3513        if not phaseName:
3514            phaseName = 'Unknown'
3515        phases = [phaseName]
3516    else:
3517        phaseName = G2frame.RefList
3518        phases = data.keys()
3519    if G2frame.dataDisplay:
3520        G2frame.dataFrame.Clear()
3521    Inst = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Instrument Parameters'))[0]
3522    if HKLF:
3523        G2gd.SetDataMenuBar(G2frame)
3524        G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.ReflMenu)
3525        if not G2frame.dataFrame.GetStatusBar():
3526            Status = G2frame.dataFrame.CreateStatusBar()   
3527        G2frame.Bind(wx.EVT_MENU, OnPlotHKL, id=G2gd.wxID_PWDHKLPLOT)
3528        G2frame.Bind(wx.EVT_MENU, OnPlot3DHKL, id=G2gd.wxID_PWD3DHKLPLOT)
3529        G2frame.dataFrame.SelectPhase.Enable(False)
3530    else:
3531        G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.ReflMenu)
3532        if not G2frame.dataFrame.GetStatusBar():
3533            Status = G2frame.dataFrame.CreateStatusBar()   
3534        G2frame.Bind(wx.EVT_MENU, OnSelectPhase, id=G2gd.wxID_SELECTPHASE)
3535        G2frame.Bind(wx.EVT_MENU, OnPlotHKL, id=G2gd.wxID_PWDHKLPLOT)
3536        G2frame.Bind(wx.EVT_MENU, OnPlot3DHKL, id=G2gd.wxID_PWD3DHKLPLOT)
3537        G2frame.dataFrame.SelectPhase.Enable(False)
3538           
3539    G2frame.dataDisplay = G2G.GSNoteBook(parent=G2frame.dataFrame,size=G2frame.dataFrame.GetClientSize())
3540    G2frame.refTable = {}
3541    for tabnum,phase in enumerate(phases):
3542        G2frame.refTable[phase] = G2G.GSGrid(parent=G2frame.dataDisplay)
3543        G2frame.dataDisplay.AddPage(G2frame.refTable[phase],phase)
3544#    if phaseName not in G2frame.refTable:
3545#        print phaseName
3546#        print phases
3547#        raise Exception("how did we get a invalid phase name?")   
3548    ShowReflTable(phaseName)
3549#    G2frame.refTable[phaseName].Fit()   #slow!!
3550#    size = G2frame.refTable[phaseName].GetSize()
3551#    G2frame.dataFrame.setSizePosLeft([size[0]+32,350])
3552    G2frame.dataFrame.setSizePosLeft([550,350])
3553    G2frame.dataDisplay.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CHANGED, OnPageChanged)
3554   
3555################################################################################
3556#####  SASD Substances
3557################################################################################
3558           
3559def UpdateSubstanceGrid(G2frame,data):
3560    '''respond to selection of SASD Substance data tree item.
3561    '''
3562    import Substances as substFile
3563   
3564    def OnLoadSubstance(event):
3565        names = substFile.Substances.keys()
3566        names.sort()
3567        dlg = wx.SingleChoiceDialog(G2frame, 'Which substance?', 'Select substance', names, wx.CHOICEDLG_STYLE)
3568        try:
3569            if dlg.ShowModal() == wx.ID_OK:
3570                name = names[dlg.GetSelection()]
3571            else:
3572                return
3573        finally:
3574            dlg.Destroy()
3575        data['Substances'][name] = {'Elements':{},'Volume':1.0,'Density':1.0,
3576            'Scatt density':0.0,'XAnom density':0.0,'XAbsorption':0.0}
3577        subst = substFile.Substances[name]
3578        ElList = subst['Elements'].keys()
3579        for El in ElList:
3580            Info = G2elem.GetAtomInfo(El.strip().capitalize())
3581            Info.update(subst['Elements'][El])
3582            data['Substances'][name]['Elements'][El] = Info
3583            if 'Volume' in subst:
3584                data['Substances'][name]['Volume'] = subst['Volume']
3585                data['Substances'][name]['Density'] = \
3586                    G2mth.Vol2Den(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])
3587            elif 'Density' in subst:
3588                data['Substances'][name]['Density'] = subst['Density']
3589                data['Substances'][name]['Volume'] = \
3590                    G2mth.Den2Vol(data['Substances'][name]['Elements'],data['Substances'][name]['Density'])
3591            else:
3592                data['Substances'][name]['Volume'] = G2mth.El2EstVol(data['Substances'][name]['Elements'])
3593                data['Substances'][name]['Density'] = \
3594                    G2mth.Vol2Den(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])
3595            data['Substances'][name]['Scatt density'] = \
3596                G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])[0]
3597            contrst,absorb = G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'],wave)         
3598            data['Substances'][name]['XAnom density'] = contrst
3599            data['Substances'][name]['XAbsorption'] = absorb
3600                         
3601        UpdateSubstanceGrid(G2frame,data)
3602       
3603    def OnCopySubstance(event):
3604        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
3605        histList = GetHistsLikeSelected(G2frame)
3606        if not histList:
3607            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
3608            return
3609        copyList = []
3610        dlg = G2G.G2MultiChoiceDialog(
3611            G2frame.dataFrame, 
3612            'Copy substances from\n'+hst[5:]+' to...',
3613            'Copy substances', histList)
3614        try:
3615            if dlg.ShowModal() == wx.ID_OK:
3616                for i in dlg.GetSelections(): 
3617                    copyList.append(histList[i])
3618        finally:
3619            dlg.Destroy()       
3620        for item in copyList:
3621            Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
3622            Inst = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Instrument Parameters'))[0]
3623            wave = G2mth.getWave(Inst)
3624            ndata = copy.deepcopy(data)
3625            for name in ndata['Substances'].keys():
3626                contrst,absorb = G2mth.XScattDen(ndata['Substances'][name]['Elements'],ndata['Substances'][name]['Volume'],wave)         
3627                ndata['Substances'][name]['XAnom density'] = contrst
3628                ndata['Substances'][name]['XAbsorption'] = absorb
3629            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Substances'),ndata)
3630   
3631    def OnAddSubstance(event):
3632        dlg = wx.TextEntryDialog(None,'Enter a name for this substance','Substance Name Entry','New substance',
3633            style=wx.OK)
3634        if dlg.ShowModal() == wx.ID_OK:
3635            Name = dlg.GetValue()
3636            data['Substances'][Name] = {'Elements':{},'Volume':1.0,'Density':1.0,
3637                'Scatt density':0.0,'XAnom density':0.,'XAbsorption':0.}
3638        dlg.Destroy()
3639        AddElement(Name)
3640        UpdateSubstanceGrid(G2frame,data)
3641       
3642    def OnDeleteSubstance(event):
3643        TextList = []
3644        for name in data['Substances']:
3645            if name != 'vacuum':
3646                TextList += [name,]
3647        if not TextList:
3648            return
3649        dlg = wx.SingleChoiceDialog(G2frame, 'Which substance?', 'Select substance to delete', TextList, wx.CHOICEDLG_STYLE)
3650        try:
3651            if dlg.ShowModal() == wx.ID_OK:
3652                name = TextList[dlg.GetSelection()]
3653            else:
3654                return
3655        finally:
3656            dlg.Destroy()
3657        del(data['Substances'][name])
3658        UpdateSubstanceGrid(G2frame,data)       
3659               
3660    def OnAddElement(event):       
3661        TextList = []
3662        for name in data['Substances']:
3663            if name != 'vacuum':
3664                TextList += [name,]
3665        if not TextList:
3666            return
3667        dlg = wx.SingleChoiceDialog(G2frame, 'Which substance?', 'Select substance', TextList, wx.CHOICEDLG_STYLE)
3668        try:
3669            if dlg.ShowModal() == wx.ID_OK:
3670                name = TextList[dlg.GetSelection()]
3671            else:
3672                return
3673        finally:
3674            dlg.Destroy()
3675        AddElement(name)
3676        UpdateSubstanceGrid(G2frame,data)
3677       
3678    def AddElement(name):
3679        ElList = data['Substances'][name]['Elements'].keys()
3680        dlg = G2elemGUI.PickElements(G2frame,ElList)
3681        if dlg.ShowModal() == wx.ID_OK:
3682            for El in dlg.Elem:
3683                El = El.strip().capitalize()
3684                Info = G2elem.GetAtomInfo(El)
3685                Info.update({'Num':1})
3686                data['Substances'][name]['Elements'][El] = Info
3687            data['Substances'][name]['Volume'] = G2mth.El2EstVol(data['Substances'][name]['Elements'])
3688            data['Substances'][name]['Density'] = \
3689                G2mth.Vol2Den(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])
3690            data['Substances'][name]['Scatt density'] = \
3691                G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])[0]
3692            contrst,absorb = G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'],wave)         
3693            data['Substances'][name]['XAnom density'] = contrst
3694            data['Substances'][name]['XAbsorption'] = absorb
3695        dlg.Destroy()
3696       
3697    def OnDeleteElement(event):
3698        TextList = []
3699        for name in data['Substances']:
3700            if name != 'vacuum':
3701                TextList += [name,]
3702        if not TextList:
3703            return
3704        dlg = wx.SingleChoiceDialog(G2frame, 'Which substance?', 'Select substance', TextList, wx.CHOICEDLG_STYLE)
3705        try:
3706            if dlg.ShowModal() == wx.ID_OK:
3707                name = TextList[dlg.GetSelection()]
3708            else:
3709                return
3710        finally:
3711            dlg.Destroy()
3712        ElList = data['Substances'][name]['Elements'].keys()
3713        if len(ElList):
3714            DE = G2elemGUI.DeleteElement(G2frame,ElList)
3715            if DE.ShowModal() == wx.ID_OK:
3716                El = DE.GetDeleteElement().strip().upper()
3717                del(data['Substances'][name]['Elements'][El])
3718                data['Substances'][name]['Volume'] = G2mth.El2EstVol(data['Substances'][name]['Elements'])
3719                data['Substances'][name]['Density'] = \
3720                    G2mth.Vol2Den(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])
3721                data['Substances'][name]['Scatt density'] = \
3722                    G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])[0]
3723                contrst,absorb = G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'],wave)         
3724                data['Substances'][name]['XAnom density'] = contrst
3725                data['Substances'][name]['XAbsorption'] = absorb
3726        UpdateSubstanceGrid(G2frame,data)
3727               
3728    def SubstSizer():
3729       
3730        def OnValueChange(event):
3731            Obj = event.GetEventObject()
3732            if len(Indx[Obj.GetId()]) == 3:
3733                name,El,keyId = Indx[Obj.GetId()]
3734                try:
3735                    value = max(0,float(Obj.GetValue()))
3736                except ValueError:
3737                    value = 0
3738                    Obj.SetValue('%.2f'%(value))
3739                data['Substances'][name]['Elements'][El][keyId] = value
3740                data['Substances'][name]['Volume'] = G2mth.El2EstVol(data['Substances'][name]['Elements'])
3741                data['Substances'][name]['Density'] = \
3742                    G2mth.Vol2Den(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])
3743            else:
3744                name,keyId = Indx[Obj.GetId()]
3745                try:
3746                    value = max(0,float(Obj.GetValue()))
3747                except ValueError:
3748                    value = 1.0
3749                data['Substances'][name][keyId] = value
3750                if keyId in 'Volume':
3751                    data['Substances'][name]['Density'] = \
3752                        G2mth.Vol2Den(data['Substances'][name]['Elements'],value)
3753                elif keyId in 'Density':
3754                    data['Substances'][name]['Volume'] = \
3755                        G2mth.Den2Vol(data['Substances'][name]['Elements'],value)
3756            data['Substances'][name]['Scatt density'] = \
3757                G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])[0]
3758            contrst,absorb = G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'],wave)         
3759            data['Substances'][name]['XAnom density'] = contrst
3760            data['Substances'][name]['XAbsorption'] = absorb
3761            wx.CallAfter(UpdateSubstanceGrid,G2frame,data)
3762       
3763        Indx = {}
3764        substSizer = wx.BoxSizer(wx.VERTICAL)
3765        substSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Substance list: wavelength: %.5fA'%(wave)),
3766            0,WACV)
3767        for name in data['Substances']:
3768            G2G.HorizontalLine(substSizer,G2frame.dataDisplay)   
3769            substSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Data for '+name+':'),
3770                0,WACV)
3771            if name == 'vacuum':
3772                substSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label='        Not applicable'),
3773                    0,WACV)
3774            else:   
3775                elSizer = wx.FlexGridSizer(0,6,5,5)
3776                Substance = data['Substances'][name]
3777                Elems = Substance['Elements']
3778                for El in Elems:    #do elements as pull downs for isotopes for neutrons
3779                    elSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' '+El+': '),
3780                        0,WACV)
3781                    num = wx.TextCtrl(G2frame.dataDisplay,value='%.2f'%(Elems[El]['Num']),style=wx.TE_PROCESS_ENTER)
3782                    Indx[num.GetId()] = [name,El,'Num']
3783                    num.Bind(wx.EVT_TEXT_ENTER,OnValueChange)       
3784                    num.Bind(wx.EVT_KILL_FOCUS,OnValueChange)
3785                    elSizer.Add(num,0,WACV)
3786                substSizer.Add(elSizer,0)
3787                vdsSizer = wx.FlexGridSizer(0,4,5,5)
3788                vdsSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Volume: '),
3789                    0,WACV)
3790                vol = wx.TextCtrl(G2frame.dataDisplay,value='%.3f'%(Substance['Volume']),style=wx.TE_PROCESS_ENTER)
3791                Indx[vol.GetId()] = [name,'Volume']
3792                vol.Bind(wx.EVT_TEXT_ENTER,OnValueChange)       
3793                vol.Bind(wx.EVT_KILL_FOCUS,OnValueChange)
3794                vdsSizer.Add(vol,0,WACV)               
3795                vdsSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Density: '),
3796                    0,WACV)
3797                den = wx.TextCtrl(G2frame.dataDisplay,value='%.3f'%(Substance['Density']),style=wx.TE_PROCESS_ENTER)
3798                Indx[den.GetId()] = [name,'Density']
3799                den.Bind(wx.EVT_TEXT_ENTER,OnValueChange)       
3800                den.Bind(wx.EVT_KILL_FOCUS,OnValueChange)
3801                vdsSizer.Add(den,0,WACV)
3802                substSizer.Add(vdsSizer,0)
3803                substSizer.Add(wx.StaticText(G2frame.dataDisplay,
3804                    label=' Scattering density  : %.2f *10%scm%s'%(Substance['Scatt density'],Pwr10,Pwrm2)),
3805                    0,WACV)               
3806                substSizer.Add(wx.StaticText(G2frame.dataDisplay,       #allow neutrons here into NAnom density & NAbsorption
3807                    label=' Anomalous density : %.2f *10%scm%s'%(Substance['XAnom density'],Pwr10,Pwrm2)),
3808                    0,WACV)               
3809                substSizer.Add(wx.StaticText(G2frame.dataDisplay,
3810                    label=' X-ray absorption   : %.2f cm%s'%(Substance['XAbsorption'],Pwrm1)),
3811                    0,WACV)               
3812        return substSizer
3813           
3814    Inst = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Instrument Parameters'))[0]
3815    wave = G2mth.getWave(Inst)
3816    if G2frame.dataDisplay:
3817        G2frame.dataFrame.DestroyChildren()  # is this a ScrolledWindow? If so, bad!
3818    G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.SubstanceMenu)
3819    if not G2frame.dataFrame.GetStatusBar():
3820        Status = G2frame.dataFrame.CreateStatusBar()
3821    G2frame.dataDisplay = wxscroll.ScrolledPanel(G2frame.dataFrame)
3822    G2frame.dataFrame.SetLabel('Substances')
3823    G2frame.dataFrame.Bind(wx.EVT_MENU, OnLoadSubstance, id=G2gd.wxID_LOADSUBSTANCE)   
3824    G2frame.dataFrame.Bind(wx.EVT_MENU, OnAddSubstance, id=G2gd.wxID_ADDSUBSTANCE)
3825    G2frame.dataFrame.Bind(wx.EVT_MENU, OnCopySubstance, id=G2gd.wxID_COPYSUBSTANCE)
3826    G2frame.dataFrame.Bind(wx.EVT_MENU, OnDeleteSubstance, id=G2gd.wxID_DELETESUBSTANCE)   
3827    G2frame.dataFrame.Bind(wx.EVT_MENU, OnAddElement, id=G2gd.wxID_ELEMENTADD)
3828    G2frame.dataFrame.Bind(wx.EVT_MENU, OnDeleteElement, id=G2gd.wxID_ELEMENTDELETE)
3829    mainSizer = wx.BoxSizer(wx.VERTICAL)
3830    mainSizer.Add(SubstSizer(),0)
3831
3832    mainSizer.Layout()   
3833    G2frame.dataDisplay.SetSizer(mainSizer)
3834    G2frame.dataDisplay.SetAutoLayout(1)
3835    G2frame.dataDisplay.SetupScrolling()
3836    Size = mainSizer.Fit(G2frame.dataFrame)
3837    Size[0] += 25
3838    G2frame.dataDisplay.SetSize(Size)
3839    G2frame.dataFrame.setSizePosLeft(Size)   
3840       
3841################################################################################
3842#####  SASD Models
3843################################################################################           
3844       
3845def UpdateModelsGrid(G2frame,data):
3846    '''respond to selection of SASD Models data tree item.
3847    '''
3848    #patches
3849    if 'Current' not in data:
3850        data['Current'] = 'Size dist.'
3851    if 'logBins' not in data['Size']:
3852        data['Size']['logBins'] = True
3853    if 'MinMaxDiam' in data['Size']:
3854        data['Size']['MinDiam'] = 50.
3855        data['Size']['MaxDiam'] = 10000.
3856        del data['Size']['MinMaxDiam']
3857    if isinstance(data['Size']['MaxEnt']['Sky'],float):
3858        data['Size']['MaxEnt']['Sky'] = -3
3859    if 'Power' not in data['Size']['IPG']:
3860        data['Size']['IPG']['Power'] = -1
3861    if 'Matrix' not in data['Particle']:
3862        data['Particle']['Matrix'] = {'Name':'vacuum','VolFrac':[0.0,False]}
3863    if 'BackFile' not in data:
3864        data['BackFile'] = ''
3865    #end patches
3866   
3867    def RefreshPlots(newPlot=False):
3868        PlotText = G2frame.G2plotNB.nb.GetPageText(G2frame.G2plotNB.nb.GetSelection())
3869        if 'Powder' in PlotText:
3870            G2plt.PlotPatterns(G2frame,plotType='SASD',newPlot=newPlot)
3871        elif 'Size' in PlotText:
3872            G2plt.PlotSASDSizeDist(G2frame)
3873               
3874    def OnAddModel(event):
3875        if data['Current'] == 'Particle fit':
3876            material = 'vacuum'
3877            if len(data['Particle']['Levels']):
3878                material = data['Particle']['Levels'][-1]['Controls']['Material']
3879            data['Particle']['Levels'].append({
3880                'Controls':{'FormFact':'Sphere','DistType':'LogNormal','Material':material,
3881                    'FFargs':{},'SFargs':{},'NumPoints':50,'Cutoff':0.01,'Contrast':0.0,
3882                    'SlitSmear':[0.0,False],'StrFact':'Dilute'},    #last 2 not used - future?
3883                'LogNormal':{'Volume':[0.05,False],'Mean':[1000.,False],'StdDev':[0.5,False],'MinSize':[10.,False],},
3884                'Gaussian':{'Volume':[0.05,False],'Mean':[1000.,False],'StdDev':[300.,False],},
3885                'LSW':{'Volume':[0.05,False],'Mean':[1000.0,False],},
3886                'Schulz-Zimm':{'Volume':[0.05,False],'Mean':[1000.,False],'StdDev':[300.,False],},
3887                'Unified':{'G':[1.e3,False],'Rg':[100,False],'B':[1.e-5,False],'P':[4,False],'Cutoff':[1e-5,False],},
3888                'Porod':{'B':[1.e-4,False],'P':[4,False],'Cutoff':[1e-5,False],},
3889                'Monodisperse':{'Volume':[0.05,False],'Radius':[100,False],},   #OK for spheres
3890                'Bragg':{'PkInt':[100,False],'PkPos':[0.2,False],
3891                    'PkSig':[10,False],'PkGam':[10,False],},        #reasonable 31A peak
3892                })
3893            G2sasd.ModelFxn(Profile,ProfDict,Limits,Sample,data)
3894            RefreshPlots(True)
3895                   
3896        wx.CallAfter(UpdateModelsGrid,G2frame,data)
3897       
3898    def OnCopyModel(event):
3899        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
3900        histList = GetHistsLikeSelected(G2frame)
3901        if not histList:
3902            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
3903            return
3904        copyList = []
3905        dlg = G2G.G2MultiChoiceDialog(
3906            G2frame.dataFrame, 
3907            'Copy models from\n'+hst[5:]+' to...',
3908            'Copy models', histList)
3909        try:
3910            if dlg.ShowModal() == wx.ID_OK:
3911                for i in dlg.GetSelections(): 
3912                    copyList.append(histList[i])
3913        finally:
3914            dlg.Destroy()       
3915        for item in copyList:
3916            Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
3917            newdata = copy.deepcopy(data)
3918            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Models'),newdata)
3919            if newdata['BackFile']:
3920                Profile = G2frame.PatternTree.GetItemPyData(Id)[1]
3921                BackId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,newdata['BackFile'])
3922                BackSample = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,BackId, 'Sample Parameters'))
3923                Profile[5] = BackSample['Scale'][0]*G2frame.PatternTree.GetItemPyData(BackId)[1][1]
3924        UpdateModelsGrid(G2frame,newdata) 
3925        wx.CallAfter(UpdateModelsGrid,G2frame,data)
3926        RefreshPlots(True)
3927               
3928    def OnCopyFlags(event):
3929        thisModel = copy.deepcopy(data)
3930        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
3931        histList = GetHistsLikeSelected(G2frame)
3932        if not histList:
3933            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
3934            return
3935        dlg = G2G.G2MultiChoiceDialog(
3936            G2frame.dataFrame, 
3937            'Copy sample ref. flags from\n'+str(hst[5:])+' to...',
3938            'Copy sample flags', histList)
3939        distChoice = ['LogNormal','Gaussian','LSW','Schulz-Zimm','Bragg','Unified',
3940            'Porod','Monodisperse',]
3941        parmOrder = ['Volume','Radius','Mean','StdDev','G','Rg','B','P',
3942            'Cutoff','PkInt','PkPos','PkSig','PkGam','VolFr','Dist',]
3943        try:
3944            if dlg.ShowModal() == wx.ID_OK:
3945                result = dlg.GetSelections()
3946                for i in result: 
3947                    item = histList[i]
3948                    Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
3949                    newModel = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Models'))
3950                    newModel['Back'][1] = copy.copy(thisModel['Back'][1])
3951                    for ilev,level in enumerate(newModel['Particle']['Levels']):
3952                        for form in level:
3953                            if form in distChoice:
3954                                thisForm = thisModel['Particle']['Levels'][ilev][form]                               
3955                                for item in parmOrder:
3956                                    if item in thisForm:
3957                                       level[form][item][1] = copy.copy(thisForm[item][1])
3958                            elif form == 'Controls':
3959                                thisForm = thisModel['Particle']['Levels'][ilev][form]['SFargs']
3960                                for item in parmOrder:
3961                                    if item in thisForm:
3962                                        level[form]['SFargs'][item][1] = copy.copy(thisForm[item][1])
3963        finally:
3964            dlg.Destroy()
3965               
3966    def OnFitModelAll(event):
3967        choices = G2gd.GetPatternTreeDataNames(G2frame,['SASD',])
3968        sel = []
3969        dlg = G2G.G2MultiChoiceDialog(G2frame.dataFrame, 'Sequential SASD refinement',
3970             'Select dataset to include',choices)
3971        dlg.SetSelections(sel)
3972        names = []
3973        if dlg.ShowModal() == wx.ID_OK:
3974            for sel in dlg.GetSelections():
3975                names.append(choices[sel])
3976        dlg.Destroy()
3977        SeqResult = {'histNames':names}
3978        Reverse = False
3979        CopyForward = False
3980        choice = ['Reverse sequence','Copy from prev.']
3981        dlg = wx.MultiChoiceDialog(G2frame.dataFrame,'Sequential controls','Select controls',choice)
3982        if dlg.ShowModal() == wx.ID_OK:
3983            for sel in dlg.GetSelections():
3984                if sel:
3985                    CopyForward = True
3986                else:
3987                    Reverse = True
3988        dlg.Destroy()
3989        dlg = wx.ProgressDialog('SASD Sequential fit','Data set name = '+names[0],len(names), 
3990            style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE|wx.PD_REMAINING_TIME|wx.PD_CAN_ABORT)
3991        wx.BeginBusyCursor()
3992        if Reverse:
3993            names.reverse()
3994        try:
3995            for i,name in enumerate(names):
3996                print ' Sequential fit for ',name
3997                GoOn = dlg.Update(i,newmsg='Data set name = '+name)[0]
3998                if not GoOn:
3999                    break
4000                Id =  G2gd.GetPatternTreeItemId(G2frame,G2frame.root,name)
4001                if i and CopyForward:
4002                    G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Models'),JModel)
4003                IProfDict,IProfile = G2frame.PatternTree.GetItemPyData(Id)[:2]
4004                IModel = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Models'))
4005                ISample = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Sample Parameters'))
4006                ILimits = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Limits'))
4007                IfOK,result,varyList,sig,Rvals,covMatrix,parmDict,Msg = G2sasd.ModelFit(IProfile,IProfDict,ILimits,ISample,IModel)
4008                JModel = copy.deepcopy(IModel)
4009                if not IfOK:
4010                    G2frame.ErrorDialog('Failed sequential refinement for data '+name,
4011                        ' Msg: '+Msg+'\nYou need to rethink your selection of parameters\n'+    \
4012                        ' Model restored to previous version for'+name)
4013                    SeqResult['histNames'] = names[:i]
4014                    dlg.Destroy()
4015                    break
4016                else:
4017                    G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Models'),copy.deepcopy(IModel))
4018               
4019                G2sasd.ModelFxn(IProfile,IProfDict,ILimits,ISample,IModel)
4020                SeqResult[name] = {'variables':result[0],'varyList':varyList,'sig':sig,'Rvals':Rvals,
4021                    'covMatrix':covMatrix,'title':name,'parmDict':parmDict}
4022            else:
4023                dlg.Destroy()
4024                print ' ***** Small angle sequential refinement successful *****'
4025        finally:
4026            wx.EndBusyCursor()   
4027        Id =  G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Sequential results')
4028        if Id:
4029            G2frame.PatternTree.SetItemPyData(Id,SeqResult)
4030        else:
4031            Id = G2frame.PatternTree.AppendItem(parent=G2frame.root,text='Sequential results')
4032            G2frame.PatternTree.SetItemPyData(Id,SeqResult)
4033        G2frame.PatternTree.SelectItem(Id)
4034       
4035    def OnFitModel(event):
4036        if data['Current'] == 'Size dist.':
4037            if not any(Sample['Contrast']):
4038                G2frame.ErrorDialog('No contrast; your sample is a vacuum!',
4039                    'You need to define a scattering substance!\n'+    \
4040                    ' Do Substances and then Sample parameters')
4041                return
4042            G2sasd.SizeDistribution(Profile,ProfDict,Limits,Sample,data)
4043            G2plt.PlotSASDSizeDist(G2frame)
4044            RefreshPlots(True)
4045           
4046        elif data['Current'] == 'Particle fit':
4047            SaveState()
4048            Results = G2sasd.ModelFit(Profile,ProfDict,Limits,Sample,data)
4049            if not Results[0]:
4050                    G2frame.ErrorDialog('Failed refinement',
4051                        ' Msg: '+Results[-1]+'\nYou need to rethink your selection of parameters\n'+    \
4052                        ' Model restored to previous version')
4053            G2sasd.ModelFxn(Profile,ProfDict,Limits,Sample,data)
4054            RefreshPlots(True)
4055            wx.CallAfter(UpdateModelsGrid,G2frame,data)
4056           
4057    def OnUnDo(event):
4058        DoUnDo()
4059        data = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,
4060            G2frame.PatternId,'Models'))
4061        G2frame.dataFrame.SasdUndo.Enable(False)
4062        UpdateModelsGrid(G2frame,data)
4063        G2sasd.ModelFxn(Profile,ProfDict,Limits,Sample,data)
4064        RefreshPlots(True)
4065
4066    def DoUnDo():
4067        print 'Undo last refinement'
4068        file = open(G2frame.undosasd,'rb')
4069        PatternId = G2frame.PatternId
4070        G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Models'),cPickle.load(file))
4071        print ' Models recovered'
4072        file.close()
4073       
4074    def SaveState():
4075        G2frame.undosasd = os.path.join(G2frame.dirname,'GSASIIsasd.save')
4076        file = open(G2frame.undosasd,'wb')
4077        PatternId = G2frame.PatternId
4078        for item in ['Models']:
4079            cPickle.dump(G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId,item)),file,1)
4080        file.close()
4081        G2frame.dataFrame.SasdUndo.Enable(True)
4082       
4083    def OnSelectFit(event):
4084        data['Current'] = fitSel.GetValue()
4085        wx.CallAfter(UpdateModelsGrid,G2frame,data)
4086       
4087    def OnCheckBox(event):
4088        Obj = event.GetEventObject()
4089        item,ind = Indx[Obj.GetId()]
4090        item[ind] = Obj.GetValue()
4091       
4092    def OnIntVal(event):
4093        Obj = event.GetEventObject()
4094        item,ind,minVal = Indx[Obj.GetId()]
4095        try:
4096            value = int(Obj.GetValue())
4097            if value <= minVal:
4098                raise ValueError
4099        except ValueError:
4100            value = item[ind]
4101        Obj.SetValue(str(value))
4102        item[ind] = value
4103
4104    def SizeSizer():
4105       
4106        def OnShape(event):
4107            data['Size']['Shape'][0] = partsh.GetValue()
4108            wx.CallAfter(UpdateModelsGrid,G2frame,data)
4109           
4110        def OnMethod(event):
4111            data['Size']['Method'] = method.GetValue()
4112            wx.CallAfter(UpdateModelsGrid,G2frame,data)
4113           
4114        def OnPartVal(event):
4115            try:
4116                val = max(0.0,float(partprm.GetValue()))
4117            except ValueError:
4118                val = 1
4119            data['Size']['Shape'][1] = val
4120            partprm.SetValue('%.3f'%(val))
4121           
4122        sizeSizer = wx.BoxSizer(wx.VERTICAL)
4123        sizeSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Size distribution parameters: '),0,WACV)
4124        binSizer = wx.FlexGridSizer(0,7,5,5)
4125        binSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' No. size bins: '),0,WACV)
4126        bins = ['50','100','150','200']
4127        nbins = wx.ComboBox(G2frame.dataDisplay,value=str(data['Size']['Nbins']),choices=bins,
4128            style=wx.CB_READONLY|wx.CB_DROPDOWN)
4129        Indx[nbins.GetId()] = [data['Size'],'Nbins',0]
4130        nbins.Bind(wx.EVT_COMBOBOX,OnIntVal)       
4131        binSizer.Add(nbins,0,WACV)
4132        binSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Min diam.: '),0,WACV)
4133        minDias = ['10','25','50','100','150','200']
4134        mindiam = wx.ComboBox(G2frame.dataDisplay,value=str(data['Size']['MinDiam']),choices=minDias,
4135            style=wx.CB_DROPDOWN)
4136        mindiam.Bind(wx.EVT_LEAVE_WINDOW,OnIntVal)
4137        mindiam.Bind(wx.EVT_TEXT_ENTER,OnIntVal)       
4138        mindiam.Bind(wx.EVT_KILL_FOCUS,OnIntVal)
4139        Indx[mindiam.GetId()] = [data['Size'],'MinDiam',0]
4140        binSizer.Add(mindiam,0,WACV)
4141        binSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Max diam.: '),0,WACV)
4142        maxDias = [str(1000*(i+1)) for i in range(10)]
4143        maxdiam = wx.ComboBox(G2frame.dataDisplay,value=str(data['Size']['MaxDiam']),choices=maxDias,
4144            style=wx.CB_DROPDOWN)
4145        maxdiam.Bind(wx.EVT_LEAVE_WINDOW,OnIntVal)
4146        maxdiam.Bind(wx.EVT_TEXT_ENTER,OnIntVal)       
4147        maxdiam.Bind(wx.EVT_KILL_FOCUS,OnIntVal)
4148        Indx[maxdiam.GetId()] = [data['Size'],'MaxDiam',0]
4149        binSizer.Add(maxdiam,0,WACV)
4150        logbins = wx.CheckBox(G2frame.dataDisplay,label='Log bins?')
4151        Indx[logbins.GetId()] = [data['Size'],'logBins']
4152        logbins.SetValue(data['Size']['logBins'])
4153        logbins.Bind(wx.EVT_CHECKBOX, OnCheckBox)
4154        binSizer.Add(logbins,0,WACV)
4155        sizeSizer.Add(binSizer,0)
4156        sizeSizer.Add((5,5),0)
4157        partSizer = wx.BoxSizer(wx.HORIZONTAL)
4158        partSizer.Add(wx.StaticText(G2frame.dataDisplay,label='Particle description: '),0,WACV)
4159        shapes = {'Spheroid':' Aspect ratio: ','Cylinder':' Diameter ','Cylinder AR':' Aspect ratio: ',
4160            'Unified sphere':'','Unified rod':' Diameter: ','Unified rod AR':' Aspect ratio: ',
4161            'Unified disk':' Thickness: ', 'Spherical shell': ' Shell thickness'}
4162        partsh = wx.ComboBox(G2frame.dataDisplay,value=str(data['Size']['Shape'][0]),choices=shapes.keys(),
4163            style=wx.CB_READONLY|wx.CB_DROPDOWN)
4164        partsh.Bind(wx.EVT_COMBOBOX,OnShape)       
4165        partSizer.Add(partsh,0,WACV)
4166        if data['Size'