source: trunk/GSASIIpwdGUI.py @ 2610

Last change on this file since 2610 was 2610, checked in by toby, 6 years ago

fix bug on change in PDF files; save location when images are moved

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