source: trunk/GSASIIpwdGUI.py @ 2524

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

in ValidatedTxtCtrl? have _onLeaveWindow ignore mouse crusing
replace the Table in limits with FlexGrids? & Text boxes

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