source: trunk/GSASIIpwdGUI.py @ 2569

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

add 'f' or 'g' to maxdigits in FormatValue? in G2py3 - should be revised some more
do a lot of TextCtrl? --> ValidatedTextCtrl? replacements
note that ValidatedTextCtrl? only checks val <= max & not val < max
added tc.event to ValidatedTextCtrl? as some things needed that
G2imgGui - mostly done
G2restrGUI - done
G2pwdGUI - started

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