source: trunk/GSASIIpwdGUI.py @ 2544

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

major cleanup of unused variables, etc.

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