source: trunk/GSASIIpwdGUI.py @ 2654

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

improve ComputeAllPDF progress msg; PDF contour plot: change G(r)_min

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