source: trunk/GSASIIpwdGUI.py @ 2521

Last change on this file since 2521 was 2521, checked in by toby, 5 years ago

extensions to Peak List: vary via menu items; animate line dragging; highlight selected peak(s)

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