source: trunk/GSASIIpwdGUI.py @ 2673

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

moved GetFileList? to top of G2pwdGUI - needed in two places. The one on GSASII doesn't seem to work & isn't used anywhere.
Put missing import of G2elem & tof2q lambda in G2imgGUI.

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