source: trunk/GSASIIpwdGUI.py @ 2546

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

cleanup of all GSASII main routines - remove unused variables, dead code, etc.

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