source: trunk/GSASIIpwdGUI.py @ 2355

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

fix plot bug
add RDF calc - in progress
add background correction to pdf

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