source: trunk/GSASIIpwdGUI.py @ 1827

Last change on this file since 1827 was 1827, checked in by toby, 8 years ago

fix scrollbar problems in many places; phase data in particular

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 220.0 KB
Line 
1# -*- coding: utf-8 -*-
2#GSASIIpwdGUI - powder data display routines
3########### SVN repository information ###################
4# $Date: 2015-04-30 19:38:20 +0000 (Thu, 30 Apr 2015) $
5# $Author: toby $
6# $Revision: 1827 $
7# $URL: trunk/GSASIIpwdGUI.py $
8# $Id: GSASIIpwdGUI.py 1827 2015-04-30 19:38:20Z toby $
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: 1827 $")
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 = G2gd.Table(data['peaks'],rowLabels=rowLabels,colLabels=colLabels,types=Types)
707    G2frame.dataFrame.SetLabel('Peak List')
708    G2frame.dataDisplay = G2gd.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.4f'%(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 = G2gd.Table(data[1]['debyeTerms'],rowLabels=rowLabels,colLabels=colLabels,types=Types)
917            debyeGrid = G2gd.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 = G2gd.Table(data[1]['peaksList'],rowLabels=rowLabels,colLabels=colLabels,types=Types)
977            peaksGrid = G2gd.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 = G2gd.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 = G2gd.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
1160    def OnLoad(event):
1161        '''Loads instrument parameters from a G2 .instprm file
1162        in response to the Instrument Parameters-Operations/Load Profile menu
1163       
1164        Note that similar code is found in ReadPowderInstprm (GSASII.py)
1165        '''
1166        dlg = wx.FileDialog(G2frame, 'Choose GSAS-II instrument parameters file', '.', '', 
1167            'instrument parameter files (*.instprm)|*.instprm',wx.OPEN|wx.CHANGE_DIR)
1168        try:
1169            if dlg.ShowModal() == wx.ID_OK:
1170                filename = dlg.GetPath()
1171                File = open(filename,'r')
1172                S = File.readline()
1173                newItems = []
1174                newVals = []
1175                while S:
1176                    if S[0] == '#':
1177                        S = File.readline()
1178                        continue
1179                    [item,val] = S[:-1].split(':')
1180                    newItems.append(item)
1181                    try:
1182                        newVals.append(float(val))
1183                    except ValueError:
1184                        newVals.append(val)                       
1185                    S = File.readline()               
1186                File.close()
1187                Inst,Inst2 = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId,'Instrument Parameters'))
1188                data = G2IO.makeInstDict(newItems,newVals,len(newVals)*[False,])
1189                G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId,'Instrument Parameters'),[data,Inst2])
1190                RefreshInstrumentGrid(event,doAnyway=True)          #to get peaks updated
1191                UpdateInstrumentGrid(G2frame,data)
1192                G2plt.PlotPeakWidths(G2frame)
1193        finally:
1194            dlg.Destroy()
1195       
1196    def OnSave(event):
1197        '''Respond to the Instrument Parameters Operations/Save Profile menu
1198        item: writes current parameters to a .instprm file
1199        '''
1200        dlg = wx.FileDialog(G2frame, 'Choose GSAS-II instrument parameters file', '.', '', 
1201            'instrument parameter files (*.instprm)|*.instprm',wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT|wx.CHANGE_DIR)
1202        try:
1203            if dlg.ShowModal() == wx.ID_OK:
1204                filename = dlg.GetPath()
1205                # make sure extension is .instprm
1206                filename = os.path.splitext(filename)[0]+'.instprm'
1207                File = open(filename,'w')
1208                File.write("#GSAS-II instrument parameter file; do not add/delete items!\n")
1209                for item in data:
1210                    File.write(item+':'+str(data[item][1])+'\n')
1211                File.close()
1212        finally:
1213            dlg.Destroy()
1214                                               
1215    def OnReset(event):
1216        insVal.update(insDef)
1217        updateData(insVal,insRef)
1218        RefreshInstrumentGrid(event,doAnyway=True)          #to get peaks updated
1219        UpdateInstrumentGrid(G2frame,data)
1220        G2plt.PlotPeakWidths(G2frame)
1221       
1222    def OnInstFlagCopy(event):
1223        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
1224        histList = GetHistsLikeSelected(G2frame)
1225        if not histList:
1226            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
1227            return
1228        keys = data.keys()
1229        flags = dict(zip(keys,[data[key][2] for key in keys]))
1230        instType = data['Type'][0]
1231        copyList = []
1232        dlg = G2G.G2MultiChoiceDialog(
1233            G2frame.dataFrame, 
1234            'Copy inst ref. flags from\n'+hst[5:],
1235            'Copy refinement flags', histList)
1236        try:
1237            if dlg.ShowModal() == wx.ID_OK:
1238                for i in dlg.GetSelections():
1239                    copyList.append(histList[i])
1240        finally:
1241            dlg.Destroy()
1242        for item in copyList:
1243            Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
1244            instData = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Instrument Parameters'))[0]
1245            if len(data) == len(instData) and instType == instData['Type'][0]:   #don't mix data types or lam & lam1/lam2 parms!
1246                for item in instData:
1247                    instData[item][2] = copy.copy(flags[item])
1248            else:
1249                print item+' not copied - instrument parameters not commensurate'
1250       
1251    def OnInstCopy(event):
1252        #need fix for dictionary
1253        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
1254        histList = GetHistsLikeSelected(G2frame)
1255        if not histList:
1256            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
1257            return
1258        copyList = []
1259        instType = data['Type'][0]
1260        dlg = G2G.G2MultiChoiceDialog(
1261            G2frame.dataFrame, 
1262            'Copy inst params from\n'+hst,
1263            'Copy parameters', histList)
1264        try:
1265            if dlg.ShowModal() == wx.ID_OK:
1266                for i in dlg.GetSelections(): 
1267                    copyList.append(histList[i])
1268        finally:
1269            dlg.Destroy()
1270        for item in copyList:
1271            Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
1272            instData = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Instrument Parameters'))[0]
1273            if len(data) == len(instData) and instType == instData['Type'][0]:  #don't mix data types or lam & lam1/lam2 parms!
1274                instData.update(data)
1275            else:
1276                print item+' not copied - instrument parameters not commensurate'
1277                         
1278    def AfterChange(invalid,value,tc):
1279        if invalid: return
1280        updateData(insVal,insRef)
1281       
1282    def OnItemRef(event):
1283        Obj = event.GetEventObject()
1284        item = RefObj[Obj.GetId()]
1285        insRef[item] = Obj.GetValue()
1286        updateData(insVal,insRef)
1287
1288    def OnCopy1Val(event):
1289        '''Select one instrument parameter value to edit and copy to many histograms
1290        optionally allow values to be edited in a table
1291        '''
1292        updateData(insVal,insRef)
1293        G2G.SelectEdit1Var(G2frame,data,labelLst,elemKeysLst,dspLst,refFlgElem)
1294        insVal.update({key:data[key][1] for key in instkeys})
1295        insRef.update({key:data[key][2] for key in instkeys})
1296        wx.CallAfter(MakeParameterWindow)
1297       
1298    def lblWdef(lbl,dec,val):
1299        'Label parameter showing the default value'
1300        fmt = "%15."+str(dec)+"f"
1301        return " " + lbl + " (" + (fmt % val).strip() + "): "
1302
1303    def RefineBox(item):
1304        'Define a refine checkbox with binding'
1305        wid = wx.CheckBox(G2frame.dataDisplay,label=' Refine?  ')
1306        wid.SetValue(bool(insRef[item]))
1307        RefObj[wid.GetId()] = item
1308        wid.Bind(wx.EVT_CHECKBOX, OnItemRef)
1309        return wid
1310
1311    def OnLamPick(event):
1312        data['Source'][1] = lamType = event.GetEventObject().GetValue()
1313        insVal['Lam1'] = waves[lamType][0]
1314        insVal['Lam2'] = waves[lamType][1]
1315        updateData(insVal,insRef)
1316        i,j= wx.__version__.split('.')[0:2]
1317        if int(i)+int(j)/10. > 2.8:
1318            pass # repaint crashes wxpython 2.9
1319            wx.CallLater(100, MakeParameterWindow)
1320            #wx.CallAfter(MakeParameterWindow)
1321        else:
1322            wx.CallAfter(MakeParameterWindow)
1323
1324    def MakeParameterWindow():
1325        'Displays the Instrument parameters in the datadisplay frame'
1326        if G2frame.dataDisplay:
1327            G2frame.dataFrame.Clear()
1328        G2frame.dataFrame.SetLabel('Instrument Parameters')
1329        G2frame.dataDisplay = wx.Panel(G2frame.dataFrame)
1330        mainSizer = wx.BoxSizer(wx.VERTICAL)
1331        instSizer = wx.FlexGridSizer(0,6,5,5)
1332        subSizer = wx.BoxSizer(wx.HORIZONTAL)
1333        subSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' Histogram Type: '+insVal['Type']),0,WACV)
1334        mainSizer.Add(subSizer)
1335        labelLst[:],elemKeysLst[:],dspLst[:],refFlgElem[:] = [],[],[],[]
1336        if 'P' in insVal['Type']:                   #powder data
1337            if 'C' in insVal['Type']:               #constant wavelength
1338                labelLst.append('Azimuth angle')
1339                elemKeysLst.append(['Azimuth',1])
1340                dspLst.append([10,2])
1341                refFlgElem.append(None)                   
1342                if 'Lam1' in insVal:
1343                    subSizer = wx.BoxSizer(wx.HORIZONTAL)
1344                    subSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' Azimuth: '),0,WACV)
1345                    txt = '%7.2f'%(insVal['Azimuth'])
1346                    subSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,txt.strip()),0,WACV)
1347                    subSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,'   Ka1/Ka2: '),0,WACV)
1348                    txt = u%8.6f/%8.6f\xc5'%(insVal['Lam1'],insVal['Lam2'])
1349                    subSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,txt.strip()),0,WACV)
1350                    waveSizer = wx.BoxSizer(wx.HORIZONTAL)
1351                    waveSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,'  Source type: '),0,WACV)
1352                    # PATCH?: for now at least, Source is not saved anywhere before here
1353                    if 'Source' not in data: data['Source'] = ['CuKa','?']
1354                    choice = ['TiKa','CrKa','FeKa','CoKa','CuKa','MoKa','AgKa']
1355                    lamPick = wx.ComboBox(G2frame.dataDisplay,value=data['Source'][1],choices=choice,style=wx.CB_READONLY|wx.CB_DROPDOWN)
1356                    lamPick.Bind(wx.EVT_COMBOBOX, OnLamPick)
1357                    waveSizer.Add(lamPick,0)
1358                    subSizer.Add(waveSizer,0)
1359                    mainSizer.Add(subSizer)
1360                    instSizer.Add(wx.StaticText(
1361                        G2frame.dataDisplay,-1,
1362                        lblWdef('I(L2)/I(L1)',4,insDef['I(L2)/I(L1)'])),
1363                        0,WACV)
1364                    key = 'I(L2)/I(L1)'
1365                    labelLst.append(key)
1366                    elemKeysLst.append([key,1])
1367                    dspLst.append([10,4])
1368                    refFlgElem.append([key,2])                   
1369                    ratVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,insVal,key,nDig=(10,4),typeHint=float,OnLeave=AfterChange)
1370                    instSizer.Add(ratVal,0)
1371                    instSizer.Add(RefineBox(key),0,WACV)
1372                    instSizer.Add((5,5),0)
1373                    instSizer.Add((5,5),0)
1374                    instSizer.Add((5,5),0)               
1375                else: # single wavelength
1376                    instSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' Azimuth: '),0,WACV)
1377                    txt = '%7.2f'%(insVal['Azimuth'])
1378                    instSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,txt.strip()),0,WACV)
1379                    instSizer.Add((5,5),0)
1380                    key = 'Lam'
1381                    instSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,u' Lam (\xc5): (%10.6f)'%(insDef[key])),
1382                        0,WACV)
1383                    waveVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,insVal,key,nDig=(10,6),typeHint=float,OnLeave=AfterChange)
1384                    labelLst.append(u'Lam (\xc5)')
1385                    elemKeysLst.append([key,1])
1386                    dspLst.append([10,6])
1387                    instSizer.Add(waveVal,0,WACV)
1388                    refFlgElem.append([key,2])                   
1389                    instSizer.Add(RefineBox(key),0,WACV)
1390#                    if ifHisto:
1391#                        refFlgElem.append([key,2])                   
1392#                        instSizer.Add(RefineBox(key),0,WACV)
1393#                    else:
1394#                        refFlgElem.append(None)                   
1395#                        instSizer.Add((5,5),0)
1396                for item in ['Zero','Polariz.']:
1397                    if item in insDef:
1398                        labelLst.append(item)
1399                        elemKeysLst.append([item,1])
1400                        dspLst.append([10,4])
1401                        instSizer.Add(
1402                            wx.StaticText(G2frame.dataDisplay,-1,lblWdef(item,4,insDef[item])),
1403                            0,WACV)
1404                        itemVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,insVal,item,nDig=(10,4),typeHint=float,OnLeave=AfterChange)
1405                        instSizer.Add(itemVal,0,WACV)
1406                        refFlgElem.append([item,2])
1407                        instSizer.Add(RefineBox(item),0,WACV)
1408#                        if ifHisto:
1409#                            refFlgElem.append([item,2])
1410#                            instSizer.Add(RefineBox(item),0,WACV)
1411#                        else:
1412#                            refFlgElem.append(None)                   
1413#                            instSizer.Add((5,5),0)
1414                    else:                           #skip Polariz. for neutrons
1415                        instSizer.Add((5,5),0)
1416                        instSizer.Add((5,5),0)
1417                        instSizer.Add((5,5),0)
1418                for item in ['U','V','W','','X','Y','SH/L']:
1419                    if item == '':
1420                        instSizer.Add((5,5),0)
1421                        instSizer.Add((5,5),0)
1422                        instSizer.Add((5,5),0)
1423                        continue
1424                    nDig = (10,3)
1425                    if item == 'SH/L':
1426                        nDig = (10,5)
1427                    labelLst.append(item)
1428                    elemKeysLst.append([item,1])
1429                    dspLst.append(nDig)
1430                    refFlgElem.append([item,2])
1431                    instSizer.Add(
1432                        wx.StaticText(G2frame.dataDisplay,-1,lblWdef(item,nDig[1],insDef[item])),
1433                        0,WACV)
1434                    itemVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,insVal,item,nDig=nDig,typeHint=float,OnLeave=AfterChange)
1435                    instSizer.Add(itemVal,0,WACV)
1436                    instSizer.Add(RefineBox(item),0,WACV)
1437            elif 'T' in insVal['Type']:                                   #time of flight (neutrons)
1438                subSizer = wx.BoxSizer(wx.HORIZONTAL)
1439                subSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' Fligth path: '),0,WACV)
1440                txt = '%8.3f'%(insVal['fltPath'])
1441                subSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,txt.strip()),0,WACV)
1442                labelLst.append('flight path')
1443                elemKeysLst.append(['fltpath',1])
1444                dspLst.append([10,2])
1445                refFlgElem.append(None)                   
1446                subSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,'  2-theta: '),0,WACV)
1447                txt = '%7.2f'%(insVal['2-theta'])
1448                subSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,txt.strip()),0,WACV)
1449                labelLst.append('2-theta')
1450                elemKeysLst.append(['2-theta',1])
1451                dspLst.append([10,2])
1452                refFlgElem.append(None)                   
1453                if 'Pdabc' in Inst2:
1454                    Items = ['sig-0','sig-1','sig-2','sig-q','X','Y']
1455                    subSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,'  difC: '),0,WACV)
1456                    txt = '%8.2f'%(insVal['difC'])
1457                    subSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,txt.strip()),0,WACV)
1458                    labelLst.append('difC')
1459                    elemKeysLst.append(['difC',1])
1460                    dspLst.append([10,2])
1461                    refFlgElem.append(None)
1462                    subSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,'  alpha, beta: fixed by table'),0,WACV)
1463                else:
1464                    Items = ['difC','difA','difB','Zero','alpha','beta-0','beta-1','beta-q','sig-0','sig-1','sig-2','sig-q','X','Y']
1465                mainSizer.Add((5,5),0)
1466                mainSizer.Add(subSizer)
1467                mainSizer.Add((5,5),0)
1468                for item in Items:
1469                    if item == '':
1470                        instSizer.Add((5,5),0)
1471                        instSizer.Add((5,5),0)
1472                        instSizer.Add((5,5),0)
1473                        continue
1474                    nDig = (10,3)
1475                    fmt = '%10.3f'
1476                    if 'beta' in item:
1477                        fmt = '%12.6g'
1478                        nDig = (12,6)
1479                    Fmt = ' %s: ('+fmt+')'
1480                    instSizer.Add(
1481                            wx.StaticText(G2frame.dataDisplay,-1,lblWdef(item,nDig[1],insDef[item])),
1482                            0,WACV)
1483                    itemVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,insVal,item,nDig=nDig,typeHint=float,OnLeave=AfterChange)
1484                    instSizer.Add(itemVal,0,WACV)
1485                    labelLst.append(item)
1486                    elemKeysLst.append([item,1])
1487                    dspLst.append(nDig)
1488                    refFlgElem.append([item,2])
1489                    instSizer.Add(RefineBox(item),0,WACV)
1490            elif 'PKS' in insVal['Type']:   #peak positions only
1491                key = 'Lam'
1492                instSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,u' Lam (\xc5): (%10.6f)'%(insDef[key])),
1493                    0,WACV)
1494                waveVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,insVal,key,nDig=(10,6),typeHint=float,OnLeave=AfterChange)
1495                labelLst.append(u'Lam (\xc5)')
1496                elemKeysLst.append([key,1])
1497                dspLst.append([10,6])
1498                instSizer.Add(waveVal,0,WACV)
1499                refFlgElem.append([key,2])                   
1500#                    instSizer.Add(RefineBox(key),0,WACV)
1501                for item in ['Zero',]:
1502                    if item in insDef:
1503                        labelLst.append(item)
1504                        elemKeysLst.append([item,1])
1505                        dspLst.append([10,4])
1506                        instSizer.Add(
1507                            wx.StaticText(G2frame.dataDisplay,-1,lblWdef(item,4,insDef[item])),
1508                            0,WACV)
1509                        itemVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,insVal,item,nDig=(10,4),typeHint=float,OnLeave=AfterChange)
1510                        instSizer.Add(itemVal,0,WACV)
1511                        refFlgElem.append([item,2])
1512#                        instSizer.Add(RefineBox(item),0,WACV)
1513               
1514               
1515        elif 'S' in insVal['Type']:                       #single crystal data
1516            if 'C' in insVal['Type']:               #constant wavelength
1517                instSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,u' Lam (\xc5): (%10.6f)'%(insDef['Lam'])),
1518                    0,WACV)
1519                waveVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,insVal,'Lam',nDig=(10,6),typeHint=float,OnLeave=AfterChange)
1520                instSizer.Add(waveVal,0,WACV)
1521                labelLst.append(u'Lam (\xc5)')
1522                elemKeysLst.append(['Lam',1])
1523                dspLst.append([10,6])
1524                refFlgElem.append(None)
1525            else:                                   #time of flight (neutrons)
1526                pass                                #for now
1527        elif 'L' in insVal['Type']:
1528            if 'C' in insVal['Type']:       
1529                instSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,u' Lam (\xc5): (%10.6f)'%(insDef['Lam'])),
1530                    0,WACV)
1531                waveVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,insVal,'Lam',nDig=(10,6),typeHint=float,OnLeave=AfterChange)
1532                instSizer.Add(waveVal,0,WACV)
1533                labelLst.append(u'Lam (\xc5)')
1534                elemKeysLst.append(['Lam',1])
1535                dspLst.append([10,6])
1536                refFlgElem.append(None)
1537                instSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,'  Azimuth: %7.2f'%(insVal['Azimuth'])),0,WACV)
1538                labelLst.append('Azimuth angle')
1539                elemKeysLst.append(['Azimuth',1])
1540                dspLst.append([10,2])
1541                refFlgElem.append(None)                   
1542            else:                                   #time of flight (neutrons)
1543                pass                                #for now
1544
1545        mainSizer.Add(instSizer,0)
1546        mainSizer.Layout()   
1547        G2frame.dataDisplay.SetSizer(mainSizer)
1548        G2frame.dataFrame.setSizePosLeft(mainSizer.Fit(G2frame.dataFrame))
1549        G2frame.dataFrame.SendSizeEvent()  # this causes a frame repaint, even if the size does not change!
1550        # end of MakeParameterWindow
1551               
1552    # beginning of UpdateInstrumentGrid code   
1553    #patch: make sure all parameter items are lists
1554    patched = 0
1555    for key in data:
1556        if type(data[key]) is tuple:
1557            data[key] = list(data[key])
1558            patched += 1
1559    if patched: print patched,' instrument parameters changed from tuples'
1560    #end of patch
1561    labelLst,elemKeysLst,dspLst,refFlgElem = [],[],[],[]
1562    instkeys = keycheck(data.keys())
1563    if 'P' in data['Type'][0]:          #powder data
1564        insVal = dict(zip(instkeys,[data[key][1] for key in instkeys]))
1565        insDef = dict(zip(instkeys,[data[key][0] for key in instkeys]))
1566        insRef = dict(zip(instkeys,[data[key][2] for key in instkeys]))
1567        if 'NC' in data['Type'][0]:
1568            del(insDef['Polariz.'])
1569            del(insVal['Polariz.'])
1570            del(insRef['Polariz.'])
1571    elif 'S' in data['Type'][0]:                               #single crystal data
1572        insVal = dict(zip(instkeys,[data[key][1] for key in instkeys]))
1573        insDef = dict(zip(instkeys,[data[key][0] for key in instkeys]))
1574        insRef = {}
1575    elif 'L' in data['Type'][0]:                               #low angle data
1576        insVal = dict(zip(instkeys,[data[key][1] for key in instkeys]))
1577        insDef = dict(zip(instkeys,[data[key][0] for key in instkeys]))
1578        insRef = {}
1579    ValObj = {}
1580    RefObj = {}
1581    waves = {'CuKa':[1.54051,1.54433],'TiKa':[2.74841,2.75207],'CrKa':[2.28962,2.29351],
1582        'FeKa':[1.93597,1.93991],'CoKa':[1.78892,1.79278],'MoKa':[0.70926,0.713543],
1583        'AgKa':[0.559363,0.563775]}
1584    Inst2 = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,
1585            G2frame.PatternId,'Instrument Parameters'))[1]       
1586    try:
1587        histoName = G2frame.PatternTree.GetItemPyData(G2frame.PatternId)[-1]
1588        ifHisto = IsHistogramInAnyPhase(G2frame,histoName)
1589    except TypeError:       #PKS data never used in a phase as data
1590        ifhisto = False
1591    G2gd.SetDataMenuBar(G2frame)
1592    #patch
1593    if 'P' in insVal['Type']:                   #powder data
1594        if 'C' in insVal['Type']:               #constant wavelength
1595            if 'Azimuth' not in insVal:
1596                insVal['Azimuth'] = 0.0
1597                insDef['Azimuth'] = 0.0
1598                insRef['Azimuth'] = False
1599#        if 'T' in insVal['Type']:
1600#            if 'difB' not in insVal:
1601#                insVal['difB'] = 0.0
1602#                insDef['difB'] = 0.0
1603#                insRef['difB'] = False
1604    #end of patch
1605    if 'P' in insVal['Type']:                   #powder data menu commands
1606        G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.InstMenu)
1607        if not G2frame.dataFrame.GetStatusBar():
1608            Status = G2frame.dataFrame.CreateStatusBar()           
1609        G2frame.Bind(wx.EVT_MENU,OnCalibrate,id=G2gd.wxID_INSTCALIB)
1610        G2frame.Bind(wx.EVT_MENU,OnLoad,id=G2gd.wxID_INSTLOAD)
1611        G2frame.Bind(wx.EVT_MENU,OnSave,id=G2gd.wxID_INSTSAVE)
1612        G2frame.Bind(wx.EVT_MENU,OnReset,id=G2gd.wxID_INSTPRMRESET)
1613        G2frame.Bind(wx.EVT_MENU,OnInstCopy,id=G2gd.wxID_INSTCOPY)
1614        G2frame.Bind(wx.EVT_MENU,OnInstFlagCopy,id=G2gd.wxID_INSTFLAGCOPY)
1615        #G2frame.Bind(wx.EVT_MENU,OnWaveChange,id=G2gd.wxID_CHANGEWAVETYPE)       
1616        G2frame.Bind(wx.EVT_MENU,OnCopy1Val,id=G2gd.wxID_INST1VAL)
1617    elif 'L' in insVal['Type']:                   #SASD data menu commands
1618        G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.InstMenu)
1619        if not G2frame.dataFrame.GetStatusBar():
1620            Status = G2frame.dataFrame.CreateStatusBar()           
1621        G2frame.Bind(wx.EVT_MENU,OnInstCopy,id=G2gd.wxID_INSTCOPY)
1622    MakeParameterWindow()
1623       
1624   
1625################################################################################
1626#####  Sample parameters
1627################################################################################           
1628       
1629def UpdateSampleGrid(G2frame,data):
1630    '''respond to selection of PWDR/SASD Sample Parameters
1631    data tree item.
1632    '''
1633
1634    def OnSampleSave(event):
1635        '''Respond to the Sample Parameters Operations/Save menu
1636        item: writes current parameters to a .samprm file
1637        '''
1638        dlg = wx.FileDialog(G2frame, 'Choose GSAS-II sample parameters file', '.', '', 
1639            'sample parameter files (*.samprm)|*.samprm',wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT|wx.CHANGE_DIR)
1640        try:
1641            if dlg.ShowModal() == wx.ID_OK:
1642                filename = dlg.GetPath()
1643                # make sure extension is .samprm
1644                filename = os.path.splitext(filename)[0]+'.samprm'
1645                File = open(filename,'w')
1646                File.write("#GSAS-II sample parameter file\n")
1647                File.write("'Type':'"+str(data['Type'])+"'\n")
1648                File.write("'Gonio. radius':"+str(data['Gonio. radius'])+"\n")
1649                if data.get('InstrName'):
1650                    File.write("'InstrName':'"+str(data['InstrName'])+"'\n")
1651                File.close()
1652        finally:
1653            dlg.Destroy()
1654           
1655    def OnSampleLoad(event):
1656        '''Loads sample parameters from a G2 .samprm file
1657        in response to the Sample Parameters-Operations/Load menu
1658       
1659        Note that similar code is found in ReadPowderInstprm (GSASII.py)
1660        '''
1661        dlg = wx.FileDialog(G2frame, 'Choose GSAS-II sample parameters file', '.', '', 
1662            'sample parameter files (*.samprm)|*.samprm',wx.OPEN|wx.CHANGE_DIR)
1663        try:
1664            if dlg.ShowModal() == wx.ID_OK:
1665                filename = dlg.GetPath()
1666                File = open(filename,'r')
1667                S = File.readline()
1668                newItems = {}
1669                while S:
1670                    if S[0] == '#':
1671                        S = File.readline()
1672                        continue
1673                    [item,val] = S[:-1].split(':')
1674                    newItems[item.strip("'")] = eval(val)
1675                    S = File.readline()               
1676                File.close()
1677                data.update(newItems)
1678                G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId,'Sample Parameters'),data)
1679                UpdateSampleGrid(G2frame,data)
1680        finally:
1681            dlg.Destroy()
1682           
1683    def OnAllSampleLoad(event):
1684        filename = ''
1685        dlg = wx.FileDialog(G2frame, 'Choose multihistogram metadata text file', '.', '', 
1686            'metadata file (*.*)|*.*',wx.OPEN|wx.CHANGE_DIR)
1687        try:
1688            if dlg.ShowModal() == wx.ID_OK:
1689                filename = dlg.GetPath()
1690                File = open(filename,'r')
1691                S = File.readline()
1692                newItems = []
1693                itemNames = []
1694                Comments = []
1695                while S:
1696                    if S[0] == '#':
1697                        Comments.append(S)
1698                        S = File.readline()
1699                        continue
1700                    S = S.replace(',',' ').replace('\t',' ')
1701                    Stuff = S[:-1].split()
1702                    itemNames.append(Stuff[0])
1703                    newItems.append(Stuff[1:])
1704                    S = File.readline()               
1705                File.close()
1706        finally:
1707            dlg.Destroy()
1708        if not filename:
1709            G2frame.ErrorDialog('Nothing to do','No file selected')
1710            return
1711        dataDict = dict(zip(itemNames,newItems))
1712        ifany = False
1713        Controls = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Controls'))
1714        Names = [' ','Phi','Chi','Omega','Time','Temperature','Pressure']
1715        freeNames = {}
1716        for name in ['FreePrm1','FreePrm2','FreePrm3']:
1717            freeNames[Controls[name]] = name
1718            Names.append(Controls[name])
1719        dlg = G2gd.G2ColumnIDDialog( G2frame,' Choose multihistogram metadata columns:',
1720            'Select columns',Comments,Names,np.array(newItems).T)
1721        try:
1722            if dlg.ShowModal() == wx.ID_OK:
1723                colNames,newData = dlg.GetSelection()
1724                dataDict = dict(zip(itemNames,newData.T))
1725                for item in colNames:
1726                    if item != ' ':
1727                        ifany = True
1728        finally:
1729            dlg.Destroy()
1730        if not ifany:
1731            G2frame.ErrorDialog('Nothing to do','No columns identified')
1732            return
1733        histList = [G2frame.PatternTree.GetItemText(G2frame.PatternId),]
1734        histList += GetHistsLikeSelected(G2frame)
1735        colIds = {}
1736        for i,name in enumerate(colNames):
1737            if name != ' ':
1738                colIds[name] = i
1739        for hist in histList:
1740            name = hist.split()[1]  #this is file name
1741            newItems = {}
1742            for item in colIds:
1743                key = freeNames.get(item,item)
1744                newItems[key] = float(dataDict[name][colIds[item]])
1745            Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,hist)
1746            sampleData = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Sample Parameters'))
1747            sampleData.update(newItems)       
1748        UpdateSampleGrid(G2frame,data)       
1749   
1750    def OnSetScale(event):
1751        histList = []
1752        item, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)
1753        while item:
1754            name = G2frame.PatternTree.GetItemText(item)
1755            if 'SASD' in name and name != histName:
1756                histList.append(name)
1757            item, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)
1758        if not len(histList):      #nothing to copy to!
1759            return
1760        dlg = wx.SingleChoiceDialog(G2frame,'Select reference histogram for scaling',
1761            'Reference histogram',histList)
1762        try:
1763            if dlg.ShowModal() == wx.ID_OK:
1764                sel = dlg.GetSelection()
1765                refHist = histList[sel]
1766        finally:
1767            dlg.Destroy()
1768        Limits = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Limits'))
1769        Profile = G2frame.PatternTree.GetItemPyData(G2frame.PatternId)[1]
1770        Data = [Profile,Limits,data]
1771        refId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,refHist)
1772        refSample = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,refId, 'Sample Parameters'))
1773        refLimits = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,refId, 'Limits'))
1774        refProfile = G2frame.PatternTree.GetItemPyData(refId)[1]
1775        refData = [refProfile,refLimits,refSample]
1776        G2sasd.SetScale(Data,refData)
1777        G2plt.PlotPatterns(G2frame,plotType='SASD',newPlot=True)
1778        UpdateSampleGrid(G2frame,data)       
1779       
1780    def OnSampleCopy(event):
1781        histType,copyNames = SetCopyNames(histName,data['Type'],
1782            addNames = ['Omega','Chi','Phi','Gonio. radius','InstrName'])
1783        copyDict = {}
1784        for parm in copyNames:
1785            copyDict[parm] = data[parm]
1786        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
1787        histList = GetHistsLikeSelected(G2frame)
1788        if not histList:
1789            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
1790            return
1791        dlg = G2G.G2MultiChoiceDialog(
1792            G2frame.dataFrame,
1793            'Copy sample params from\n'+str(hst[5:])+' to...',
1794            'Copy sample parameters', histList)
1795        try:
1796            if dlg.ShowModal() == wx.ID_OK:
1797                result = dlg.GetSelections()
1798                for i in result: 
1799                    item = histList[i]
1800                    Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
1801                    sampleData = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Sample Parameters'))
1802                    sampleData.update(copy.deepcopy(copyDict))
1803        finally:
1804            dlg.Destroy()
1805
1806    def OnSampleCopySelected(event):
1807        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
1808        Controls = G2frame.PatternTree.GetItemPyData(
1809            G2gd.GetPatternTreeItemId(G2frame,G2frame.root, 'Controls'))
1810        histList = GetHistsLikeSelected(G2frame)
1811        if not histList:
1812            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
1813            return
1814        # Assemble a list of item labels
1815        TextTable = {key:label for key,label,dig in
1816                     SetupSampleLabels(hst,data.get('Type'),Inst['Type'][0])
1817                     }
1818        # get flexible labels
1819        TextTable.update({
1820            key:Controls[key] for key in Controls if key.startswith('FreePrm')
1821            })
1822        # add a few extra
1823        TextTable.update({
1824            'Type':'Diffractometer type',
1825            'InstrName':'Instrument Name',
1826            })
1827        # Assemble a list of dict entries that would be labeled in the Sample
1828        # params data window (drop ranId and items not used).
1829        keyList = [i for i in data.keys() if i in TextTable]
1830        keyText = [TextTable[i] for i in keyList]
1831        # sort both lists together, ordered by keyText
1832        keyText, keyList = zip(*sorted(zip(keyText,keyList))) # sort lists
1833        selectedKeys = []
1834        dlg = G2G.G2MultiChoiceDialog(
1835            G2frame.dataFrame,
1836            'Select which sample parameters\nto copy',
1837            'Select sample parameters', keyText)
1838        try:
1839            if dlg.ShowModal() == wx.ID_OK:
1840                selectedKeys = [keyList[i] for i in dlg.GetSelections()]
1841        finally:
1842            dlg.Destroy()
1843        if not selectedKeys: return # nothing to copy
1844        copyDict = {}
1845        for parm in selectedKeys:
1846            copyDict[parm] = data[parm]
1847        dlg = G2G.G2MultiChoiceDialog(
1848            G2frame.dataFrame,
1849            'Copy sample params from\n'+str(hst[5:])+' to...',
1850            'Copy sample parameters', histList)
1851        try:
1852            if dlg.ShowModal() == wx.ID_OK:
1853                result = dlg.GetSelections()
1854                for i in result: 
1855                    item = histList[i]
1856                    Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
1857                    sampleData = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Sample Parameters'))
1858                    sampleData.update(copy.deepcopy(copyDict))
1859        finally:
1860            dlg.Destroy()           
1861        G2plt.PlotPatterns(G2frame,plotType=hst[:4],newPlot=False)
1862
1863    def OnSampleFlagCopy(event):
1864        histType,copyNames = SetCopyNames(histName,data['Type'])
1865        flagDict = {}
1866        for parm in copyNames:
1867            flagDict[parm] = data[parm][1]
1868        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
1869        histList = GetHistsLikeSelected(G2frame)
1870        if not histList:
1871            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
1872            return
1873        dlg = G2G.G2MultiChoiceDialog(
1874            G2frame.dataFrame, 
1875            'Copy sample ref. flags from\n'+str(hst[5:])+' to...',
1876            'Copy sample flags', histList)
1877        try:
1878            if dlg.ShowModal() == wx.ID_OK:
1879                result = dlg.GetSelections()
1880                for i in result: 
1881                    item = histList[i]
1882                    Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
1883                    sampleData = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Sample Parameters'))
1884                    for name in copyNames:
1885                        sampleData[name][1] = copy.copy(flagDict[name])
1886        finally:
1887            dlg.Destroy()
1888
1889    def OnHistoChange():
1890        '''Called when the histogram type is changed to refresh the window
1891        '''
1892        wx.CallAfter(UpdateSampleGrid,G2frame,data)
1893       
1894    def SetNameVal():
1895        inst = instNameVal.GetValue()
1896        data['InstrName'] = inst.strip()
1897
1898    def OnNameVal(event):
1899        event.Skip()
1900        wx.CallAfter(SetNameVal)
1901       
1902    def AfterChange(invalid,value,tc):
1903        if invalid:
1904            return
1905        if tc.key == 0 and 'SASD' in histName:          #a kluge for Scale!
1906            G2plt.PlotPatterns(G2frame,plotType='SASD',newPlot=True)
1907        elif tc.key == 'Thick':
1908            wx.CallAfter(UpdateSampleGrid,G2frame,data)           
1909           
1910    def OnMaterial(event):
1911        Obj = event.GetEventObject()
1912        id,key = Info[Obj.GetId()]
1913        if key == 'Name':
1914            data['Materials'][id][key] = Obj.GetValue()
1915        elif key == 'VolFrac':
1916            try:
1917                value = min(max(0.,float(Obj.GetValue())),1.)
1918            except ValueError:
1919                value = data['Materials'][id][key]
1920            data['Materials'][id][key] = value
1921            data['Materials'][not id][key] = 1.-value
1922        wx.CallAfter(UpdateSampleGrid,G2frame,data)
1923
1924    def OnCopy1Val(event):
1925        'Select one value to copy to many histograms and optionally allow values to be edited in a table'
1926        G2G.SelectEdit1Var(G2frame,data,labelLst,elemKeysLst,dspLst,refFlgElem)
1927        wx.CallAfter(UpdateSampleGrid,G2frame,data)
1928       
1929    ######## DEBUG #######################################################
1930    #import GSASIIpwdGUI
1931    #reload(GSASIIpwdGUI)
1932    #reload(G2gd)
1933    ######################################################################
1934    Inst = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(
1935            G2frame,G2frame.PatternId, 'Instrument Parameters'))[0]
1936    histName = G2frame.PatternTree.GetItemText(G2frame.PatternId)
1937    if G2frame.dataDisplay:
1938        G2frame.dataFrame.Clear()
1939    G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.SampleMenu)
1940    G2frame.dataFrame.SetLabel('Sample Parameters')
1941    G2frame.Bind(wx.EVT_MENU, OnSetScale, id=G2gd.wxID_SETSCALE)
1942    G2frame.Bind(wx.EVT_MENU, OnSampleCopy, id=G2gd.wxID_SAMPLECOPY)
1943    G2frame.Bind(wx.EVT_MENU, OnSampleCopySelected, id=G2gd.wxID_SAMPLECOPYSOME)
1944    G2frame.Bind(wx.EVT_MENU, OnSampleFlagCopy, id=G2gd.wxID_SAMPLEFLAGCOPY)
1945    G2frame.Bind(wx.EVT_MENU, OnSampleSave, id=G2gd.wxID_SAMPLESAVE)
1946    G2frame.Bind(wx.EVT_MENU, OnSampleLoad, id=G2gd.wxID_SAMPLELOAD)
1947    G2frame.Bind(wx.EVT_MENU, OnCopy1Val, id=G2gd.wxID_SAMPLE1VAL)
1948    G2frame.Bind(wx.EVT_MENU, OnAllSampleLoad, id=G2gd.wxID_ALLSAMPLELOAD)
1949    if 'SASD' in histName:
1950        G2frame.dataFrame.SetScale.Enable(True)
1951    if not G2frame.dataFrame.GetStatusBar():
1952        Status = G2frame.dataFrame.CreateStatusBar()   
1953    G2frame.dataDisplay = wx.Panel(G2frame.dataFrame)
1954    Controls = G2frame.PatternTree.GetItemPyData(
1955        G2gd.GetPatternTreeItemId(G2frame,G2frame.root, 'Controls'))
1956#patch
1957    if 'ranId' not in data:
1958        data['ranId'] = ran.randint(0,sys.maxint)
1959    if not 'Gonio. radius' in data:
1960        data['Gonio. radius'] = 200.0
1961    if not 'Omega' in data:
1962        data.update({'Omega':0.0,'Chi':0.0,'Phi':0.0})
1963    if 'Azimuth' not in data:
1964        data['Azimuth'] = 0.0
1965    if type(data['Temperature']) is int:
1966        data['Temperature'] = float(data['Temperature'])
1967    if 'Time' not in data:
1968        data['Time'] = 0.0
1969    if 'FreePrm1' not in Controls:
1970        Controls['FreePrm1'] = 'Sample humidity (%)'
1971    if 'FreePrm2' not in Controls:
1972        Controls['FreePrm2'] = 'Sample voltage (V)'
1973    if 'FreePrm3' not in Controls:
1974        Controls['FreePrm3'] = 'Applied load (MN)'
1975    if 'FreePrm1' not in data:
1976        data['FreePrm1'] = 0.
1977    if 'FreePrm2' not in data:
1978        data['FreePrm2'] = 0.
1979    if 'FreePrm3' not in data:
1980        data['FreePrm3'] = 0.
1981    if 'SurfRoughA' not in data and 'PWDR' in histName:
1982        data['SurfRoughA'] = [0.,False]
1983        data['SurfRoughB'] = [0.,False]
1984    if 'Trans' not in data and 'SASD' in histName:
1985        data['Trans'] = 1.0
1986    if 'SlitLen' not in data and 'SASD' in histName:
1987        data['SlitLen'] = 0.0
1988    if 'Shift' not in data:
1989        data['Shift'] = [0.0,False]
1990    if 'Transparency' not in data:
1991        data['Transparency'] = [0.0,False]
1992    data['InstrName'] = data.get('InstrName','')
1993#patch end
1994    labelLst,elemKeysLst,dspLst,refFlgElem = [],[],[],[]
1995    parms = SetupSampleLabels(histName,data.get('Type'),Inst['Type'][0])
1996    mainSizer = wx.BoxSizer(wx.VERTICAL)
1997    topSizer = wx.BoxSizer(wx.HORIZONTAL)
1998    topSizer.Add((-1,-1),1,wx.EXPAND,1)
1999    topSizer.Add(wx.StaticText(G2frame.dataDisplay,label='Sample and Experimental Parameters'))
2000    topSizer.Add((-1,-1),1,wx.EXPAND,1)
2001    mainSizer.Add(topSizer,0,wx.EXPAND,1)
2002    nameSizer = wx.BoxSizer(wx.HORIZONTAL)
2003    nameSizer.Add(wx.StaticText(G2frame.dataDisplay,wx.ID_ANY,' Instrument Name'),
2004                0,WACV)
2005    nameSizer.Add((-1,-1),1,wx.EXPAND,1)
2006    instNameVal = wx.TextCtrl(G2frame.dataDisplay,wx.ID_ANY,data['InstrName'],
2007                              size=(200,-1),style=wx.TE_PROCESS_ENTER)       
2008    nameSizer.Add(instNameVal)
2009    instNameVal.Bind(wx.EVT_CHAR,OnNameVal)
2010    mainSizer.Add(nameSizer,0,wx.EXPAND,1)
2011    mainSizer.Add((5,5),0)
2012    labelLst.append('Instrument Name')
2013    elemKeysLst.append(['InstrName'])
2014    dspLst.append(None)
2015    refFlgElem.append(None)
2016
2017    if 'PWDR' in histName:
2018        nameSizer = wx.BoxSizer(wx.HORIZONTAL)
2019        nameSizer.Add(wx.StaticText(G2frame.dataDisplay,wx.ID_ANY,' Diffractometer type: '),
2020                    0,WACV)
2021        if 'T' in Inst['Type'][0]:
2022            choices = ['Debye-Scherrer',]
2023        else:
2024            choices = ['Debye-Scherrer','Bragg-Brentano',]
2025        histoType = G2gd.G2ChoiceButton(G2frame.dataDisplay,choices,
2026                    strLoc=data,strKey='Type',
2027                    onChoice=OnHistoChange)
2028        nameSizer.Add(histoType)
2029        mainSizer.Add(nameSizer,0,wx.EXPAND,1)
2030        mainSizer.Add((5,5),0)
2031
2032    parmSizer = wx.FlexGridSizer(0,2,5,0)
2033    for key,lbl,nDig in parms:
2034        labelLst.append(lbl.strip().strip(':').strip())
2035        dspLst.append(nDig)
2036        if 'list' in str(type(data[key])):
2037            parmRef = G2G.G2CheckBox(G2frame.dataDisplay,' '+lbl,data[key],1)
2038            parmSizer.Add(parmRef,0,WACV|wx.EXPAND)
2039            parmVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,data[key],0,
2040                nDig=nDig,typeHint=float,OnLeave=AfterChange)
2041            elemKeysLst.append([key,0])
2042            refFlgElem.append([key,1])
2043        else:
2044            parmSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' '+lbl),
2045                0,WACV|wx.EXPAND)
2046            parmVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,data,key,
2047                typeHint=float,OnLeave=AfterChange)
2048            elemKeysLst.append([key])
2049            refFlgElem.append(None)
2050        parmSizer.Add(parmVal,1,wx.EXPAND)
2051    Info = {}
2052       
2053    for key in ('FreePrm1','FreePrm2','FreePrm3'):
2054        parmVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,Controls,key,typeHint=str,
2055                                        notBlank=False)
2056        parmSizer.Add(parmVal,1,wx.EXPAND)
2057        parmVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,data,key,typeHint=float)
2058        parmSizer.Add(parmVal,1,wx.EXPAND)
2059        labelLst.append(Controls[key])
2060        dspLst.append(None)
2061        elemKeysLst.append([key])
2062        refFlgElem.append(None)
2063       
2064    mainSizer.Add(parmSizer,1,wx.EXPAND)
2065    mainSizer.Add((0,5),0)   
2066    if 'SASD' in histName:
2067        rho = [0.,0.]
2068        anomrho = [0.,0.]
2069        mu = 0.
2070        subSizer = wx.FlexGridSizer(0,4,5,5)
2071        Substances = G2frame.PatternTree.GetItemPyData(
2072            G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Substances'))
2073        for id,item in enumerate(data['Materials']):
2074            subSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Material: '),0,WACV)
2075            matsel = wx.ComboBox(G2frame.dataDisplay,value=item['Name'],choices=Substances['Substances'].keys(),
2076                style=wx.CB_READONLY|wx.CB_DROPDOWN)
2077            Info[matsel.GetId()] = [id,'Name']
2078            matsel.Bind(wx.EVT_COMBOBOX,OnMaterial)       
2079            subSizer.Add(matsel,0,WACV)
2080            subSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Volume fraction: '),0,WACV)
2081            volfrac = wx.TextCtrl(G2frame.dataDisplay,value=str('%.3f'%(item['VolFrac'])),style=wx.TE_PROCESS_ENTER)
2082            Info[volfrac.GetId()] = [id,'VolFrac']
2083            volfrac.Bind(wx.EVT_TEXT_ENTER,OnMaterial)
2084            volfrac.Bind(wx.EVT_KILL_FOCUS,OnMaterial)
2085            subSizer.Add(volfrac,0,WACV)
2086            material = Substances['Substances'][item['Name']]
2087            mu += item['VolFrac']*material.get('XAbsorption',0.)
2088            rho[id] = material['Scatt density']
2089            anomrho[id] = material.get('XAnom density',0.)
2090        data['Contrast'] = [(rho[1]-rho[0])**2,(anomrho[1]-anomrho[0])**2]
2091        mainSizer.Add(subSizer,0)
2092        conSizer = wx.BoxSizer(wx.HORIZONTAL)
2093        conSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Contrast: %10.2f '%(data['Contrast'][0])),0,WACV)
2094        conSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Anom. Contrast: %10.2f '%(data['Contrast'][1])),0,WACV)
2095        mut =  mu*data['Thick']
2096        conSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Transmission (calc): %10.3f  '%(np.exp(-mut))),0,WACV)
2097        mainSizer.Add(conSizer,0)
2098   
2099    mainSizer.Layout()   
2100    G2frame.dataDisplay.SetSizer(mainSizer)
2101    Size = mainSizer.Fit(G2frame.dataFrame)
2102    G2frame.dataDisplay.SetSize(Size)
2103    G2frame.dataFrame.setSizePosLeft(Size)
2104               
2105################################################################################
2106#####  Indexing Peaks
2107################################################################################           
2108       
2109def UpdateIndexPeaksGrid(G2frame, data):
2110    '''respond to selection of PWDR Index Peak List data
2111    tree item.
2112    '''
2113    bravaisSymb = ['Fm3m','Im3m','Pm3m','R3-H','P6/mmm','I4/mmm',
2114        'P4/mmm','Fmmm','Immm','Cmmm','Pmmm','C2/m','P2/m','P1']
2115    IndexId = G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Index Peak List')
2116    Inst = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Instrument Parameters'))[0]
2117
2118    def RefreshIndexPeaksGrid(event):
2119        r,c =  event.GetRow(),event.GetCol()
2120        peaks = G2frame.IndexPeaksTable.GetData()
2121        if c == 2:
2122            if peaks[r][c]:
2123                peaks[r][c] = False
2124            else:
2125                peaks[r][c] = True
2126            G2frame.IndexPeaksTable.SetData(peaks)
2127            G2frame.PatternTree.SetItemPyData(IndexId,[peaks,data[1]])
2128            G2frame.dataDisplay.ForceRefresh()
2129            if 'PKS' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
2130                G2plt.PlotPowderLines(G2frame)
2131            else:
2132                G2plt.PlotPatterns(G2frame,plotType='PWDR')
2133           
2134    def OnReload(event):
2135        peaks = []
2136        sigs = []
2137        Peaks = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Peak List'))
2138        for ip,peak in enumerate(Peaks['peaks']):
2139            dsp = G2lat.Pos2dsp(Inst,peak[0])
2140            peaks.append([peak[0],peak[2],True,False,0,0,0,dsp,0.0])    #SS?
2141            try:
2142                sig = Peaks['sigDict']['pos'+str(ip)]
2143            except KeyError:
2144                sig = 0.
2145            sigs.append(sig)
2146        data = [peaks,sigs]
2147        G2frame.PatternTree.SetItemPyData(IndexId,data)
2148        UpdateIndexPeaksGrid(G2frame,data)
2149       
2150    def KeyEditPickGrid(event):
2151        colList = G2frame.dataDisplay.GetSelectedCols()
2152        rowList = G2frame.dataDisplay.GetSelectedRows()
2153        data = G2frame.PatternTree.GetItemPyData(IndexId)
2154        if event.GetKeyCode() == wx.WXK_RETURN:
2155            event.Skip(True)
2156        elif event.GetKeyCode() == wx.WXK_CONTROL:
2157            event.Skip(True)
2158        elif event.GetKeyCode() == wx.WXK_SHIFT:
2159            event.Skip(True)
2160        elif colList:
2161            G2frame.dataDisplay.ClearSelection()
2162            key = event.GetKeyCode()
2163            for col in colList:
2164                if G2frame.IndexPeaksTable.GetColLabelValue(col) in ['use',]:
2165                    if key == 89: #'Y'
2166                        for row in range(G2frame.IndexPeaksTable.GetNumberRows()): data[0][row][col]=True
2167                    elif key == 78:  #'N'
2168                        for row in range(G2frame.IndexPeaksTable.GetNumberRows()): data[0][row][col]=False
2169           
2170    if G2frame.dataDisplay:
2171        G2frame.dataFrame.Clear()
2172    if not G2frame.dataFrame.GetStatusBar():
2173        Status = G2frame.dataFrame.CreateStatusBar()
2174    if 'PWD' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
2175        G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.IndPeaksMenu)
2176        G2frame.Bind(wx.EVT_MENU, OnReload, id=G2gd.wxID_INDXRELOAD)
2177    G2frame.dataFrame.IndexPeaks.Enable(False)
2178    G2frame.IndexPeaksTable = []
2179    if len(data[0]):
2180        G2frame.dataFrame.IndexPeaks.Enable(True)
2181        Unit = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Unit Cells List'))
2182        if Unit:
2183            if len(Unit) == 4:  #patch
2184                Unit.append({})
2185            controls,bravais,cellist,dmin,ssopt = Unit
2186            G2frame.HKL = []
2187            if ssopt.get('Use',False):
2188                cell = controls[6:12]
2189                A = G2lat.cell2A(cell)
2190                ibrav = bravaisSymb.index(controls[5])
2191                spc = controls[13]
2192                SGData = G2spc.SpcGroup(spc)[1]
2193                SSGData = G2spc.SSpcGroup(SGData,ssopt['ssSymb'])[1]
2194                Vec = ssopt['ModVec']
2195                maxH = ssopt['maxH']
2196                G2frame.HKL = G2pwd.getHKLMpeak(dmin,Inst,SGData,SSGData,Vec,maxH,A)
2197                data[0] = G2indx.IndexSSPeaks(data[0],G2frame.HKL)[1]
2198            else:        #select cell from table - no SS
2199                for i,cell in enumerate(cellist):
2200                    if cell[-2]:
2201                        ibrav = cell[2]
2202                        A = G2lat.cell2A(cell[3:9])
2203                        G2frame.HKL = G2lat.GenHBravais(dmin,ibrav,A)
2204                        for hkl in G2frame.HKL:
2205                            hkl.insert(4,G2lat.Dsp2pos(Inst,hkl[3]))
2206                        data[0] = G2indx.IndexPeaks(data[0],G2frame.HKL)[1]
2207                        break
2208    rowLabels = []
2209    for i in range(len(data[0])): rowLabels.append(str(i+1))
2210    colLabels = ['position','intensity','use','indexed','h','k','l','d-obs','d-calc']
2211    Types = [wg.GRID_VALUE_FLOAT+':10,4',wg.GRID_VALUE_FLOAT+':10,1',]+2*[wg.GRID_VALUE_BOOL,]+ \
2212        3*[wg.GRID_VALUE_LONG,]+2*[wg.GRID_VALUE_FLOAT+':10,5',]
2213    if len(data[0]) and len(data[0][0]) > 9:
2214        colLabels = ['position','intensity','use','indexed','h','k','l','m','d-obs','d-calc']
2215        Types = [wg.GRID_VALUE_FLOAT+':10,4',wg.GRID_VALUE_FLOAT+':10,1',]+2*[wg.GRID_VALUE_BOOL,]+ \
2216            4*[wg.GRID_VALUE_LONG,]+2*[wg.GRID_VALUE_FLOAT+':10,5',]
2217    G2frame.PatternTree.SetItemPyData(IndexId,data)
2218    G2frame.IndexPeaksTable = G2gd.Table(data[0],rowLabels=rowLabels,colLabels=colLabels,types=Types)
2219    G2frame.dataFrame.SetLabel('Index Peak List')
2220    G2frame.dataDisplay = G2gd.GSGrid(parent=G2frame.dataFrame)               
2221    G2frame.dataDisplay.SetTable(G2frame.IndexPeaksTable, True)
2222    XY = []
2223    Sigs = []
2224    for r in range(G2frame.dataDisplay.GetNumberRows()):
2225        for c in range(G2frame.dataDisplay.GetNumberCols()):
2226            if c == 2:
2227                G2frame.dataDisplay.SetReadOnly(r,c,isReadOnly=False)
2228            else:
2229                G2frame.dataDisplay.SetReadOnly(r,c,isReadOnly=True)
2230        if data[0][r][2] and data[0][r][3]:
2231            XY.append([data[0][r][-1],data[0][r][0]])
2232            try:
2233                sig = data[1][r]
2234            except IndexError:
2235                sig = 0.
2236            Sigs.append(sig)
2237    G2frame.dataDisplay.Bind(wg.EVT_GRID_CELL_LEFT_CLICK, RefreshIndexPeaksGrid)
2238    G2frame.dataDisplay.Bind(wx.EVT_KEY_DOWN, KeyEditPickGrid)                 
2239    G2frame.dataDisplay.SetMargins(0,0)
2240    G2frame.dataDisplay.AutoSizeColumns(False)
2241    G2frame.dataFrame.setSizePosLeft([490,300])
2242    if len(XY):
2243        XY = np.array(XY)
2244        G2plt.PlotCalib(G2frame,Inst,XY,Sigs,newPlot=True)
2245    G2frame.dataFrame.SendSizeEvent()
2246     
2247################################################################################
2248#####  Unit cells
2249################################################################################           
2250       
2251def UpdateUnitCellsGrid(G2frame, data):
2252    '''respond to selection of PWDR Unit Cells data tree item.
2253    '''
2254    UnitCellsId = G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Unit Cells List')
2255    SPGlist = G2spc.spglist
2256    bravaisSymb = ['Fm3m','Im3m','Pm3m','R3-H','P6/mmm','I4/mmm',
2257        'P4/mmm','Fmmm','Immm','Cmmm','Pmmm','C2/m','P2/m','P1']
2258    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',
2259        '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']
2260    Inst = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Instrument Parameters'))[0]
2261    if 'C' in Inst['Type'][0] or 'PKS' in Inst['Type'][0]:
2262        wave = G2mth.getWave(Inst)
2263    else:
2264        difC = Inst['difC'][1]
2265   
2266    def SetLattice(controls):
2267        ibrav = bravaisSymb.index(controls[5])
2268        if ibrav in [0,1,2]:
2269            controls[7] = controls[8] = controls[6]
2270            controls[9] = controls[10] = controls[11] = 90.
2271        elif ibrav in [3,4,5,6]:
2272            controls[7] = controls[6]
2273            controls[9] = controls[10] = controls[11] = 90.
2274            if ibrav in [3,4]:
2275                controls[11] = 120.
2276        elif ibrav in [7,8,9,10]:
2277            controls[9] = controls[10] = controls[11] = 90.
2278        elif ibrav in [11,12]:
2279            controls[9] = controls[11] = 90.  # b unique
2280        if len(controls) < 13: controls.append(0)
2281        controls[12] = G2lat.calc_V(G2lat.cell2A(controls[6:12]))
2282        return ibrav
2283       
2284    def OnNcNo(event):
2285        controls[2] = NcNo.GetValue()
2286       
2287    def OnIfX20(event):
2288        G2frame.ifX20 = x20.GetValue()
2289       
2290    def OnStartVol(event):
2291        try:
2292            stVol = int(float(startVol.GetValue()))
2293            if stVol < 25:
2294                raise ValueError
2295        except ValueError:
2296            stVol = 25
2297        controls[3] = stVol
2298        startVol.SetValue("%d"%(stVol))
2299       
2300    def OnBravais(event):
2301        Obj = event.GetEventObject()
2302        bravais[bravList.index(Obj.GetId())] = Obj.GetValue()
2303       
2304    def OnZero(event):
2305        try:
2306            Zero = min(5.0,max(-5.0,float(zero.GetValue())))
2307        except ValueError:
2308            Zero = 0.0
2309        controls[1] = Zero
2310        zero.SetValue("%.4f"%(Zero))
2311       
2312    def OnZeroVar(event):
2313        controls[0] = zeroVar.GetValue()
2314       
2315    def OnSSopt(event):
2316        if controls[5] in ['Fm3m','Im3m','Pm3m']:
2317            SSopt.SetValue(False)
2318            G2frame.ErrorDialog('Cubic lattice', 'Superlattice not allowed for a cubic lattice')
2319            return
2320        ssopt['Use'] = SSopt.GetValue()
2321        if 'ssSymb' not in ssopt:
2322            ssopt.update({'ssSymb':'(abg)','ModVec':[0.1,0.1,0.1],'maxH':1})
2323        wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)
2324       
2325    def OnSelMG(event):
2326        ssopt['ssSymb'] = selMG.GetValue()
2327        Vec = ssopt['ModVec']
2328        modS = G2spc.splitSSsym(ssopt['ssSymb'])[0]
2329        ssopt['ModVec'] = G2spc.SSGModCheck(Vec,modS)[0]
2330        print ' Selecting: ',controls[13],ssopt['ssSymb'], 'maxH:',ssopt['maxH']
2331        OnHklShow(event)
2332        wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)
2333       
2334    def OnModVal(event):
2335        Obj = event.GetEventObject()
2336        ObjId = Obj.GetId()
2337        Id = Indx[ObjId]
2338        try:
2339            value = min(1.0,max(0.,float(Obj.GetValue())))
2340        except ValueError:
2341            value = ssopt['ModVec'][Id]
2342        Obj.SetValue('%.4f'%(value))
2343        ssopt['ModVec'][Id] = value
2344        OnHklShow(event)
2345       
2346    def OnMoveMod(event):
2347        Obj = event.GetEventObject()
2348        ObjId = Obj.GetId()
2349        Id,valObj = Indx[ObjId]
2350        move = Obj.GetValue()*0.0005
2351        Obj.SetValue(0)
2352        value = min(1.0,max(.0,float(valObj.GetValue())+move))
2353        valObj.SetValue('%.4f'%(value)) 
2354        ssopt['ModVec'][Id] = value
2355        OnHklShow(event)
2356       
2357    def OnMaxMH(event):
2358        ssopt['maxH'] = int(maxMH.GetValue())
2359        print ' Selecting: ',controls[13],ssopt['ssSymb'], 'maxH:',ssopt['maxH']
2360        OnHklShow(event)
2361       
2362    def OnFindMV(event):
2363        Peaks = np.copy(peaks[0])
2364        print ' Trying: ',controls[13],ssopt['ssSymb'], 'maxH:',ssopt['maxH']
2365        dlg = wx.ProgressDialog('Elapsed time','Modulation vector search',
2366            style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE)
2367        try:
2368            ssopt['ModVec'] = G2indx.findMV(Peaks,controls,ssopt,Inst,dlg)
2369        finally:
2370            dlg.Destroy()
2371        OnHklShow(event)
2372        wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)
2373       
2374    def OnBravSel(event):
2375        brav = bravSel.GetString(bravSel.GetSelection())
2376        controls[5] = brav
2377        controls[13] = SPGlist[brav][0]       
2378        wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)
2379       
2380    def OnSpcSel(event):
2381        controls[13] = spcSel.GetString(spcSel.GetSelection())
2382        G2frame.dataFrame.RefineCell.Enable(True)
2383        OnHklShow(event)
2384       
2385    def SetCellValue(Obj,ObjId,value):
2386        ibrav = bravaisSymb.index(controls[5])
2387        if ibrav in [0,1,2]:
2388            controls[6] = controls[7] = controls[8] = value
2389            controls[9] = controls[10] = controls[11] = 90.0
2390            Obj.SetValue("%.5f"%(controls[6]))
2391        elif ibrav in [3,4,5,6]:
2392            if ObjId == 0:
2393                controls[6] = controls[7] = value
2394                Obj.SetValue("%.5f"%(controls[6]))
2395            else:
2396                controls[8] = value
2397                Obj.SetValue("%.5f"%(controls[8]))
2398            controls[9] = controls[10] = controls[11] = 90.0
2399            if ibrav in [3,4]:
2400                controls[11] = 120.
2401        elif ibrav in [7,8,9,10]:
2402            controls[6+ObjId] = value
2403            Obj.SetValue("%.5f"%(controls[6+ObjId]))
2404            controls[9] = controls[10] = controls[11] = 90.0
2405        elif ibrav in [11,12]:
2406            controls[9] = controls[11] = 90.0
2407            if ObjId != 3:
2408                controls[6+ObjId] = value
2409                Obj.SetValue("%.5f"%(controls[6+ObjId]))
2410            else:
2411                controls[10] = value
2412                Obj.SetValue("%.3f"%(controls[10]))
2413        else:
2414            controls[6+ObjId] = value
2415            if ObjId < 3:
2416                Obj.SetValue("%.5f"%(controls[6+ObjId]))
2417            else:
2418                Obj.SetValue("%.3f"%(controls[6+ObjId]))
2419        controls[12] = G2lat.calc_V(G2lat.cell2A(controls[6:12]))
2420        volVal.SetValue("%.3f"%(controls[12]))
2421       
2422    def OnMoveCell(event):
2423        Obj = event.GetEventObject()
2424        ObjId = cellList.index(Obj.GetId())
2425        valObj = valDict[Obj.GetId()]
2426        if ObjId/2 < 3:
2427            move = Obj.GetValue()*0.01
2428        else:
2429            move = Obj.GetValue()*0.1
2430        Obj.SetValue(0)
2431        value = float(valObj.GetValue())+move 
2432        SetCellValue(valObj,ObjId/2,value)
2433        OnHklShow(event)
2434       
2435    def OnCellChange(event):
2436        Obj = event.GetEventObject()
2437        ObjId = cellList.index(Obj.GetId())
2438        try:
2439            value = max(1.0,float(Obj.GetValue()))
2440        except ValueError:
2441            if ObjId/2 < 3:               #bad cell edge - reset
2442                value = controls[6+ObjId/2]
2443            else:                       #bad angle
2444                value = 90.
2445        SetCellValue(Obj,ObjId/2,value)
2446       
2447    def OnHklShow(event):
2448        PatternId = G2frame.PatternId
2449        PickId = G2frame.PickId   
2450        peaks = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Index Peak List'))
2451        limits = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Limits'))[1]
2452        controls,bravais,cells,dmin,ssopt = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Unit Cells List'))
2453        cell = controls[6:12]
2454        A = G2lat.cell2A(cell)
2455        ibrav = bravaisSymb.index(controls[5])
2456        spc = controls[13]
2457        SGData = G2spc.SpcGroup(spc)[1]
2458        if 'C' in Inst['Type'][0]:
2459            dmin = G2lat.Pos2dsp(Inst,limits[1])
2460        else:   #TOF - use other limit!
2461            dmin = G2lat.Pos2dsp(Inst,limits[0])
2462        if ssopt.get('Use',False):
2463            dmin = peaks[0][-1][8]
2464            SSGData = G2spc.SSpcGroup(SGData,ssopt['ssSymb'])[1]
2465            Vec = ssopt['ModVec']
2466            maxH = ssopt['maxH']
2467            G2frame.HKL = G2pwd.getHKLMpeak(dmin,Inst,SGData,SSGData,Vec,maxH,A)
2468            peaks = [G2indx.IndexSSPeaks(peaks[0],G2frame.HKL)[1],peaks[1]]   #keep esds from peak fit
2469            M20,X20 = G2indx.calc_M20SS(peaks[0],G2frame.HKL)
2470        else:
2471            if len(peaks[0]):
2472                dmin = peaks[0][-1][7]
2473                G2frame.HKL = G2pwd.getHKLpeak(dmin,SGData,A,Inst)
2474                peaks = [G2indx.IndexPeaks(peaks[0],G2frame.HKL)[1],peaks[1]]   #keep esds from peak fit
2475                M20,X20 = G2indx.calc_M20(peaks[0],G2frame.HKL)
2476            else:
2477                M20 = X20 = 0.
2478                G2frame.HKL = G2pwd.getHKLpeak(dmin,SGData,A,Inst)
2479        if len(G2frame.HKL):
2480            print ' new M20,X20: %.2f %d fraction found: %.3f'%(M20,X20,float(len(peaks[0]))/len(G2frame.HKL))
2481        G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Index Peak List'),peaks)
2482        if 'PKS' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
2483            G2plt.PlotPowderLines(G2frame)
2484        else:
2485            G2plt.PlotPatterns(G2frame)
2486           
2487    def OnSortCells(event):
2488        controls,bravais,cells,dmin,ssopt = G2frame.PatternTree.GetItemPyData(UnitCellsId)
2489        c =  event.GetCol()
2490        if colLabels[c] == 'M20':
2491            cells = G2indx.sortM20(cells)
2492        elif colLabels[c] in ['X20','Bravais','a','b','c','alpha','beta','gamma','Volume']:
2493            if c == 1:
2494                c += 1  #X20 before Use
2495            cells = G2indx.sortCells(cells,c-1)     #an extra column (Use) not in cells
2496        else:
2497            return
2498        data = [controls,bravais,cells,dmin,ssopt]
2499        G2frame.PatternTree.SetItemPyData(UnitCellsId,data)
2500        wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)
2501       
2502    def CopyUnitCell(event):
2503        controls,bravais,cells,dmin,ssopt = G2frame.PatternTree.GetItemPyData(UnitCellsId)
2504        for Cell in cells:
2505            if Cell[-2]:
2506                break
2507        cell = Cell[2:9]
2508        controls[4] = 1
2509        controls[5] = bravaisSymb[cell[0]]
2510        controls[6:12] = cell[1:8]
2511        controls[12] = G2lat.calc_V(G2lat.cell2A(controls[6:12]))
2512        controls[13] = spaceGroups[bravaisSymb.index(controls[5])]
2513        G2frame.PatternTree.SetItemPyData(UnitCellsId,[controls,bravais,cells,dmin,ssopt])
2514        G2frame.dataFrame.RefineCell.Enable(True)
2515        wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)       
2516               
2517    def RefineCell(event):
2518       
2519        def cellPrint(ibrav,A):
2520            cell = G2lat.A2cell(A)
2521            Vol = G2lat.calc_V(A)
2522            if ibrav in [0,1,2]:
2523                print " %s%10.6f" % ('a =',cell[0])
2524            elif ibrav in [3,4,5,6]:
2525                print " %s%10.6f %s%10.6f %s%12.3f" % ('a =',cell[0],' c =',cell[2],' volume =',Vol)
2526            elif ibrav in [7,8,9,10]:
2527                print " %s%10.6f %s%10.6f %s%10.6f %s%12.3f" % ('a =',cell[0],'b =',cell[1],'c =',cell[2],' volume =',Vol)
2528            elif ibrav in [11,12]:
2529                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)
2530            else:
2531                print " %s%10.6f %s%10.6f %s%10.6f" % ('a =',cell[0],'b =',cell[1],'c =',cell[2])
2532                print " %s%8.3f %s%8.3f %s%8.3f %s%12.3f" % ('alpha =',cell[3],'beta =',cell[4],'gamma =',cell[5],' volume =',Vol)
2533               
2534        def vecPrint(Vec):
2535            print ' %s %10.5f %10.5f %10.5f'%('Modulation vector:',Vec[0],Vec[1],Vec[2])
2536             
2537        PatternId = G2frame.PatternId
2538        PickId = G2frame.PickId   
2539        peaks = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Index Peak List'))
2540        if not len(peaks[0]):
2541            G2frame.ErrorDialog('No peaks!', 'Nothing to refine!')
2542            return       
2543        print ' Refine cell'
2544        controls,bravais,cells,dmin,ssopt = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Unit Cells List'))
2545        cell = controls[6:12]
2546        A = G2lat.cell2A(cell)
2547        ibrav = bravaisSymb.index(controls[5])
2548        SGData = G2spc.SpcGroup(controls[13])[1]
2549        dmin = G2indx.getDmin(peaks[0])-0.005
2550        if 'C' in Inst['Type'][0]:
2551            if ssopt.get('Use',False):
2552                vecFlags = [True if x in ssopt['ssSymb'] else False for x in ['a','b','g']]
2553                SSGData = G2spc.SSpcGroup(SGData,ssopt['ssSymb'])[1]
2554                G2frame.HKL = G2pwd.getHKLMpeak(dmin,Inst,SGData,SSGData,ssopt['ModVec'],ssopt['maxH'],A)
2555                peaks = [G2indx.IndexSSPeaks(peaks[0],G2frame.HKL)[1],peaks[1]]   #put peak fit esds back in peaks
2556                Lhkl,M20,X20,Aref,Vec,Zero = \
2557                    G2indx.refinePeaksZSS(peaks[0],wave,Inst,SGData,SSGData,ssopt['maxH'],ibrav,A,ssopt['ModVec'],vecFlags,controls[1],controls[0])
2558            else:
2559                G2frame.HKL = G2pwd.getHKLpeak(dmin,SGData,A,Inst)
2560                peaks = [G2indx.IndexPeaks(peaks[0],G2frame.HKL)[1],peaks[1]]   #put peak fit esds back in peaks
2561                Lhkl,M20,X20,Aref,Zero = G2indx.refinePeaksZ(peaks[0],wave,ibrav,A,controls[1],controls[0])
2562        else:   #'T'OF - doesn't seem to work
2563            G2frame.HKL = G2pwd.getHKLpeak(dmin,SGData,A,Inst)
2564            peaks = [G2indx.IndexPeaks(peaks[0],G2frame.HKL)[1],peaks[1]]   #put peak fit esds back in peaks
2565            Lhkl,M20,X20,Aref,Zero = G2indx.refinePeaksT(peaks[0],difC,ibrav,A,controls[1],controls[0])           
2566        controls[1] = Zero
2567        controls[6:12] = G2lat.A2cell(Aref)
2568        controls[12] = G2lat.calc_V(Aref)
2569        cells = G2frame.PatternTree.GetItemPyData(UnitCellsId)[2]
2570        for cell in cells:
2571            cell[-2] = False
2572        cells.insert(0,[M20,X20,ibrav]+controls[6:13]+[True,False])
2573        if ssopt.get('Use',False):
2574            ssopt['ModVec'] = Vec
2575            G2frame.HKL = G2pwd.getHKLMpeak(dmin,Inst,SGData,SSGData,ssopt['ModVec'],ssopt['maxH'],A)
2576        else:
2577            G2frame.HKL = G2pwd.getHKLpeak(dmin,SGData,A,Inst)
2578        data = [controls,bravais,cells,dmin,ssopt]
2579        G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Unit Cells List'),data)
2580        print " %s%10.3f" % ('refinement M20 = ',M20)
2581        print ' unindexed lines = ',X20
2582        cellPrint(ibrav,Aref)
2583        ip = 4
2584        if ssopt.get('Use',False):
2585            vecPrint(Vec)
2586            ip = 5
2587        for hkl in G2frame.HKL:
2588            hkl[ip] = G2lat.Dsp2pos(Inst,hkl[ip-1])+controls[1]
2589        if 'PKS' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
2590            G2plt.PlotPowderLines(G2frame)
2591        else:
2592            G2plt.PlotPatterns(G2frame)
2593        wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)
2594       
2595    def IndexPeaks(event):
2596        PatternId = G2frame.PatternId   
2597        print 'Peak Indexing'
2598        keepcells = []
2599        try:
2600            controls,bravais,cells,dmin,ssopt = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Unit Cells List'))
2601            for cell in cells:
2602                if cell[11]:
2603                    cell[10] = False    #clear selection flag on keepers
2604                    keepcells.append(cell)
2605        except IndexError:
2606            pass
2607        except ValueError:
2608            G2frame.ErrorDialog('Error','Need to set controls in Unit Cell List first')
2609            return
2610        if ssopt.get('Use',False):
2611            G2frame.ErrorDialog('Super lattice error','Indexing not available for super lattices')
2612            return
2613        if True not in bravais:
2614            G2frame.ErrorDialog('Error','No Bravais lattices selected')
2615            return
2616        if not len(peaks[0]):
2617            G2frame.ErrorDialog('Error','Index Peak List is empty')
2618            return
2619        if len(peaks[0][0]) > 9:
2620            G2frame.ErrorDialog('Error','You need to reload Index Peaks List first')
2621            return
2622        G2frame.dataFrame.CopyCell.Enable(False)
2623        G2frame.dataFrame.RefineCell.Enable(False)
2624        OK,dmin,newcells = G2indx.DoIndexPeaks(peaks[0],controls,bravais,G2frame.ifX20)
2625        cells = keepcells+newcells
2626        cells = G2indx.sortM20(cells)
2627        if OK:
2628            cells[0][10] = True         #select best M20
2629            data = [controls,bravais,cells,dmin,ssopt]
2630            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Unit Cells List'),data)
2631            bestCell = cells[0]
2632            if bestCell[0] > 10.:
2633                G2frame.HKL = G2lat.GenHBravais(dmin,bestCell[2],G2lat.cell2A(bestCell[3:9]))
2634                for hkl in G2frame.HKL:
2635                    hkl.insert(4,G2lat.Dsp2pos(Inst,hkl[3])+controls[1])
2636                if 'PKS' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
2637                    G2plt.PlotPowderLines(G2frame)
2638                else:
2639                    G2plt.PlotPatterns(G2frame)
2640            G2frame.dataFrame.CopyCell.Enable(True)
2641            G2frame.dataFrame.IndexPeaks.Enable(True)
2642            G2frame.dataFrame.MakeNewPhase.Enable(True)
2643            G2frame.ifX20 = True
2644            wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)
2645               
2646    def RefreshUnitCellsGrid(event):
2647        data = G2frame.PatternTree.GetItemPyData(UnitCellsId)
2648        cells,dmin = data[2:4]
2649        r,c =  event.GetRow(),event.GetCol()
2650        if cells:
2651            if c == 2:
2652                for i in range(len(cells)):
2653                    cells[i][-2] = False
2654                    UnitCellsTable.SetValue(i,c,False)
2655                UnitCellsTable.SetValue(r,c,True)
2656                gridDisplay.Refresh()
2657                cells[r][-2] = True
2658                ibrav = cells[r][2]
2659                A = G2lat.cell2A(cells[r][3:9])
2660                G2frame.HKL = G2lat.GenHBravais(dmin,ibrav,A)
2661                for hkl in G2frame.HKL:
2662                    hkl.insert(4,G2lat.Dsp2pos(Inst,hkl[3])+controls[1])
2663                if 'PKS' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
2664                    G2plt.PlotPowderLines(G2frame)
2665                else:
2666                    G2plt.PlotPatterns(G2frame)
2667            elif c == 11:
2668                if UnitCellsTable.GetValue(r,c):
2669                    UnitCellsTable.SetValue(r,c,False)
2670                    cells[r][c] = False
2671                else:
2672                    cells[r][c] = True
2673                    UnitCellsTable.SetValue(r,c,True)
2674                gridDisplay.ForceRefresh()
2675            G2frame.PatternTree.SetItemPyData(UnitCellsId,data)
2676       
2677    def MakeNewPhase(event):
2678        if not G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Phases'):
2679            sub = G2frame.PatternTree.AppendItem(parent=G2frame.root,text='Phases')
2680        else:
2681            sub = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Phases')
2682        PhaseName = ''
2683        dlg = wx.TextEntryDialog(None,'Enter a name for this phase','Phase Name Entry','New phase',
2684            style=wx.OK)
2685        try:
2686            if dlg.ShowModal() == wx.ID_OK:
2687                PhaseName = dlg.GetValue()
2688                cells = G2frame.PatternTree.GetItemPyData(UnitCellsId)[2]
2689                for Cell in cells:
2690                    if Cell[-2]:
2691                        break
2692                cell = Cell[2:10]       
2693                sub = G2frame.PatternTree.AppendItem(parent=sub,text=PhaseName)
2694                E,SGData = G2spc.SpcGroup(controls[13])
2695                G2frame.PatternTree.SetItemPyData(sub, \
2696                    G2IO.SetNewPhase(Name=PhaseName,SGData=SGData,cell=cell[1:],Super=ssopt))
2697                Status.SetStatusText('Change space group from '+str(controls[13])+' if needed')
2698        finally:
2699            dlg.Destroy()
2700           
2701    if G2frame.dataDisplay:
2702        G2frame.dataFrame.DestroyChildren()
2703    G2frame.dataDisplay = wxscroll.ScrolledPanel(G2frame.dataFrame)
2704    G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.IndexMenu)
2705    if not G2frame.dataFrame.GetStatusBar():
2706        Status = G2frame.dataFrame.CreateStatusBar()
2707    G2frame.Bind(wx.EVT_MENU, IndexPeaks, id=G2gd.wxID_INDEXPEAKS)
2708    G2frame.Bind(wx.EVT_MENU, CopyUnitCell, id=G2gd.wxID_COPYCELL)
2709    G2frame.Bind(wx.EVT_MENU, RefineCell, id=G2gd.wxID_REFINECELL)
2710    G2frame.Bind(wx.EVT_MENU, MakeNewPhase, id=G2gd.wxID_MAKENEWPHASE)   
2711    controls,bravais,cells,dmin,ssopt = data
2712    if len(controls) < 13:              #add cell volume if missing
2713        controls.append(G2lat.calc_V(G2lat.cell2A(controls[6:12])))
2714    if len(controls) < 14:              #add space gropu used in indexing
2715        controls.append(spaceGroups[bravaisSymb.index(controls[5])])
2716    G2frame.PatternTree.SetItemPyData(UnitCellsId,data)            #update with volume
2717    bravaisNames = ['Cubic-F','Cubic-I','Cubic-P','Trigonal-R','Trigonal/Hexagonal-P',
2718        'Tetragonal-I','Tetragonal-P','Orthorhombic-F','Orthorhombic-I','Orthorhombic-C',
2719        'Orthorhombic-P','Monoclinic-C','Monoclinic-P','Triclinic']
2720    cellGUIlist = [[[0,1,2],4,zip([" Unit cell: a = "," Vol = "],["%.5f","%.3f"],[True,False],[0,0])],
2721    [[3,4,5,6],6,zip([" Unit cell: a = "," c = "," Vol = "],["%.5f","%.5f","%.3f"],[True,True,False],[0,2,0])],
2722    [[7,8,9,10],8,zip([" Unit cell: a = "," b = "," c = "," Vol = "],["%.5f","%.5f","%.5f","%.3f"],
2723        [True,True,True,False],[0,1,2,0])],
2724    [[11,12],10,zip([" Unit cell: a = "," b = "," c = "," beta = "," Vol = "],
2725        ["%.5f","%.5f","%.5f","%.3f","%.3f"],[True,True,True,True,False],[0,1,2,4,0])],
2726    [[13,],8,zip([" Unit cell: a = "," b = "," c = "," Vol = "," alpha = "," beta = "," gamma = "],
2727        ["%.5f","%.5f","%.5f","%.3f","%.3f","%.3f","%.3f"],
2728        [True,True,True,False,True,True,True],[0,1,2,0,3,4,5])]]
2729   
2730    G2frame.dataFrame.SetLabel('Unit Cells List')
2731    G2frame.dataFrame.IndexPeaks.Enable(False)
2732    peaks = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Index Peak List'))
2733    if peaks:
2734        G2frame.dataFrame.IndexPeaks.Enable(True)
2735    G2frame.dataFrame.RefineCell.Enable(False)
2736    if controls[12] > 1.0:                               #if a "real" volume (i.e. not default)
2737        G2frame.dataFrame.RefineCell.Enable(True)   
2738    G2frame.dataFrame.CopyCell.Enable(False)
2739    G2frame.dataFrame.MakeNewPhase.Enable(False)       
2740    if cells:
2741        G2frame.dataFrame.CopyCell.Enable(True)
2742        G2frame.dataFrame.MakeNewPhase.Enable(True)       
2743    mainSizer = wx.BoxSizer(wx.VERTICAL)
2744    mainSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Indexing controls: '),0,WACV)
2745    mainSizer.Add((5,5),0)
2746    littleSizer = wx.FlexGridSizer(0,5,5,5)
2747    littleSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Max Nc/Nobs '),0,WACV)
2748    NcNo = wx.SpinCtrl(G2frame.dataDisplay)
2749    NcNo.SetRange(2,6)
2750    NcNo.SetValue(controls[2])
2751    NcNo.Bind(wx.EVT_SPINCTRL,OnNcNo)
2752    littleSizer.Add(NcNo,0,WACV)
2753    littleSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Start Volume '),0,WACV)
2754    startVol = wx.TextCtrl(G2frame.dataDisplay,value=str('%d'%(controls[3])),style=wx.TE_PROCESS_ENTER)
2755    startVol.Bind(wx.EVT_TEXT_ENTER,OnStartVol)
2756    startVol.Bind(wx.EVT_KILL_FOCUS,OnStartVol)
2757    littleSizer.Add(startVol,0,WACV)
2758    x20 = wx.CheckBox(G2frame.dataDisplay,label='Use M20/(X20+1)?')
2759    x20.SetValue(G2frame.ifX20)
2760    x20.Bind(wx.EVT_CHECKBOX,OnIfX20)
2761    littleSizer.Add(x20,0,WACV)
2762    mainSizer.Add(littleSizer,0)
2763    mainSizer.Add((5,5),0)
2764    mainSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Select Bravais Lattices for indexing: '),
2765        0,WACV)
2766    mainSizer.Add((5,5),0)
2767    littleSizer = wx.FlexGridSizer(0,7,5,5)
2768    bravList = []
2769    bravs = zip(bravais,bravaisNames)
2770    for brav,bravName in bravs:
2771        bravCk = wx.CheckBox(G2frame.dataDisplay,label=bravName)
2772        bravList.append(bravCk.GetId())
2773        bravCk.SetValue(brav)
2774        bravCk.Bind(wx.EVT_CHECKBOX,OnBravais)
2775        littleSizer.Add(bravCk,0,WACV)
2776    mainSizer.Add(littleSizer,0)
2777    mainSizer.Add((5,5),0)
2778   
2779    mainSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Cell Refinement: '),0,WACV)
2780    mainSizer.Add((5,5),0)
2781    littleSizer = wx.BoxSizer(wx.HORIZONTAL)
2782    littleSizer.Add(wx.StaticText(G2frame.dataDisplay,label=" Bravais lattice "),0,WACV)
2783    bravSel = wx.Choice(G2frame.dataDisplay,choices=bravaisSymb)
2784    bravSel.SetSelection(bravaisSymb.index(controls[5]))
2785    bravSel.Bind(wx.EVT_CHOICE,OnBravSel)
2786    littleSizer.Add(bravSel,0,WACV)
2787    littleSizer.Add(wx.StaticText(G2frame.dataDisplay,label=" Space group "),0,WACV)
2788    spcSel = wx.Choice(G2frame.dataDisplay,choices=SPGlist[controls[5]])
2789    spcSel.SetSelection(SPGlist[controls[5]].index(controls[13]))
2790    spcSel.Bind(wx.EVT_CHOICE,OnSpcSel)
2791    littleSizer.Add(spcSel,0,WACV)
2792    if ssopt.get('Use',False):        #zero for super lattice doesn't work!
2793        controls[0] = False
2794    else:
2795        littleSizer.Add(wx.StaticText(G2frame.dataDisplay,label=" Zero offset"),0,WACV)
2796        zero = wx.TextCtrl(G2frame.dataDisplay,value="%.4f"%(controls[1]),style=wx.TE_PROCESS_ENTER)
2797        zero.Bind(wx.EVT_TEXT_ENTER,OnZero)
2798        zero.Bind(wx.EVT_KILL_FOCUS,OnZero)
2799        littleSizer.Add(zero,0,WACV)
2800        zeroVar = wx.CheckBox(G2frame.dataDisplay,label="Refine?")
2801        zeroVar.SetValue(controls[0])
2802        zeroVar.Bind(wx.EVT_CHECKBOX,OnZeroVar)
2803        littleSizer.Add(zeroVar,0,WACV)
2804    SSopt = wx.CheckBox(G2frame.dataDisplay,label="Super lattice?")
2805    SSopt.SetValue(ssopt.get('Use',False))
2806    SSopt.Bind(wx.EVT_CHECKBOX,OnSSopt)
2807    littleSizer.Add(SSopt,0,WACV)
2808    hklShow = wx.Button(G2frame.dataDisplay,label="Show hkl positions")
2809    hklShow.Bind(wx.EVT_BUTTON,OnHklShow)
2810    littleSizer.Add(hklShow,0,WACV)
2811    mainSizer.Add(littleSizer,0)
2812   
2813    mainSizer.Add((5,5),0)
2814    ibrav = SetLattice(controls)
2815    for cellGUI in cellGUIlist:
2816        if ibrav in cellGUI[0]:
2817            useGUI = cellGUI
2818    cellList = []
2819    valDict = {}
2820    littleSizer = wx.FlexGridSizer(0,useGUI[1],5,5)
2821    for txt,fmt,ifEdit,Id in useGUI[2]:
2822        littleSizer.Add(wx.StaticText(G2frame.dataDisplay,label=txt),0,WACV)
2823        if ifEdit:          #a,b,c,etc.
2824            cellVal = wx.TextCtrl(G2frame.dataDisplay,value=(fmt%(controls[6+Id])),style=wx.TE_PROCESS_ENTER)
2825            cellVal.Bind(wx.EVT_TEXT_ENTER,OnCellChange)       
2826            cellVal.Bind(wx.EVT_KILL_FOCUS,OnCellChange)
2827            valSizer = wx.BoxSizer(wx.HORIZONTAL)
2828            valSizer.Add(cellVal,0,WACV)
2829            cellSpin = wx.SpinButton(G2frame.dataDisplay,style=wx.SP_VERTICAL,size=wx.Size(20,20))
2830            cellSpin.SetValue(0)
2831            cellSpin.SetRange(-1,1)
2832            cellSpin.Bind(wx.EVT_SPIN, OnMoveCell)
2833            valSizer.Add(cellSpin,0,WACV)
2834            littleSizer.Add(valSizer,0,WACV)
2835            cellList.append(cellVal.GetId())
2836            cellList.append(cellSpin.GetId())
2837            valDict[cellSpin.GetId()] = cellVal
2838        else:               #volume
2839            volVal = wx.TextCtrl(G2frame.dataDisplay,value=(fmt%(controls[12])),style=wx.TE_READONLY)
2840            volVal.SetBackgroundColour(VERY_LIGHT_GREY)
2841            littleSizer.Add(volVal,0,WACV)
2842    mainSizer.Add(littleSizer,0)
2843    if ssopt.get('Use',False):        #super lattice display
2844        indChoice = ['1','2','3','4',]
2845        SpSg = controls[13]
2846        ssChoice = G2spc.ssdict[SpSg]
2847        if ssopt['ssSymb'] not in ssChoice:
2848            ssopt['ssSymb'] = ssChoice[0]
2849        ssSizer = wx.BoxSizer(wx.HORIZONTAL)
2850        ssSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Supersymmetry space group: '+SpSg+' '),0,WACV)
2851        selMG = wx.ComboBox(G2frame.dataDisplay,value=ssopt['ssSymb'],
2852                choices=ssChoice,style=wx.CB_READONLY|wx.CB_DROPDOWN)
2853        selMG.Bind(wx.EVT_COMBOBOX, OnSelMG)
2854        ssSizer.Add(selMG,0,WACV)
2855        ssSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Mod. vector: '),0,WACV)
2856        modS = G2spc.splitSSsym(ssopt['ssSymb'])[0]
2857        ssopt['ModVec'],ifShow = G2spc.SSGModCheck(ssopt['ModVec'],modS)
2858        Indx = {}
2859        for i,[val,show] in enumerate(zip(ssopt['ModVec'],ifShow)):
2860            if show:
2861                valSizer = wx.BoxSizer(wx.HORIZONTAL)
2862                modVal = wx.TextCtrl(G2frame.dataDisplay,value=('%.4f'%(val)),
2863                    size=wx.Size(50,20),style=wx.TE_PROCESS_ENTER)
2864                modVal.Bind(wx.EVT_TEXT_ENTER,OnModVal)       
2865                modVal.Bind(wx.EVT_KILL_FOCUS,OnModVal)
2866                valSizer.Add(modVal,0,WACV)
2867                modSpin = wx.SpinButton(G2frame.dataDisplay,style=wx.SP_VERTICAL,size=wx.Size(20,20))
2868                modSpin.SetValue(0)
2869                modSpin.SetRange(-1,1)
2870                modSpin.Bind(wx.EVT_SPIN, OnMoveMod)
2871                valSizer.Add(modSpin,0,WACV)
2872                ssSizer.Add(valSizer,0,WACV)
2873                Indx[modVal.GetId()] = i
2874                Indx[modSpin.GetId()] = [i,modVal]
2875            else:
2876                modVal = wx.TextCtrl(G2frame.dataDisplay,value=('%.3f'%(val)),
2877                    size=wx.Size(50,20),style=wx.TE_READONLY)
2878                modVal.SetBackgroundColour(VERY_LIGHT_GREY)
2879                ssSizer.Add(modVal,0,WACV)
2880        ssSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Max. M: '),0,WACV)
2881        maxMH = wx.ComboBox(G2frame.dataDisplay,value=str(ssopt['maxH']),
2882            choices=indChoice,style=wx.CB_READONLY|wx.CB_DROPDOWN)
2883        maxMH.Bind(wx.EVT_COMBOBOX, OnMaxMH)
2884        ssSizer.Add(maxMH,0,WACV)
2885        findMV = wx.wx.Button(G2frame.dataDisplay,label="Find mod. vec.?")
2886        findMV.Bind(wx.EVT_BUTTON,OnFindMV)
2887        ssSizer.Add(findMV,0,WACV)
2888        mainSizer.Add(ssSizer,0)
2889
2890    if cells:
2891        mainSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label='\n Indexing Result:'),0,WACV)
2892        rowLabels = []
2893        colLabels = ['M20','X20','use','Bravais','a','b','c','alpha','beta','gamma','Volume','Keep']
2894        Types = [wg.GRID_VALUE_FLOAT+':10,2',wg.GRID_VALUE_NUMBER,wg.GRID_VALUE_BOOL,wg.GRID_VALUE_STRING,]+ \
2895            3*[wg.GRID_VALUE_FLOAT+':10,5',]+3*[wg.GRID_VALUE_FLOAT+':10,3',]+ \
2896            [wg.GRID_VALUE_FLOAT+':10,2',wg.GRID_VALUE_BOOL]
2897        numRows = len(cells)
2898        table = []
2899        for cell in cells:
2900            rowLabels.append('')
2901            row = cell[0:2]+[cell[-2]]+[bravaisSymb[cell[2]]]+cell[3:10]+[cell[11],]
2902            if cell[-2]:
2903                A = G2lat.cell2A(cell[3:9])
2904                G2frame.HKL = G2lat.GenHBravais(dmin,cell[2],A)
2905                for hkl in G2frame.HKL:
2906                    hkl.insert(4,G2lat.Dsp2pos(Inst,hkl[3])+controls[1])
2907            table.append(row)
2908        UnitCellsTable = G2gd.Table(table,rowLabels=rowLabels,colLabels=colLabels,types=Types)
2909        gridDisplay = G2gd.GSGrid(G2frame.dataDisplay)
2910        gridDisplay.SetTable(UnitCellsTable, True)
2911        G2frame.dataFrame.CopyCell.Enable(True)
2912        gridDisplay.Bind(wg.EVT_GRID_CELL_LEFT_CLICK,RefreshUnitCellsGrid)
2913        gridDisplay.Bind(wg.EVT_GRID_LABEL_LEFT_DCLICK,OnSortCells)
2914        gridDisplay.SetMargins(0,0)
2915        gridDisplay.SetRowLabelSize(0)
2916        gridDisplay.AutoSizeColumns(False)
2917        for r in range(gridDisplay.GetNumberRows()):
2918            for c in range(gridDisplay.GetNumberCols()):
2919                if c == 2:
2920                    gridDisplay.SetReadOnly(r,c,isReadOnly=False)
2921                else:
2922                    gridDisplay.SetReadOnly(r,c,isReadOnly=True)
2923        mainSizer.Add(gridDisplay,0,WACV)
2924    mainSizer.Layout()   
2925    G2frame.dataDisplay.SetSizer(mainSizer)
2926    G2frame.dataDisplay.SetAutoLayout(1)
2927    G2frame.dataDisplay.SetupScrolling()
2928    Size = mainSizer.Fit(G2frame.dataFrame)
2929    Size[0] += 25
2930    G2frame.dataDisplay.SetSize(Size)
2931    G2frame.dataFrame.setSizePosLeft(Size)   
2932   
2933################################################################################
2934#####  Reflection list
2935################################################################################           
2936       
2937def UpdateReflectionGrid(G2frame,data,HKLF=False,Name=''):
2938    '''respond to selection of PWDR Reflections data tree item by displaying
2939    a table of reflections in the data window.
2940    '''
2941    def OnPlotHKL(event):
2942        '''Plots a layer of reflections
2943        '''
2944        phaseName = G2frame.RefList
2945        pId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Phases')
2946        phaseId =  G2gd.GetPatternTreeItemId(G2frame,pId,phaseName)
2947        General = G2frame.PatternTree.GetItemPyData(phaseId)['General']
2948        Super = General.get('Super',0)
2949        SuperVec = General.get('SuperVec',[])
2950        if 'list' in str(type(data)):   #single crystal data is 2 dict in list
2951            refList = data[1]['RefList']
2952        else:                           #powder data is a dict of dicts; each same structure as SC 2nd dict
2953            refList = np.array(data[phaseName]['RefList'])
2954        FoMax = np.max(refList.T[8+Super])
2955        Hmin = np.array([int(np.min(refList.T[0])),int(np.min(refList.T[1])),int(np.min(refList.T[2]))])
2956        Hmax = np.array([int(np.max(refList.T[0])),int(np.max(refList.T[1])),int(np.max(refList.T[2]))])
2957        controls = {'Type' : 'Fo','ifFc' : True,'HKLmax' : Hmax,'HKLmin' : Hmin,
2958            'FoMax' : FoMax,'Zone' : '001','Layer' : 0,'Scale' : 1.0,'Super':Super,'SuperVec':SuperVec}
2959        G2plt.PlotSngl(G2frame,newPlot=True,Data=controls,hklRef=refList,Title=phaseName)
2960       
2961    def OnPlot3DHKL(event):
2962        '''Plots the reflections in 3D
2963        '''
2964        phaseName = G2frame.RefList
2965        pId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Phases')
2966        phaseId =  G2gd.GetPatternTreeItemId(G2frame,pId,phaseName)
2967        General = G2frame.PatternTree.GetItemPyData(phaseId)['General']
2968        Super = General.get('Super',0)
2969        SuperVec = General.get('SuperVec',[])
2970        if 'list' in str(type(data)):   #single crystal data is 2 dict in list
2971            refList = data[1]['RefList']
2972        else:                           #powder data is a dict of dicts; each same structure as SC 2nd dict
2973            refList = np.array(data[phaseName]['RefList'])
2974        FoMax = np.max(refList.T[8+Super])
2975        Hmin = np.array([int(np.min(refList.T[0])),int(np.min(refList.T[1])),int(np.min(refList.T[2]))])
2976        Hmax = np.array([int(np.max(refList.T[0])),int(np.max(refList.T[1])),int(np.max(refList.T[2]))])
2977        Vpoint = [int(np.mean(refList.T[0])),int(np.mean(refList.T[1])),int(np.mean(refList.T[2]))]
2978        controls = {'Type':'Fosq','Iscale':False,'HKLmax':Hmax,'HKLmin':Hmin,
2979            'FoMax' : FoMax,'Scale' : 1.0,'Drawing':{'viewPoint':[Vpoint,[]],'default':Vpoint[:],
2980            'backColor':[0,0,0],'depthFog':False,'Zclip':10.0,'cameraPos':10.,'Zstep':0.05,
2981            'Scale':1.0,'oldxy':[],'viewDir':[1,0,0]},'Super':Super,'SuperVec':SuperVec}
2982        G2plt.Plot3DSngl(G2frame,newPlot=True,Data=controls,hklRef=refList,Title=phaseName)
2983       
2984    def MakeReflectionTable(phaseName):
2985        '''Returns a wx.grid table (G2gd.Table) containing a list of all reflections
2986        for a phase.       
2987        '''
2988        if phaseName:
2989            pId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Phases')
2990            phaseId =  G2gd.GetPatternTreeItemId(G2frame,pId,phaseName)
2991            General = G2frame.PatternTree.GetItemPyData(phaseId)['General']
2992            Super = General.get('Super',0)
2993            SuperVec = General.get('SuperVec',[])
2994        else:
2995            Super = 0
2996            SuperVec = []       
2997        rowLabels = []
2998        if HKLF:
2999            refList = data[1]['RefList']
3000            refs = refList
3001        else:
3002            if len(data) > 1:
3003                G2frame.dataFrame.SelectPhase.Enable(True)
3004            try:            #patch for old reflection lists
3005                if not len(data[phaseName]):
3006                    return None
3007                refList = np.array(data[phaseName]['RefList'])
3008                I100 = refList.T[8+Super]*refList.T[11+Super]
3009            except TypeError:
3010                refList = np.array([refl[:11+Super] for refl in data[phaseName]])
3011                I100 = refList.T[8+Super]*np.array([refl[11+Super] for refl in data[phaseName]])
3012            Imax = np.max(I100)
3013            if Imax:
3014                I100 *= 100.0/Imax
3015            if 'C' in Inst['Type'][0]:
3016                refs = np.vstack((refList.T[:15+Super],I100)).T
3017            elif 'T' in Inst['Type'][0]:
3018                refs = np.vstack((refList.T[:18+Super],I100)).T
3019        for i in range(len(refs)): rowLabels.append(str(i))
3020        Types = (4+Super)*[wg.GRID_VALUE_LONG,]+4*[wg.GRID_VALUE_FLOAT+':10,4',]+ \
3021            2*[wg.GRID_VALUE_FLOAT+':10,2',]+[wg.GRID_VALUE_FLOAT+':10,3',]+ \
3022            [wg.GRID_VALUE_FLOAT+':10,3',]
3023        if HKLF:
3024            colLabels = ['H','K','L','mul','d','Fosq','sig','Fcsq','FoTsq','FcTsq','phase','ExtC',]
3025            if 'T' in Inst['Type'][0]:
3026                colLabels = ['H','K','L','mul','d','Fosq','sig','Fcsq','FoTsq','FcTsq','phase','ExtC','wave','tbar']
3027                Types += 2*[wg.GRID_VALUE_FLOAT+':10,3',]
3028            if Super:
3029                colLabels.insert(3,'M')
3030        else:
3031            if 'C' in Inst['Type'][0]:
3032                colLabels = ['H','K','L','mul','d','pos','sig','gam','Fosq','Fcsq','phase','Icorr','Prfo','Trans','ExtP','I100']
3033                Types += 4*[wg.GRID_VALUE_FLOAT+':10,3',]
3034            elif 'T' in Inst['Type'][0]:
3035                colLabels = ['H','K','L','mul','d','pos','sig','gam','Fosq','Fcsq','phase','Icorr','alp','bet','wave','Prfo','Abs','Ext','I100']
3036                Types += 7*[wg.GRID_VALUE_FLOAT+':10,3',]
3037            if Super:
3038                colLabels.insert(3,'M')
3039        return G2gd.Table(refs,rowLabels=rowLabels,colLabels=colLabels,types=Types)
3040
3041    def ShowReflTable(phaseName):
3042        '''Posts a table of reflections for a phase, creating the table
3043        if needed using MakeReflectionTable
3044        '''
3045        def setBackgroundColors(im,it):
3046            for r in range(G2frame.refTable[phaseName].GetNumberRows()):
3047                if HKLF:
3048                    if float(G2frame.refTable[phaseName].GetCellValue(r,3+im)) <= 0.:
3049                        G2frame.refTable[phaseName].SetCellBackgroundColour(r,3+im,wx.RED)
3050                    Fosq = float(G2frame.refTable[phaseName].GetCellValue(r,5+im))
3051                    Fcsq = float(G2frame.refTable[phaseName].GetCellValue(r,7+im))
3052                    sig = float(G2frame.refTable[phaseName].GetCellValue(r,6+im))
3053                    rat = abs(Fosq-Fcsq)/sig
3054                    if  rat > 10.:
3055                        G2frame.refTable[phaseName].SetCellBackgroundColour(r,7+im,wx.RED)
3056                    elif rat > 3.0:
3057                        G2frame.refTable[phaseName].SetCellBackgroundColour(r,7+im,wx.Colour(255,255,0))
3058#                    else:
3059#                        G2frame.refTable[phaseName].SetCellBackgroundColour(r,7+im,wx.WHITE)
3060                else:   #PWDR
3061                    if float(G2frame.refTable[phaseName].GetCellValue(r,12+im+it)) < 0.:
3062                        G2frame.refTable[phaseName].SetCellBackgroundColour(r,12+im+it,wx.RED)
3063                                                 
3064        G2frame.RefList = phaseName
3065        G2frame.dataFrame.SetLabel('Reflection List for '+phaseName)
3066        if HKLF:
3067            Status.SetStatusText('abs(DF)/sig > 10 red; > 3 yellow; mul < 0 (user rejected) red; mul=0 (sp. gp. absent) red')
3068        else:
3069            Status.SetStatusText('Prfo < 0. in red')
3070        it = 0
3071        if HKLF:
3072            im = data[1].get('Super',0)
3073        else:
3074            if 'T' in data[phaseName]['Type']:
3075                it = 3
3076            im = data[phaseName].get('Super',0)
3077        # has this table already been displayed?
3078        if G2frame.refTable[phaseName].GetTable() is None:
3079            PeakTable = MakeReflectionTable(phaseName)
3080            G2frame.refTable[phaseName].SetTable(PeakTable, True)
3081            G2frame.refTable[phaseName].EnableEditing(False)
3082            G2frame.refTable[phaseName].SetMargins(0,0)
3083            G2frame.refTable[phaseName].AutoSizeColumns(False)
3084            setBackgroundColors(im,it)
3085        # raise the tab (needed for 1st use and from OnSelectPhase)
3086        for PageNum in range(G2frame.dataDisplay.GetPageCount()):
3087            if phaseName == G2frame.dataDisplay.GetPageText(PageNum):
3088                G2frame.dataDisplay.SetSelection(PageNum)
3089                break
3090        else:
3091            print phaseName
3092            print phases
3093            raise Exception("how did we not find a phase name?")
3094       
3095    def OnPageChanged(event):
3096        '''Respond to a press on a phase tab by displaying the reflections. This
3097        routine is needed because the reflection table may not have been created yet.
3098        '''
3099        page = event.GetSelection()
3100        phaseName = G2frame.dataDisplay.GetPageText(page)
3101        ShowReflTable(phaseName)
3102
3103    def OnSelectPhase(event):
3104        '''For PWDR, selects a phase with a selection box. Called from menu.
3105        '''
3106        if len(phases) < 2: return
3107        dlg = wx.SingleChoiceDialog(G2frame,'Select','Phase',phases)
3108        try:
3109            if dlg.ShowModal() == wx.ID_OK:
3110                sel = dlg.GetSelection()
3111                ShowReflTable(phases[sel])
3112        finally:
3113            dlg.Destroy()
3114           
3115    if not data:
3116        print 'No phases, no reflections'
3117        return
3118    if HKLF:
3119        G2frame.RefList = 1
3120        phaseName = IsHistogramInAnyPhase(G2frame,Name)
3121        phases = [phaseName]
3122    else:
3123        phaseName = G2frame.RefList
3124        phases = data.keys()
3125    if G2frame.dataDisplay:
3126        G2frame.dataFrame.Clear()
3127    Inst = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Instrument Parameters'))[0]
3128    if HKLF:
3129        G2gd.SetDataMenuBar(G2frame)
3130        G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.ReflMenu)
3131        if not G2frame.dataFrame.GetStatusBar():
3132            Status = G2frame.dataFrame.CreateStatusBar()   
3133        G2frame.Bind(wx.EVT_MENU, OnPlotHKL, id=G2gd.wxID_PWDHKLPLOT)
3134        G2frame.Bind(wx.EVT_MENU, OnPlot3DHKL, id=G2gd.wxID_PWD3DHKLPLOT)
3135        G2frame.dataFrame.SelectPhase.Enable(False)
3136    else:
3137        G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.ReflMenu)
3138        if not G2frame.dataFrame.GetStatusBar():
3139            Status = G2frame.dataFrame.CreateStatusBar()   
3140        G2frame.Bind(wx.EVT_MENU, OnSelectPhase, id=G2gd.wxID_SELECTPHASE)
3141        G2frame.Bind(wx.EVT_MENU, OnPlotHKL, id=G2gd.wxID_PWDHKLPLOT)
3142        G2frame.Bind(wx.EVT_MENU, OnPlot3DHKL, id=G2gd.wxID_PWD3DHKLPLOT)
3143        G2frame.dataFrame.SelectPhase.Enable(False)
3144           
3145    G2frame.dataDisplay = G2gd.GSNoteBook(parent=G2frame.dataFrame,size=G2frame.dataFrame.GetClientSize())
3146    G2frame.refTable = {}
3147    for tabnum,phase in enumerate(phases):
3148        G2frame.refTable[phase] = G2gd.GSGrid(parent=G2frame.dataDisplay)
3149        G2frame.dataDisplay.AddPage(G2frame.refTable[phase],phase)
3150    if phaseName not in G2frame.refTable:
3151        print phaseName
3152        print phases
3153        raise Exception("how did we get a invalid phase name?")   
3154    ShowReflTable(phaseName)
3155    G2frame.refTable[phaseName].Fit()
3156    size = G2frame.refTable[phaseName].GetSize()
3157    G2frame.dataFrame.setSizePosLeft([size[0]+32,350])       
3158    G2frame.dataDisplay.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CHANGED, OnPageChanged)
3159   
3160################################################################################
3161#####  SASD Substances
3162################################################################################
3163           
3164def UpdateSubstanceGrid(G2frame,data):
3165    '''respond to selection of SASD Substance data tree item.
3166    '''
3167    import Substances as substFile
3168   
3169    def OnLoadSubstance(event):
3170        names = substFile.Substances.keys()
3171        names.sort()
3172        dlg = wx.SingleChoiceDialog(G2frame, 'Which substance?', 'Select substance', names, wx.CHOICEDLG_STYLE)
3173        try:
3174            if dlg.ShowModal() == wx.ID_OK:
3175                name = names[dlg.GetSelection()]
3176            else:
3177                return
3178        finally:
3179            dlg.Destroy()
3180        data['Substances'][name] = {'Elements':{},'Volume':1.0,'Density':1.0,
3181            'Scatt density':0.0,'XAnom density':0.0,'XAbsorption':0.0}
3182        subst = substFile.Substances[name]
3183        ElList = subst['Elements'].keys()
3184        for El in ElList:
3185            Info = G2elem.GetAtomInfo(El.strip().capitalize())
3186            Info.update(subst['Elements'][El])
3187            data['Substances'][name]['Elements'][El] = Info
3188            if 'Volume' in subst:
3189                data['Substances'][name]['Volume'] = subst['Volume']
3190                data['Substances'][name]['Density'] = \
3191                    G2mth.Vol2Den(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])
3192            elif 'Density' in subst:
3193                data['Substances'][name]['Density'] = subst['Density']
3194                data['Substances'][name]['Volume'] = \
3195                    G2mth.Den2Vol(data['Substances'][name]['Elements'],data['Substances'][name]['Density'])
3196            else:
3197                data['Substances'][name]['Volume'] = G2mth.El2EstVol(data['Substances'][name]['Elements'])
3198                data['Substances'][name]['Density'] = \
3199                    G2mth.Vol2Den(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])
3200            data['Substances'][name]['Scatt density'] = \
3201                G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])[0]
3202            contrst,absorb = G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'],wave)         
3203            data['Substances'][name]['XAnom density'] = contrst
3204            data['Substances'][name]['XAbsorption'] = absorb
3205                         
3206        UpdateSubstanceGrid(G2frame,data)
3207       
3208    def OnCopySubstance(event):
3209        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
3210        histList = GetHistsLikeSelected(G2frame)
3211        if not histList:
3212            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
3213            return
3214        copyList = []
3215        dlg = G2G.G2MultiChoiceDialog(
3216            G2frame.dataFrame, 
3217            'Copy substances from\n'+hst[5:]+' to...',
3218            'Copy substances', histList)
3219        try:
3220            if dlg.ShowModal() == wx.ID_OK:
3221                for i in dlg.GetSelections(): 
3222                    copyList.append(histList[i])
3223        finally:
3224            dlg.Destroy()       
3225        for item in copyList:
3226            Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
3227            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Substances'),
3228                copy.copy(data))
3229   
3230    def OnAddSubstance(event):
3231        dlg = wx.TextEntryDialog(None,'Enter a name for this substance','Substance Name Entry','New substance',
3232            style=wx.OK)
3233        if dlg.ShowModal() == wx.ID_OK:
3234            Name = dlg.GetValue()
3235            data['Substances'][Name] = {'Elements':{},'Volume':1.0,'Density':1.0,
3236                'Scatt density':0.0,'XAnom density':0.,'XAbsorption':0.}
3237        dlg.Destroy()
3238        AddElement(Name)
3239        UpdateSubstanceGrid(G2frame,data)
3240       
3241    def OnDeleteSubstance(event):
3242        TextList = []
3243        for name in data['Substances']:
3244            if name != 'vacuum':
3245                TextList += [name,]
3246        if not TextList:
3247            return
3248        dlg = wx.SingleChoiceDialog(G2frame, 'Which substance?', 'Select substance to delete', TextList, wx.CHOICEDLG_STYLE)
3249        try:
3250            if dlg.ShowModal() == wx.ID_OK:
3251                name = TextList[dlg.GetSelection()]
3252            else:
3253                return
3254        finally:
3255            dlg.Destroy()
3256        del(data['Substances'][name])
3257        UpdateSubstanceGrid(G2frame,data)       
3258               
3259    def OnAddElement(event):       
3260        TextList = []
3261        for name in data['Substances']:
3262            if name != 'vacuum':
3263                TextList += [name,]
3264        if not TextList:
3265            return
3266        dlg = wx.SingleChoiceDialog(G2frame, 'Which substance?', 'Select substance', TextList, wx.CHOICEDLG_STYLE)
3267        try:
3268            if dlg.ShowModal() == wx.ID_OK:
3269                name = TextList[dlg.GetSelection()]
3270            else:
3271                return
3272        finally:
3273            dlg.Destroy()
3274        AddElement(name)
3275        UpdateSubstanceGrid(G2frame,data)
3276       
3277    def AddElement(name):
3278        ElList = data['Substances'][name]['Elements'].keys()
3279        dlg = G2elemGUI.PickElements(G2frame,ElList)
3280        if dlg.ShowModal() == wx.ID_OK:
3281            for El in dlg.Elem:
3282                El = El.strip().capitalize()
3283                Info = G2elem.GetAtomInfo(El)
3284                Info.update({'Num':1})
3285                data['Substances'][name]['Elements'][El] = Info
3286                data['Substances'][name]['Volume'] = G2mth.El2EstVol(data['Substances'][name]['Elements'])
3287                data['Substances'][name]['Density'] = \
3288                    G2mth.Vol2Den(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])
3289                data['Substances'][name]['Scatt density'] = \
3290                    G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])[0]
3291                contrst,absorb = G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'],wave)         
3292                data['Substances'][name]['XAnom density'] = contrst
3293                data['Substances'][name]['XAbsorption'] = absorb
3294        dlg.Destroy()
3295       
3296    def OnDeleteElement(event):
3297        TextList = []
3298        for name in data['Substances']:
3299            if name != 'vacuum':
3300                TextList += [name,]
3301        if not TextList:
3302            return
3303        dlg = wx.SingleChoiceDialog(G2frame, 'Which substance?', 'Select substance', TextList, wx.CHOICEDLG_STYLE)
3304        try:
3305            if dlg.ShowModal() == wx.ID_OK:
3306                name = TextList[dlg.GetSelection()]
3307            else:
3308                return
3309        finally:
3310            dlg.Destroy()
3311        ElList = data['Substances'][name]['Elements'].keys()
3312        if len(ElList):
3313            DE = G2elemGUI.DeleteElement(G2frame,ElList)
3314            if DE.ShowModal() == wx.ID_OK:
3315                El = DE.GetDeleteElement().strip().upper()
3316                del(data['Substances'][name]['Elements'][El])
3317                data['Substances'][name]['Volume'] = G2mth.El2EstVol(data['Substances'][name]['Elements'])
3318                data['Substances'][name]['Density'] = \
3319                    G2mth.Vol2Den(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])
3320                data['Substances'][name]['Scatt density'] = \
3321                    G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])[0]
3322                contrst,absorb = G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'],wave)         
3323                data['Substances'][name]['XAnom density'] = contrst
3324                data['Substances'][name]['XAbsorption'] = absorb
3325        UpdateSubstanceGrid(G2frame,data)
3326               
3327    def SubstSizer():
3328       
3329        def OnValueChange(event):
3330            Obj = event.GetEventObject()
3331            if len(Indx[Obj.GetId()]) == 3:
3332                name,El,keyId = Indx[Obj.GetId()]
3333                try:
3334                    value = max(0,float(Obj.GetValue()))
3335                except ValueError:
3336                    value = 0
3337                    Obj.SetValue('%.2f'%(value))
3338                data['Substances'][name]['Elements'][El][keyId] = value
3339                data['Substances'][name]['Volume'] = G2mth.El2EstVol(data['Substances'][name]['Elements'])
3340                data['Substances'][name]['Density'] = \
3341                    G2mth.Vol2Den(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])
3342            else:
3343                name,keyId = Indx[Obj.GetId()]
3344                try:
3345                    value = max(0,float(Obj.GetValue()))
3346                except ValueError:
3347                    value = 1.0
3348                data['Substances'][name][keyId] = value
3349                if keyId in 'Volume':
3350                    data['Substances'][name]['Density'] = \
3351                        G2mth.Vol2Den(data['Substances'][name]['Elements'],value)
3352                elif keyId in 'Density':
3353                    data['Substances'][name]['Volume'] = \
3354                        G2mth.Den2Vol(data['Substances'][name]['Elements'],value)
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            wx.CallAfter(UpdateSubstanceGrid,G2frame,data)
3361       
3362        Indx = {}
3363        substSizer = wx.BoxSizer(wx.VERTICAL)
3364        substSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Substance list: wavelength: %.5fA'%(wave)),
3365            0,WACV)
3366        for name in data['Substances']:
3367            G2gd.HorizontalLine(substSizer,G2frame.dataDisplay)   
3368            substSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Data for '+name+':'),
3369                0,WACV)
3370            if name == 'vacuum':
3371                substSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label='        Not applicable'),
3372                    0,WACV)
3373            else:   
3374                elSizer = wx.FlexGridSizer(0,6,5,5)
3375                Substance = data['Substances'][name]
3376                Elems = Substance['Elements']
3377                for El in Elems:    #do elements as pull downs for isotopes for neutrons
3378                    elSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' '+El+': '),
3379                        0,WACV)
3380                    num = wx.TextCtrl(G2frame.dataDisplay,value='%.2f'%(Elems[El]['Num']),style=wx.TE_PROCESS_ENTER)
3381                    Indx[num.GetId()] = [name,El,'Num']
3382                    num.Bind(wx.EVT_TEXT_ENTER,OnValueChange)       
3383                    num.Bind(wx.EVT_KILL_FOCUS,OnValueChange)
3384                    elSizer.Add(num,0,WACV)
3385                substSizer.Add(elSizer,0)
3386                vdsSizer = wx.FlexGridSizer(0,4,5,5)
3387                vdsSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Volume: '),
3388                    0,WACV)
3389                vol = wx.TextCtrl(G2frame.dataDisplay,value='%.3f'%(Substance['Volume']),style=wx.TE_PROCESS_ENTER)
3390                Indx[vol.GetId()] = [name,'Volume']
3391                vol.Bind(wx.EVT_TEXT_ENTER,OnValueChange)       
3392                vol.Bind(wx.EVT_KILL_FOCUS,OnValueChange)
3393                vdsSizer.Add(vol,0,WACV)               
3394                vdsSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Density: '),
3395                    0,WACV)
3396                den = wx.TextCtrl(G2frame.dataDisplay,value='%.3f'%(Substance['Density']),style=wx.TE_PROCESS_ENTER)
3397                Indx[den.GetId()] = [name,'Density']
3398                den.Bind(wx.EVT_TEXT_ENTER,OnValueChange)       
3399                den.Bind(wx.EVT_KILL_FOCUS,OnValueChange)
3400                vdsSizer.Add(den,0,WACV)
3401                substSizer.Add(vdsSizer,0)
3402                substSizer.Add(wx.StaticText(G2frame.dataDisplay,
3403                    label=' Scattering density  : %.2f *10%scm%s'%(Substance['Scatt density'],Pwr10,Pwrm2)),
3404                    0,WACV)               
3405                substSizer.Add(wx.StaticText(G2frame.dataDisplay,       #allow neutrons here into NAnom density & NAbsorption
3406                    label=' Anomalous density : %.2f *10%scm%s'%(Substance['XAnom density'],Pwr10,Pwrm2)),
3407                    0,WACV)               
3408                substSizer.Add(wx.StaticText(G2frame.dataDisplay,
3409                    label=' X-ray absorption   : %.2f cm%s'%(Substance['XAbsorption'],Pwrm1)),
3410                    0,WACV)               
3411        return substSizer
3412           
3413    Inst = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Instrument Parameters'))[0]
3414    wave = G2mth.getWave(Inst)
3415    if G2frame.dataDisplay:
3416        G2frame.dataFrame.DestroyChildren()  # is this a ScrolledWindow? If so, bad!
3417    G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.SubstanceMenu)
3418    if not G2frame.dataFrame.GetStatusBar():
3419        Status = G2frame.dataFrame.CreateStatusBar()
3420    G2frame.dataDisplay = wxscroll.ScrolledPanel(G2frame.dataFrame)
3421    G2frame.dataFrame.SetLabel('Substances')
3422    G2frame.dataFrame.Bind(wx.EVT_MENU, OnLoadSubstance, id=G2gd.wxID_LOADSUBSTANCE)   
3423    G2frame.dataFrame.Bind(wx.EVT_MENU, OnAddSubstance, id=G2gd.wxID_ADDSUBSTANCE)
3424    G2frame.dataFrame.Bind(wx.EVT_MENU, OnCopySubstance, id=G2gd.wxID_COPYSUBSTANCE)
3425    G2frame.dataFrame.Bind(wx.EVT_MENU, OnDeleteSubstance, id=G2gd.wxID_DELETESUBSTANCE)   
3426    G2frame.dataFrame.Bind(wx.EVT_MENU, OnAddElement, id=G2gd.wxID_ELEMENTADD)
3427    G2frame.dataFrame.Bind(wx.EVT_MENU, OnDeleteElement, id=G2gd.wxID_ELEMENTDELETE)
3428    mainSizer = wx.BoxSizer(wx.VERTICAL)
3429    mainSizer.Add(SubstSizer(),0)
3430
3431    mainSizer.Layout()   
3432    G2frame.dataDisplay.SetSizer(mainSizer)
3433    G2frame.dataDisplay.SetAutoLayout(1)
3434    G2frame.dataDisplay.SetupScrolling()
3435    Size = mainSizer.Fit(G2frame.dataFrame)
3436    Size[0] += 25
3437    G2frame.dataDisplay.SetSize(Size)
3438    G2frame.dataFrame.setSizePosLeft(Size)   
3439       
3440################################################################################
3441#####  SASD Models
3442################################################################################           
3443       
3444def UpdateModelsGrid(G2frame,data):
3445    '''respond to selection of SASD Models data tree item.
3446    '''
3447    #patches
3448    if 'Current' not in data:
3449        data['Current'] = 'Size dist.'
3450    if 'logBins' not in data['Size']:
3451        data['Size']['logBins'] = True
3452    if 'MinMaxDiam' in data['Size']:
3453        data['Size']['MinDiam'] = 50.
3454        data['Size']['MaxDiam'] = 10000.
3455        del data['Size']['MinMaxDiam']
3456    if isinstance(data['Size']['MaxEnt']['Sky'],float):
3457        data['Size']['MaxEnt']['Sky'] = -3
3458    if 'Power' not in data['Size']['IPG']:
3459        data['Size']['IPG']['Power'] = -1
3460    if 'Matrix' not in data['Particle']:
3461        data['Particle']['Matrix'] = {'Name':'vacuum','VolFrac':[0.0,False]}
3462    if 'BackFile' not in data:
3463        data['BackFile'] = ''
3464    #end patches
3465   
3466    def RefreshPlots(newPlot=False):
3467        PlotText = G2frame.G2plotNB.nb.GetPageText(G2frame.G2plotNB.nb.GetSelection())
3468        if 'Powder' in PlotText:
3469            G2plt.PlotPatterns(G2frame,plotType='SASD',newPlot=newPlot)
3470        elif 'Size' in PlotText:
3471            G2plt.PlotSASDSizeDist(G2frame)
3472               
3473    def OnAddModel(event):
3474        if data['Current'] == 'Particle fit':
3475            material = 'vacuum'
3476            if len(data['Particle']['Levels']):
3477                material = data['Particle']['Levels'][-1]['Controls']['Material']
3478            data['Particle']['Levels'].append({
3479                'Controls':{'FormFact':'Sphere','DistType':'LogNormal','Material':material,
3480                    'FFargs':{},'SFargs':{},'NumPoints':50,'Cutoff':0.01,'Contrast':0.0,
3481                    'SlitSmear':[0.0,False],'StrFact':'Dilute'},    #last 2 not used - future?
3482                'LogNormal':{'Volume':[0.05,False],'Mean':[1000.,False],'StdDev':[0.5,False],'MinSize':[10.,False],},
3483                'Gaussian':{'Volume':[0.05,False],'Mean':[1000.,False],'StdDev':[300.,False],},
3484                'LSW':{'Volume':[0.05,False],'Mean':[1000.0,False],},
3485                'Schulz-Zimm':{'Volume':[0.05,False],'Mean':[1000.,False],'StdDev':[300.,False],},
3486                'Unified':{'G':[1.e3,False],'Rg':[100,False],'B':[1.e-5,False],'P':[4,False],'Cutoff':[1e-5,False],},
3487                'Porod':{'B':[1.e-4,False],'P':[4,False],'Cutoff':[1e-5,False],},
3488                'Monodisperse':{'Volume':[0.05,False],'Radius':[100,False],},   #OK for spheres
3489                'Bragg':{'PkInt':[100,False],'PkPos':[0.2,False],
3490                    'PkSig':[10,False],'PkGam':[10,False],},        #reasonable 31A peak
3491                })
3492            G2sasd.ModelFxn(Profile,ProfDict,Limits,Sample,data)
3493            RefreshPlots(True)
3494                   
3495        wx.CallAfter(UpdateModelsGrid,G2frame,data)
3496       
3497    def OnCopyModel(event):
3498        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
3499        histList = GetHistsLikeSelected(G2frame)
3500        if not histList:
3501            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
3502            return
3503        copyList = []
3504        dlg = G2G.G2MultiChoiceDialog(
3505            G2frame.dataFrame, 
3506            'Copy models from\n'+hst[5:]+' to...',
3507            'Copy models', histList)
3508        try:
3509            if dlg.ShowModal() == wx.ID_OK:
3510                for i in dlg.GetSelections(): 
3511                    copyList.append(histList[i])
3512        finally:
3513            dlg.Destroy()       
3514        for item in copyList:
3515            Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
3516            newdata = copy.deepcopy(data)
3517            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Models'),newdata)
3518            if newdata['BackFile']:
3519                Profile = G2frame.PatternTree.GetItemPyData(Id)[1]
3520                BackId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,newdata['BackFile'])
3521                BackSample = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,BackId, 'Sample Parameters'))
3522                Profile[5] = BackSample['Scale'][0]*G2frame.PatternTree.GetItemPyData(BackId)[1][1]
3523        RefreshPlots(True)
3524               
3525    def OnCopyFlags(event):
3526        thisModel = copy.deepcopy(data)
3527        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
3528        histList = GetHistsLikeSelected(G2frame)
3529        if not histList:
3530            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
3531            return
3532        dlg = G2G.G2MultiChoiceDialog(
3533            G2frame.dataFrame, 
3534            'Copy sample ref. flags from\n'+str(hst[5:])+' to...',
3535            'Copy sample flags', histList)
3536        distChoice = ['LogNormal','Gaussian','LSW','Schulz-Zimm','Bragg','Unified',
3537            'Porod','Monodisperse',]
3538        parmOrder = ['Volume','Radius','Mean','StdDev','G','Rg','B','P',
3539            'Cutoff','PkInt','PkPos','PkSig','PkGam','VolFr','Dist',]
3540        try:
3541            if dlg.ShowModal() == wx.ID_OK:
3542                result = dlg.GetSelections()
3543                for i in result: 
3544                    item = histList[i]
3545                    Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
3546                    newModel = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Models'))
3547                    newModel['Back'][1] = copy.copy(thisModel['Back'][1])
3548                    for ilev,level in enumerate(newModel['Particle']['Levels']):
3549                        for form in level:
3550                            if form in distChoice:
3551                                thisForm = thisModel['Particle']['Levels'][ilev][form]                               
3552                                for item in parmOrder:
3553                                    if item in thisForm:
3554                                       level[form][item][1] = copy.copy(thisForm[item][1])
3555                            elif form == 'Controls':
3556                                thisForm = thisModel['Particle']['Levels'][ilev][form]['SFargs']
3557                                for item in parmOrder:
3558                                    if item in thisForm:
3559                                        level[form]['SFargs'][item][1] = copy.copy(thisForm[item][1])
3560        finally:
3561            dlg.Destroy()
3562               
3563    def OnFitModelAll(event):
3564        choices = G2gd.GetPatternTreeDataNames(G2frame,['SASD',])
3565        sel = []
3566        dlg = G2G.G2MultiChoiceDialog(G2frame.dataFrame, 'Sequential SASD refinement',
3567             'Select dataset to include',choices)
3568        dlg.SetSelections(sel)
3569        names = []
3570        if dlg.ShowModal() == wx.ID_OK:
3571            for sel in dlg.GetSelections():
3572                names.append(choices[sel])
3573        dlg.Destroy()
3574        SeqResult = {'histNames':names}
3575        Reverse = False
3576        CopyForward = False
3577        choice = ['Reverse sequence','Copy from prev.']
3578        dlg = wx.MultiChoiceDialog(G2frame.dataFrame,'Sequential controls','Select controls',choice)
3579        if dlg.ShowModal() == wx.ID_OK:
3580            for sel in dlg.GetSelections():
3581                if sel:
3582                    CopyForward = True
3583                else:
3584                    Reverse = True
3585        dlg.Destroy()
3586        dlg = wx.ProgressDialog('SASD Sequential fit','Data set name = '+names[0],len(names), 
3587            style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE|wx.PD_REMAINING_TIME|wx.PD_CAN_ABORT)
3588        wx.BeginBusyCursor()
3589        if Reverse:
3590            names.reverse()
3591        try:
3592            for i,name in enumerate(names):
3593                print ' Sequential fit for ',name
3594                GoOn = dlg.Update(i,newmsg='Data set name = '+name)[0]
3595                if not GoOn:
3596                    break
3597                Id =  G2gd.GetPatternTreeItemId(G2frame,G2frame.root,name)
3598                if i and CopyForward:
3599                    G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Models'),JModel)
3600                IProfDict,IProfile = G2frame.PatternTree.GetItemPyData(Id)[:2]
3601                IModel = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Models'))
3602                ISample = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Sample Parameters'))
3603                ILimits = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Limits'))
3604                IfOK,result,varyList,sig,Rvals,covMatrix,parmDict,Msg = G2sasd.ModelFit(IProfile,IProfDict,ILimits,ISample,IModel)
3605                JModel = copy.deepcopy(IModel)
3606                if not IfOK:
3607                    G2frame.ErrorDialog('Failed sequential refinement for data '+name,
3608                        ' Msg: '+Msg+'\nYou need to rethink your selection of parameters\n'+    \
3609                        ' Model restored to previous version for'+name)
3610                    SeqResult['histNames'] = names[:i]
3611                    dlg.Destroy()
3612                    break
3613                else:
3614                    G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Models'),copy.deepcopy(IModel))
3615               
3616                G2sasd.ModelFxn(IProfile,IProfDict,ILimits,ISample,IModel)
3617                SeqResult[name] = {'variables':result[0],'varyList':varyList,'sig':sig,'Rvals':Rvals,
3618                    'covMatrix':covMatrix,'title':name,'parmDict':parmDict}
3619            else:
3620                dlg.Destroy()
3621                print ' ***** Small angle sequential refinement successful *****'
3622        finally:
3623            wx.EndBusyCursor()   
3624        Id =  G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Sequential results')
3625        if Id:
3626            G2frame.PatternTree.SetItemPyData(Id,SeqResult)
3627        else:
3628            Id = G2frame.PatternTree.AppendItem(parent=G2frame.root,text='Sequential results')
3629            G2frame.PatternTree.SetItemPyData(Id,SeqResult)
3630        G2frame.PatternTree.SelectItem(Id)
3631       
3632    def OnFitModel(event):
3633        if data['Current'] == 'Size dist.':
3634            if not any(Sample['Contrast']):
3635                G2frame.ErrorDialog('No contrast; your sample is a vacuum!',
3636                    'You need to define a scattering substance!\n'+    \
3637                    ' Do Substances and then Sample parameters')
3638                return
3639            G2sasd.SizeDistribution(Profile,ProfDict,Limits,Sample,data)
3640            G2plt.PlotSASDSizeDist(G2frame)
3641            RefreshPlots(True)
3642           
3643        elif data['Current'] == 'Particle fit':
3644            SaveState()
3645            Results = G2sasd.ModelFit(Profile,ProfDict,Limits,Sample,data)
3646            if not Results[0]:
3647                    G2frame.ErrorDialog('Failed refinement',
3648                        ' Msg: '+Results[-1]+'\nYou need to rethink your selection of parameters\n'+    \
3649                        ' Model restored to previous version')
3650            G2sasd.ModelFxn(Profile,ProfDict,Limits,Sample,data)
3651            RefreshPlots(True)
3652            wx.CallAfter(UpdateModelsGrid,G2frame,data)
3653           
3654    def OnUnDo(event):
3655        DoUnDo()
3656        data = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,
3657            G2frame.PatternId,'Models'))
3658        G2frame.dataFrame.SasdUndo.Enable(False)
3659        UpdateModelsGrid(G2frame,data)
3660        G2sasd.ModelFxn(Profile,ProfDict,Limits,Sample,data)
3661        RefreshPlots(True)
3662
3663    def DoUnDo():
3664        print 'Undo last refinement'
3665        file = open(G2frame.undosasd,'rb')
3666        PatternId = G2frame.PatternId
3667        G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Models'),cPickle.load(file))
3668        print ' Models recovered'
3669        file.close()
3670       
3671    def SaveState():
3672        G2frame.undosasd = os.path.join(G2frame.dirname,'GSASIIsasd.save')
3673        file = open(G2frame.undosasd,'wb')
3674        PatternId = G2frame.PatternId
3675        for item in ['Models']:
3676            cPickle.dump(G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId,item)),file,1)
3677        file.close()
3678        G2frame.dataFrame.SasdUndo.Enable(True)
3679       
3680    def OnSelectFit(event):
3681        data['Current'] = fitSel.GetValue()
3682        wx.CallAfter(UpdateModelsGrid,G2frame,data)
3683       
3684    def OnCheckBox(event):
3685        Obj = event.GetEventObject()
3686        item,ind = Indx[Obj.GetId()]
3687        item[ind] = Obj.GetValue()
3688       
3689    def OnIntVal(event):
3690        Obj = event.GetEventObject()
3691        item,ind,minVal = Indx[Obj.GetId()]
3692        try:
3693            value = int(Obj.GetValue())
3694            if value <= minVal:
3695                raise ValueError
3696        except ValueError:
3697            value = item[ind]
3698        Obj.SetValue(str(value))
3699        item[ind] = value
3700
3701    def SizeSizer():
3702       
3703        def OnShape(event):
3704            data['Size']['Shape'][0] = partsh.GetValue()
3705            wx.CallAfter(UpdateModelsGrid,G2frame,data)
3706           
3707        def OnMethod(event):
3708            data['Size']['Method'] = method.GetValue()
3709            wx.CallAfter(UpdateModelsGrid,G2frame,data)
3710           
3711        def OnPartVal(event):
3712            try:
3713                val = max(0.0,float(partprm.GetValue()))
3714            except ValueError:
3715                val = 1
3716            data['Size']['Shape'][1] = val
3717            partprm.SetValue('%.3f'%(val))
3718           
3719        sizeSizer = wx.BoxSizer(wx.VERTICAL)
3720        sizeSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Size distribution parameters: '),0,WACV)
3721        binSizer = wx.FlexGridSizer(0,7,5,5)
3722        binSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' No. size bins: '),0,WACV)
3723        bins = ['50','100','150','200']
3724        nbins = wx.ComboBox(G2frame.dataDisplay,value=str(data['Size']['Nbins']),choices=bins,
3725            style=wx.CB_READONLY|wx.CB_DROPDOWN)
3726        Indx[nbins.GetId()] = [data['Size'],'Nbins',0]
3727        nbins.Bind(wx.EVT_COMBOBOX,OnIntVal)       
3728        binSizer.Add(nbins,0,WACV)
3729        binSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Min diam.: '),0,WACV)
3730        minDias = ['10','25','50','100','150','200']
3731        mindiam = wx.ComboBox(G2frame.dataDisplay,value=str(data['Size']['MinDiam']),choices=minDias,
3732            style=wx.CB_DROPDOWN)
3733        mindiam.Bind(wx.EVT_LEAVE_WINDOW,OnIntVal)
3734        mindiam.Bind(wx.EVT_TEXT_ENTER,OnIntVal)       
3735        mindiam.Bind(wx.EVT_KILL_FOCUS,OnIntVal)
3736        Indx[mindiam.GetId()] = [data['Size'],'MinDiam',0]
3737        binSizer.Add(mindiam,0,WACV)
3738        binSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Max diam.: '),0,WACV)
3739        maxDias = [str(1000*(i+1)) for i in range(10)]
3740        maxdiam = wx.ComboBox(G2frame.dataDisplay,value=str(data['Size']['MaxDiam']),choices=maxDias,
3741            style=wx.CB_DROPDOWN)
3742        maxdiam.Bind(wx.EVT_LEAVE_WINDOW,OnIntVal)
3743        maxdiam.Bind(wx.EVT_TEXT_ENTER,OnIntVal)       
3744        maxdiam.Bind(wx.EVT_KILL_FOCUS,OnIntVal)
3745        Indx[maxdiam.GetId()] = [data['Size'],'MaxDiam',0]
3746        binSizer.Add(maxdiam,0,WACV)
3747        logbins = wx.CheckBox(G2frame.dataDisplay,label='Log bins?')
3748        Indx[logbins.GetId()] = [data['Size'],'logBins']
3749        logbins.SetValue(data['Size']['logBins'])
3750        logbins.Bind(wx.EVT_CHECKBOX, OnCheckBox)
3751        binSizer.Add(logbins,0,WACV)
3752        sizeSizer.Add(binSizer,0)
3753        sizeSizer.Add((5,5),0)
3754        partSizer = wx.BoxSizer(wx.HORIZONTAL)
3755        partSizer.Add(wx.StaticText(G2frame.dataDisplay,label='Particle description: '),0,WACV)
3756        shapes = {'Spheroid':' Aspect ratio: ','Cylinder':' Diameter ','Cylinder AR':' Aspect ratio: ',
3757            'Unified sphere':'','Unified rod':' Diameter: ','Unified rod AR':' Aspect ratio: ',
3758            'Unified disk':' Thickness: '}
3759        partsh = wx.ComboBox(G2frame.dataDisplay,value=str(data['Size']['Shape'][0]),choices=shapes.keys(),
3760            style=wx.CB_READONLY|wx.CB_DROPDOWN)
3761        partsh.Bind(wx.EVT_COMBOBOX,OnShape)       
3762        partSizer.Add(partsh,0,WACV)
3763        if data['Size']['Shape'][0] not in ['Unified sphere',]:
3764            partSizer.Add(wx.StaticText(G2frame.dataDisplay,label=shapes[data['Size']['Shape'][0]]),0,WACV)
3765            partprm = wx.TextCtrl(G2frame.dataDisplay,value='%.3f'%(data['Size']['Shape'][1]),
3766                style=wx.TE_PROCESS_ENTER)
3767            partprm.Bind(wx.EVT_TEXT_ENTER,OnPartVal)       
3768            partprm.Bind(wx.EVT_KILL_FOCUS,OnPartVal)
3769            partSizer.Add(partprm,0,WACV)
3770        sizeSizer.Add(partSizer,0)
3771        sizeSizer.Add((5,5),0)
3772        fitSizer = wx.BoxSizer(wx.HORIZONTAL)
3773        methods = ['MaxEnt','IPG',]
3774        fitSizer.Add(wx.StaticText(G2frame.dataDisplay,label='Fitting method: '),0,WACV)
3775        method = wx.ComboBox(G2frame.dataDisplay,value=data['Size']['Method'],choices=methods,
3776            style=wx.CB_READONLY|wx.CB_DROPDOWN)
3777        method.Bind(wx.EVT_COMBOBOX,OnMethod)
3778        fitSizer.Add(method,0,WACV)
3779        iters = ['10','25','50','100','150','200']       
3780        fitSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' No. iterations: '),0,WACV)
3781        Method = data['Size']['Method']
3782        iter = wx.ComboBox(G2frame.dataDisplay,value=str(data['Size'][Method]['Niter']),choices=iters,
3783            style=wx.CB_READONLY|wx.CB_DROPDOWN)
3784        Indx[iter.GetId()] = [data['Size'][Method],'Niter',0]
3785        iter.Bind(wx.EVT_COMBOBOX,OnIntVal)
3786        fitSizer.Add(iter,0,WACV)
3787        if 'MaxEnt' in data['Size']['Method']:
3788            fitSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Log floor factor: '),0,WACV)
3789            floors = [str(-i) for i in range(9)]
3790            floor = wx.ComboBox(G2frame.dataDisplay,value=str(data['Size']['MaxEnt']['Sky']),choices=floors,
3791                style=wx.CB_READONLY|wx.CB_DROPDOWN)
3792            Indx[floor.GetId()] = [data['Size']['MaxEnt'],'Sky',-10]
3793            floor.Bind(wx.EVT_COMBOBOX,OnIntVal)
3794            fitSizer.Add(floor,0,WACV)
3795        elif 'IPG' in data['Size']['Method']:
3796            fitSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Q power weight (-1 for sigma): '),0,WACV)
3797            choices = ['-1','0','1','2','3','4']
3798            power = wx.ComboBox(G2frame.dataDisplay,value=str(data['Size']['IPG']['Power']),choices=choices,
3799                style=wx.CB_READONLY|wx.CB_DROPDOWN)
3800            Indx[power.GetId()] = [data['Size']['IPG'],'Power',-2]
3801            power.Bind(wx.EVT_COMBOBOX,OnIntVal)
3802            fitSizer.Add(power,0,WACV)
3803        sizeSizer.Add(fitSizer,0)
3804
3805        return sizeSizer
3806       
3807    def PartSizer():
3808       
3809        FormFactors = {'Sphere':{},'Spheroid':{'Aspect ratio':[1.0,False]},
3810            'Cylinder':{'Length':[100.,False]},'Cylinder diam':{'Diameter':[100.,False]},
3811            'Cylinder AR':{'Aspect ratio':[1.0,False]},'Unified sphere':{},
3812            'Unified rod':{'Length':[100.,False]},'Unified rod AR':{'Aspect ratio':[1.0,False]},
3813            'Unified disk':{'Thickness':[100.,False]},
3814            'Unified tube':{'Length':[100.,False],'Thickness':[10.,False]},}
3815               
3816        StructureFactors = {'Dilute':{},'Hard sphere':{'VolFr':[0.1,False],'Dist':[100.,False]},
3817            'Sticky hard sphere':{'VolFr':[0.1,False],'Dist':[100.,False],'epis':[0.05,False],'Sticky':[0.2,False]},
3818            'Square well':{'VolFr':[0.1,False],'Dist':[100.,False],'Depth':[0.1,False],'Width':[1.,False]},
3819            'InterPrecipitate':{'VolFr':[0.1,False],'Dist':[100.,False]},}
3820               
3821        ffDistChoices =  ['Sphere','Spheroid','Cylinder','Cylinder diam',
3822            'Cylinder AR','Unified sphere','Unified rod','Unified rod AR',
3823            'Unified disk','Unified tube',]
3824               
3825        ffMonoChoices = ['Sphere','Spheroid','Cylinder','Cylinder AR',]
3826       
3827        sfChoices = ['Dilute','Hard sphere','Sticky hard sphere','Square well','InterPrecipitate',]
3828           
3829        slMult = 1000.
3830                 
3831        def OnValue(event):
3832            Obj = event.GetEventObject()
3833            item,key,sldrObj = Indx[Obj.GetId()]
3834            try:
3835                value = float(Obj.GetValue())
3836                if value <= 0.:
3837                    raise ValueError
3838            except ValueError:
3839                value = item[key][0]
3840            item[key][0] = value
3841            Obj.SetValue('%.3g'%(value))
3842            if key in ['P','epis','Sticky','Depth','Width','VolFr','Dist']:
3843                sldrObj.SetValue(slMult*value)
3844            else:
3845                logv = np.log10(value)
3846                valMinMax = [logv-1,logv+1]
3847                sldrObj.SetRange(slMult*valMinMax[0],slMult*valMinMax[1])
3848                sldrObj.SetValue(slMult*logv)
3849            G2sasd.ModelFxn(Profile,ProfDict,Limits,Sample,data)
3850            RefreshPlots()
3851           
3852        def OnSelect(event):
3853            Obj = event.GetEventObject()
3854            item,key = Indx[Obj.GetId()]
3855            item[key] = Obj.GetValue()
3856            if 'Refine' not in Obj.GetLabel():
3857                if 'FormFact' in key :
3858                    item['FFargs'] = FormFactors[Obj.GetValue()]
3859                elif 'StrFact' in key:
3860                    item['SFargs'] = StructureFactors[Obj.GetValue()]
3861                wx.CallAfter(UpdateModelsGrid,G2frame,data)
3862                G2sasd.ModelFxn(Profile,ProfDict,Limits,Sample,data)
3863                RefreshPlots()
3864               
3865        def OnDelLevel(event):
3866            Obj = event.GetEventObject()
3867            item = Indx[Obj.GetId()]
3868            del data['Particle']['Levels'][item]
3869            wx.CallAfter(UpdateModelsGrid,G2frame,data)
3870            G2sasd.ModelFxn(Profile,ProfDict,Limits,Sample,data)
3871            RefreshPlots()
3872           
3873        def OnParmSlider(event):
3874            Obj = event.GetEventObject()
3875            item,key,pvObj = Indx[Obj.GetId()]
3876            slide = Obj.GetValue()
3877            if key in ['P','epis','Sticky','Depth','Width','VolFr','Dist']:
3878                value = float(slide/slMult)
3879            else:
3880                value = 10.**float(slide/slMult)
3881            item[key][0] = value
3882            pvObj.SetValue('%.3g'%(item[key][0]))
3883            G2sasd.ModelFxn(Profile,ProfDict,Limits,Sample,data)
3884            RefreshPlots()
3885           
3886        def SizeSizer():
3887            sizeSizer = wx.FlexGridSizer(0,4,5,5)
3888            sizeSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Distribution: '),0,WACV)
3889            Distchoice = ['LogNormal','Gaussian','LSW','Schulz-Zimm','Bragg','Unified','Porod','Monodisperse',]
3890            distChoice = wx.ComboBox(G2frame.dataDisplay,value=level['Controls']['DistType'],choices=Distchoice,
3891                style=wx.CB_READONLY|wx.CB_DROPDOWN)
3892            Indx[distChoice.GetId()] = [level['Controls'],'DistType']
3893            distChoice.Bind(wx.EVT_COMBOBOX,OnSelect)
3894            sizeSizer.Add(distChoice,0,WACV)    #put structure factor choices here
3895            if level['Controls']['DistType'] not in ['Bragg','Unified','Porod',]:
3896                sizeSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Form Factor: '),0,WACV)
3897                if 'Mono' in level['Controls']['DistType']:
3898                    ffChoice = wx.ComboBox(G2frame.dataDisplay,value=level['Controls']['FormFact'],choices=ffMonoChoices,
3899                        style=wx.CB_READONLY|wx.CB_DROPDOWN)
3900                else:
3901                    ffChoice = wx.ComboBox(G2frame.dataDisplay,value=level['Controls']['FormFact'],choices=ffDistChoices,
3902                        style=wx.CB_READONLY|wx.CB_DROPDOWN)
3903                Indx[ffChoice.GetId()] = [level['Controls'],'FormFact']
3904                ffChoice.Bind(wx.EVT_COMBOBOX,OnSelect)
3905                sizeSizer.Add(ffChoice,0,WACV)
3906               
3907                sizeSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Material: '),0,WACV)
3908                matSel = wx.ComboBox(G2frame.dataDisplay,value=level['Controls']['Material'],
3909                    choices=Substances['Substances'].keys(),style=wx.CB_READONLY|wx.CB_DROPDOWN)
3910                Indx[matSel.GetId()] = [level['Controls'],'Material']
3911                matSel.Bind(wx.EVT_COMBOBOX,OnSelect)       
3912                sizeSizer.Add(matSel,0,WACV) #do neutron test here?
3913                rho = Substances['Substances'][level['Controls']['Material']].get('XAnom density',0.0)
3914                level['Controls']['Contrast'] = contrast = (rho-rhoMat)**2                 
3915                sizeSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Resonant X-ray contrast: '),0,WACV)
3916                sizeSizer.Add(wx.StaticText(G2frame.dataDisplay,label=%.2f 10%scm%s'%(contrast,Pwr20,Pwrm4)),0,WACV)
3917                if 'Mono' not in level['Controls']['DistType']:
3918                    sizeSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Num. radii: '),0,WACV)
3919                    radii = ['25','50','75','100','200']
3920                    nRadii = wx.ComboBox(G2frame.dataDisplay,value=str(level['Controls']['NumPoints']),choices=radii,
3921                        style=wx.CB_READONLY|wx.CB_DROPDOWN)
3922                    Indx[nRadii.GetId()] = [level['Controls'],'NumPoints']
3923                    nRadii.Bind(wx.EVT_COMBOBOX,OnSelect)
3924                    sizeSizer.Add(nRadii,0,WACV)
3925                    sizeSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' R dist. cutoff: '),0,WACV)
3926                    rCutoff = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,level['Controls'],'Cutoff',
3927                        min=0.001,max=0.1,typeHint=float)
3928                    sizeSizer.Add(rCutoff,0,WACV)
3929            elif level['Controls']['DistType']  in ['Unified',]:
3930                Parms = level['Unified']
3931                Best = G2sasd.Bestimate(Parms['G'][0],Parms['Rg'][0],Parms['P'][0])
3932                sizeSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Estimated Dist B: %12.4g'%(Best)),0,WACV)
3933            return sizeSizer
3934           
3935        def ParmSizer():
3936            parmSizer = wx.FlexGridSizer(0,3,5,5)
3937            parmSizer.AddGrowableCol(2,1)
3938            parmSizer.SetFlexibleDirection(wx.HORIZONTAL)
3939            Parms = level[level['Controls']['DistType']]
3940            FFargs = level['Controls']['FFargs']
3941            SFargs = level['Controls'].get('SFargs',{})
3942            parmOrder = ['Volume','Radius','Mean','StdDev','MinSize','G','Rg','B','P','Cutoff',
3943                'PkInt','PkPos','PkSig','PkGam',]
3944            for parm in parmOrder:
3945                if parm in Parms:
3946                    if parm == 'MinSize':
3947                        parmSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Dist '+parm),0,wx.ALIGN_CENTER)
3948                    else:
3949                        parmVar = wx.CheckBox(G2frame.dataDisplay,label='Refine? Dist '+parm) 
3950                        parmVar.SetValue(Parms[parm][1])
3951                        parmVar.Bind(wx.EVT_CHECKBOX, OnSelect)
3952                        parmSizer.Add(parmVar,0,WACV)
3953                        Indx[parmVar.GetId()] = [Parms[parm],1]
3954                    parmValue = wx.TextCtrl(G2frame.dataDisplay,value='%.3g'%(Parms[parm][0]),
3955                        style=wx.TE_PROCESS_ENTER)
3956                    parmValue.Bind(wx.EVT_TEXT_ENTER,OnValue)       
3957                    parmValue.Bind(wx.EVT_KILL_FOCUS,OnValue)
3958                    parmSizer.Add(parmValue,0,WACV)
3959                    if parm == 'P':
3960                        value = Parms[parm][0]
3961                        valMinMax = [0.1,4.2]
3962                    else:
3963                        value = np.log10(Parms[parm][0])
3964                        valMinMax = [value-1,value+1]
3965                    parmSldr = wx.Slider(G2frame.dataDisplay,minValue=slMult*valMinMax[0],
3966                        maxValue=slMult*valMinMax[1],value=slMult*value)
3967                    Indx[parmValue.GetId()] = [Parms,parm,parmSldr]
3968                    Indx[parmSldr.GetId()] = [Parms,parm,parmValue]
3969                    parmSldr.Bind(wx.EVT_SLIDER,OnParmSlider)
3970                    parmSizer.Add(parmSldr,1,wx.EXPAND)
3971            if level['Controls']['DistType'] not in ['Bragg']:
3972                parmOrder = ['Aspect ratio','Length','Diameter','Thickness','VolFr','Dist','epis','Sticky','Depth','Width']
3973                fTypes = ['FF ','SF ']
3974                for iarg,Args in enumerate([FFargs,SFargs]):
3975                    for parm in parmOrder:
3976                        if parm in Args:
3977                            parmVar = wx.CheckBox(G2frame.dataDisplay,label='Refine? '+fTypes[iarg]+parm) 
3978                            parmVar.SetValue(Args[parm][1])
3979                            Indx[parmVar.GetId()] = [Args[parm],1]
3980                            parmVar.Bind(wx.EVT_CHECKBOX, OnSelect)
3981                            parmSizer.Add(parmVar,0,WACV)
3982                            parmValue = wx.TextCtrl(G2frame.dataDisplay,value='%.3g'%(Args[parm][0]),
3983                                style=wx.TE_PROCESS_ENTER)
3984                            parmValue.Bind(wx.EVT_TEXT_ENTER,OnValue)       
3985                            parmValue.Bind(wx.EVT_KILL_FOCUS,OnValue)
3986                            parmSizer.Add(parmValue,0,WACV)
3987                            value = Args[parm][0]
3988                            if parm == 'epis':
3989                                valMinMax = [0,.1]
3990                            elif parm in ['Sticky','Width',]:
3991                                valMinMax = [0,1.]
3992                            elif parm == 'Depth':
3993                                valMinMax = [-2.,2.]
3994                            elif parm == 'Dist':
3995                                valMinMax = [100.,1000.]
3996                            elif parm == 'VolFr':
3997                                valMinMax = [1.e-4,1.]
3998                            else:
3999                                value = np.log10(Args[parm][0])
4000                                valMinMax = [value-1,value+1]
4001                            parmSldr = wx.Slider(G2frame.dataDisplay,minValue=slMult*valMinMax[0],
4002                                maxValue=slMult*valMinMax[1],value=slMult*value)
4003                            Indx[parmVar.GetId()] = [Args[parm],1]
4004                            Indx[parmValue.GetId()] = [Args,parm,parmSldr]
4005                            Indx[parmSldr.GetId()] = [Args,parm,parmValue]
4006                            parmSldr.Bind(wx.EVT_SLIDER,OnParmSlider)
4007                            parmSizer.Add(parmSldr,1,wx.EXPAND)
4008            return parmSizer               
4009           
4010        Indx = {}
4011        partSizer = wx.BoxSizer(wx.VERTICAL)
4012        topSizer = wx.BoxSizer(wx.HORIZONTAL)
4013        topSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Particle fit parameters: '),0,WACV)
4014        topSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Matrix: '),0,WACV)
4015        matsel = wx.ComboBox(G2frame.dataDisplay,value=data['Particle']['Matrix']['Name'],
4016            choices=Substances['Substances'].keys(),style=wx.CB_READONLY|wx.CB_DROPDOWN)
4017        Indx[matsel.GetId()] = [data['Particle']['Matrix'],'Name'] 
4018        matsel.Bind(wx.EVT_COMBOBOX,OnSelect) #Do neutron test here?
4019        rhoMat = Substances['Substances'][data['Particle']['Matrix']['Name']].get('XAnom density',0.0)       
4020        topSizer.Add(matsel,0,WACV)
4021        topSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Volume fraction: '),0,WACV)
4022        volfrac = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,data['Particle']['Matrix']['VolFrac'],0,
4023                typeHint=float)
4024        topSizer.Add(volfrac,0,WACV)
4025        volVar = wx.CheckBox(G2frame.dataDisplay,label=' Refine?')
4026        volVar.SetValue(data['Particle']['Matrix']['VolFrac'][1])
4027        Indx[volVar.GetId()] = [data['Particle']['Matrix']['VolFrac'],1]
4028        volVar.Bind(wx.EVT_CHECKBOX, OnSelect)
4029        topSizer.Add(volVar,0,WACV)
4030        partSizer.Add(topSizer,0,)
4031        for ilev,level in enumerate(data['Particle']['Levels']):
4032            G2gd.HorizontalLine(partSizer,G2frame.dataDisplay)
4033            topLevel = wx.BoxSizer(wx.HORIZONTAL)
4034            topLevel.Add(wx.StaticText(G2frame.dataDisplay,label=' Model component %d: '%(ilev)),0,WACV)
4035            delBtn = wx.Button(G2frame.dataDisplay,label=' Delete?')
4036            Indx[delBtn.GetId()] = ilev
4037            delBtn.Bind(wx.EVT_BUTTON,OnDelLevel)
4038            topLevel.Add(delBtn,0,WACV)
4039            partSizer.Add(topLevel,0)
4040            partSizer.Add(SizeSizer())
4041            if level['Controls']['DistType'] not in ['Bragg','Unified','Porod',]:
4042                topLevel.Add(wx.StaticText(G2frame.dataDisplay,label=' Structure factor: '),0,WACV)
4043                strfctr = wx.ComboBox(G2frame.dataDisplay,value=level['Controls']['StrFact'],
4044                    choices=sfChoices,style=wx.CB_READONLY|wx.CB_DROPDOWN)
4045                Indx[strfctr.GetId()] = [level['Controls'],'StrFact']
4046                strfctr.Bind(wx.EVT_COMBOBOX,OnSelect)
4047                topLevel.Add(strfctr,0,WACV)
4048            partSizer.Add(ParmSizer(),0,wx.EXPAND)
4049        return partSizer
4050       
4051    def OnEsdScale(event):
4052        try:
4053            value = float(esdScale.GetValue())
4054            if value <= 0.:
4055                raise ValueError
4056        except ValueError:
4057            value = 1./np.sqrt(ProfDict['wtFactor'])
4058        ProfDict['wtFactor'] = 1./value**2
4059        esdScale.SetValue('%.3f'%(value))
4060        RefreshPlots(True)
4061       
4062    def OnBackChange(event):
4063        try:
4064            value = float(backVal.GetValue())
4065        except ValueError:
4066            value = 0.0
4067        backVal.SetValue('%.3g'%(value))
4068        data['Back'][0] = value
4069        Profile[4][:] = value
4070        RefreshPlots()
4071       
4072    def OnBackFile(event):  #multiple backgrounds?
4073        data['BackFile'] = backFile.GetValue()
4074        if data['BackFile']:
4075            fixBack =  data['Back'][0]
4076            BackId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,data['BackFile'])
4077            BackSample = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,BackId, 'Sample Parameters'))
4078            Profile[5] = BackSample['Scale'][0]*G2frame.PatternTree.GetItemPyData(BackId)[1][1]
4079        else:
4080            Profile[5] = np.zeros(len(Profile[5]))
4081        RefreshPlots(True)
4082           
4083    Sample = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Sample Parameters'))
4084    Limits = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Limits'))
4085    Substances = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Substances'))
4086    ProfDict,Profile = G2frame.PatternTree.GetItemPyData(G2frame.PatternId)[:2]
4087    if data['BackFile']:
4088        BackId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,data['BackFile'])
4089        BackSample = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,BackId, 'Sample Parameters'))
4090        Profile[5] = BackSample['Scale'][0]*G2frame.PatternTree.GetItemPyData(BackId)[1][1]
4091    if G2frame.dataDisplay:
4092        G2frame.dataFrame.DestroyChildren()   # is this a ScrolledWindow? If so, bad!
4093    G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.ModelMenu)
4094    if not G2frame.dataFrame.GetStatusBar():
4095        Status = G2frame.dataFrame.CreateStatusBar()
4096    G2frame.dataFrame.SetLabel('Modelling')
4097    G2frame.dataDisplay = wxscroll.ScrolledPanel(G2frame.dataFrame)
4098    G2frame.dataFrame.Bind(wx.EVT_MENU, OnCopyModel, id=G2gd.wxID_MODELCOPY)
4099    G2frame.dataFrame.Bind(wx.EVT_MENU, OnCopyFlags, id=G2gd.wxID_MODELCOPYFLAGS)
4100    G2frame.dataFrame.Bind(wx.EVT_MENU, OnFitModel, id=G2gd.wxID_MODELFIT)
4101    G2frame.dataFrame.Bind(wx.EVT_MENU, OnFitModelAll, id=G2gd.wxID_MODELFITALL)
4102    G2frame.dataFrame.Bind(wx.EVT_MENU, OnUnDo, id=G2gd.wxID_MODELUNDO)
4103    G2frame.dataFrame.Bind(wx.EVT_MENU, OnAddModel, id=G2gd.wxID_MODELADD)
4104    Indx = {}
4105    mainSizer = wx.BoxSizer(wx.VERTICAL)
4106    topSizer = wx.BoxSizer(wx.HORIZONTAL)
4107    models = ['Size dist.','Particle fit']
4108    topSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Modeling by: '),0