source: trunk/GSASIIpwdGUI.py @ 1622

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

add 4D charge flipping - works to give 3D structure; only enabled for 4D data
fix problems with hkl limits in Fourier calcs. - see adjHKLmax
fix reflection table/2D & 3D display issues
disable MC/SA for 4D data

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