source: trunk/GSASIIpwdGUI.py @ 1880

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

fix wx bug in SetMapPeaksText? - 'GridWindow?' vs 'grid window'
add characteristic source choice to single crystal instrument parameters -
select mean Ka = (2*Ka1+Ka2)/3
change default single crystal wavelength to MoKa?

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