source: trunk/GSASIIpwdGUI.py @ 2659

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

make lab data (2 x-ray wavelengths) instrument default 'Bragg-Brentano', all others 'Debye-Scherrer'
refactor PDF stuff to show PDF Controls & (new) PDF Peaks on G2 tree (removing I(Q)...).
Old gpx files with I(Q)... updated automatically to new scheme
Add new tree item for PDF Peaks - does nothing yet.
Fix FWHM calc for TOF so bins/FWHM on peak fitting make sense.

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