source: trunk/GSASIIpwdGUI.py @ 1587

Last change on this file since 1587 was 1587, checked in by vondreele, 8 years ago

use successive approx. to get d from TOF
allow sorting on a,b,c,alp,bet,gam, vol & m20 in cell indexed table
put in derivatives for fitCell inside indexing routine - better accuracy & speed
add a couple more orthos to SS table

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