source: trunk/GSASIIpwdGUI.py @ 2570

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

more TextCtrl? --> ValidatedTextCtrl?

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