source: trunk/GSASIIpwdGUI.py @ 2505

Last change on this file since 2505 was 2505, checked in by vondreele, 5 years ago

fix busy cursor problem for seq peak fit. Too far inside loop.

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