source: trunk/GSASIIpwdGUI.py @ 2634

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

add ExpandAll? to main File menu
change PDF plotting to use color schemes for multiplots
's' option on multiplot changed to color scheme selection
removed G9r0-4pi*r plot

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