source: trunk/GSASIIpwdGUI.py @ 2563

Last change on this file since 2563 was 2563, checked in by vondreele, 7 years ago

Speed up image integration on Mac by reducing ProgressBar? calls from 3*nBlk*nBlk+3 to Nblk+3
Allow PDF setup to include chemical formula from tif macrofile
fix contour bug for G(R), etc.
fix copy error for masks

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