source: trunk/GSASIIpwdGUI.py @ 1571

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

fix typos in small angle tutorials
add menu with copy & reset to instrument parameters for SASD data
copy masks now copies the lower threshold
work on indexing incommensurate powder patterns, plots

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 206.8 KB
Line 
1# -*- coding: utf-8 -*-
2#GSASIIpwdGUI - powder data display routines
3########### SVN repository information ###################
4# $Date: 2014-11-15 18:01:30 +0000 (Sat, 15 Nov 2014) $
5# $Author: vondreele $
6# $Revision: 1571 $
7# $URL: trunk/GSASIIpwdGUI.py $
8# $Id: GSASIIpwdGUI.py 1571 2014-11-15 18:01:30Z 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: 1571 $")
32import GSASIImath as G2mth
33import GSASIIpwd as G2pwd
34import GSASIIIO as G2IO
35import GSASIIlattice as G2lat
36import GSASIIspc as G2spc
37import GSASIIindex as G2indx
38import GSASIIplot as G2plt
39import GSASIIgrid as G2gd
40import GSASIIElemGUI as G2elemGUI
41import GSASIIElem as G2elem
42import GSASIIsasd as G2sasd
43import GSASIIexprGUI as G2exG
44VERY_LIGHT_GREY = wx.Colour(235,235,235)
45WACV = wx.ALIGN_CENTER_VERTICAL
46Pwr10 = unichr(0x0b9)+unichr(0x0b0)
47Pwr20 = unichr(0x0b2)+unichr(0x0b0)
48Pwrm1 = unichr(0x207b)+unichr(0x0b9)
49Pwrm2 = unichr(0x207b)+unichr(0x0b2)
50Pwrm4 = unichr(0x207b)+unichr(0x2074)   #really -d but looks like -4 as a superscript
51# trig functions in degrees
52sind = lambda x: math.sin(x*math.pi/180.)
53tand = lambda x: math.tan(x*math.pi/180.)
54cosd = lambda x: math.cos(x*math.pi/180.)
55asind = lambda x: 180.*math.asin(x)/math.pi
56   
57def IsHistogramInAnyPhase(G2frame,histoName):
58    'Needs a doc string'
59    phases = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Phases')
60    if phases:
61        item, cookie = G2frame.PatternTree.GetFirstChild(phases)
62        while item:
63            data = G2frame.PatternTree.GetItemPyData(item)
64            histoList = data['Histograms'].keys()
65            if histoName in histoList:
66                return G2frame.PatternTree.GetItemText(item)
67            item, cookie = G2frame.PatternTree.GetNextChild(phases, cookie)
68        return False
69    else:
70        return False
71
72def SetDefaultSample():
73    'Fills in default items for the Sample dictionary'
74    return {
75        'InstrName':'',
76        'ranId':ran.randint(0,sys.maxint),
77        'Scale':[1.0,True],'Type':'Debye-Scherrer','Absorption':[0.0,False],
78        'DisplaceX':[0.0,False],'DisplaceY':[0.0,False],'Diffuse':[],
79        'Temperature':300.,'Pressure':0.1,'Time':0.0,
80        'FreePrm1':0.,'FreePrm2':0.,'FreePrm3':0.,
81        'Gonio. radius':200.0,
82        'Omega':0.0,'Chi':0.0,'Phi':0.0,
83#SASD items
84        'Materials':[{'Name':'vacuum','VolFrac':1.0,},{'Name':'vacuum','VolFrac':0.0,}],
85        'Thick':1.0,'Contrast':[0.0,0.0],       #contrast & anomalous contrast
86        'Trans':1.0,                            #measured transmission
87        'SlitLen':0.0,                          #Slit length - in Q(A-1)
88        }
89def SetupSampleLabels(histName,dataType,histType):
90    '''Setup a list of labels and number formatting for use in
91    labeling sample parameters.
92    :param str histName: Name of histogram, ("PWDR ...")
93    :param str dataType:
94    '''
95    parms = []
96    parms.append(['Scale','Histogram scale factor: ',[10,4]])
97    if 'C' in histType:
98        parms.append(['Gonio. radius','Goniometer radius (mm): ',[10,3]])
99    if 'PWDR' in histName:
100        if dataType == 'Debye-Scherrer':
101            parms += [['DisplaceX',u'Sample X displ. perp. to beam (\xb5m): ',[10,3]],
102                ['DisplaceY',u'Sample Y displ. || to beam (\xb5m): ',[10,3]],
103                ['Absorption',u'Sample absorption (\xb5\xb7r): ',[10,4]],]
104            if 'T' in histType:
105                parms[-1] = ['Absorption',u'Sample absorption (\xb5\xb7r/l): ',[10,4]]
106        elif dataType == 'Bragg-Brentano':
107            parms += [['Shift',u'Sample displacement(\xb5m): ',[10,4]],
108                ['Transparency',u'Sample transparency(1/\xb5eff, cm): ',[10,3]],
109                ['SurfRoughA','Surface roughness A: ',[10,4]],
110                ['SurfRoughB','Surface roughness B: ',[10,4]]]
111    elif 'SASD' in histName:
112        parms.append(['Thick','Sample thickness (mm)',[10,3]])
113        parms.append(['Trans','Transmission (meas)',[10,3]])
114        parms.append(['SlitLen',u'Slit length (Q,\xc5'+Pwrm1+')',[10,3]])
115    parms.append(['Omega','Goniometer omega:',[10,3]])
116    parms.append(['Chi','Goniometer chi:',[10,3]])
117    parms.append(['Phi','Goniometer phi:',[10,3]])
118    parms.append(['Time','Clock time (s)',[12,3]])
119    parms.append(['Temperature','Sample temperature (K): ',[10,3]])
120    parms.append(['Pressure','Sample pressure (MPa): ',[10,3]])
121    return parms
122
123def SetDefaultSASDModel():
124    'Fills in default items for the SASD Models dictionary'   
125    return {'Back':[0.0,False],'Size':{'MinDiam':50,'MaxDiam':10000,'Nbins':100,'logBins':True,'Method':'MaxEnt','Distribution':[],
126        'Shape':['Spheroid',1.0],'MaxEnt':{'Niter':100,'Precision':0.01,'Sky':-3},
127        'IPG':{'Niter':100,'Approach':0.8,'Power':-1},'Reg':{},},           
128        'Particle':{'Matrix':{'Name':'vacuum','VolFrac':[0.0,False]},'Levels':[],},
129        'Current':'Size dist.','BackFile':'',
130        }
131       
132def SetDefaultSubstances():
133    'Fills in default items for the SASD Substances dictionary'
134    return {'Substances':{'vacuum':{'Elements':{},'Volume':1.0,'Density':0.0,'Scatt density':0.0}}}
135
136def GetHistsLikeSelected(G2frame):
137    '''Get the histograms that match the current selected one:
138    The histogram prefix and data type (PXC etc.), the number of
139    wavelengths and the instrument geometry (Debye-Scherrer etc.)
140    must all match. The current histogram is not included in the list.
141
142    :param wx.Frame G2frame: pointer to main GSAS-II data tree
143    '''
144    histList = []
145    inst,inst2 = G2frame.PatternTree.GetItemPyData(
146        G2gd.GetPatternTreeItemId(
147            G2frame,G2frame.PatternId, 'Instrument Parameters')
148        )
149    hType = inst['Type'][0]
150    if 'Lam1' in inst:
151        hLam = 2
152    elif 'Lam' in inst:
153        hLam = 1
154    else:
155        hLam = 0
156    sample = G2frame.PatternTree.GetItemPyData(
157        G2gd.GetPatternTreeItemId(
158            G2frame,G2frame.PatternId, 'Sample Parameters')
159        )
160    hGeom = sample.get('Type')
161    hstName = G2frame.PatternTree.GetItemText(G2frame.PatternId)
162    hPrefix = hstName.split()[0]+' '
163    # cycle through tree looking for items that match the above
164    item, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)       
165    while item:
166        name = G2frame.PatternTree.GetItemText(item)
167        if name.startswith(hPrefix) and name != hstName:
168            cGeom,cType,cLam, = '?','?',-1
169            subitem, subcookie = G2frame.PatternTree.GetFirstChild(item)
170            while subitem:
171                subname = G2frame.PatternTree.GetItemText(subitem)
172                if subname == 'Sample Parameters':
173                    sample = G2frame.PatternTree.GetItemPyData(subitem)
174                    cGeom = sample.get('Type')
175                elif subname == 'Instrument Parameters':
176                    inst,inst2 = G2frame.PatternTree.GetItemPyData(subitem)
177                    cType = inst['Type'][0]
178                    if 'Lam1' in inst:
179                        cLam = 2
180                    elif 'Lam' in inst:
181                        cLam = 1
182                    else:
183                        cLam = 0
184                subitem, subcookie = G2frame.PatternTree.GetNextChild(item, subcookie)
185            if cLam == hLam and cType == hType and cGeom == hGeom:
186                if name not in histList: histList.append(name)
187        item, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)
188    return histList
189
190def SetCopyNames(histName,dataType,addNames=[]):
191    '''Determine the items in the sample parameters that should be copied,
192    depending on the histogram type and the instrument type.
193    '''
194    copyNames = ['Scale',]
195    histType = 'HKLF'
196    if 'PWDR' in histName:
197        histType = 'PWDR'
198        if 'Debye' in dataType:
199            copyNames += ['DisplaceX','DisplaceY','Absorption']
200        else:       #Bragg-Brentano
201            copyNames += ['Shift','Transparency','SurfRoughA','SurfRoughB']
202    elif 'SASD' in histName:
203        histType = 'SASD'
204        copyNames += ['Materials','Thick',]
205    if len(addNames):
206        copyNames += addNames
207    return histType,copyNames
208
209def CopySelectedHistItems(G2frame):
210    '''Global copy: Copy items from current histogram to others.
211    This is called from the menubar and is available only when the top histogram tree entry
212    is selected.
213    '''
214    hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
215    histList = GetHistsLikeSelected(G2frame)
216    if not histList:
217        G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
218        return
219    choices = ['Limits','Background','Instrument Parameters','Sample Parameters']
220    dlg = G2gd.G2MultiChoiceDialog(
221        G2frame.dataFrame, 
222        'Copy which histogram sections from\n'+str(hst[5:]),
223        'Select copy sections', choices, filterBox=False)
224    dlg.SetSelections(range(len(choices)))
225    choiceList = []
226    if dlg.ShowModal() == wx.ID_OK:
227        choiceList = [choices[i] for i in dlg.GetSelections()]
228    if not choiceList: return
229   
230    dlg = G2gd.G2MultiChoiceDialog(
231        G2frame.dataFrame, 
232        'Copy parameters from\n'+str(hst[5:])+' to...',
233        'Copy parameters', histList)
234    results = []
235    try:
236        if dlg.ShowModal() == wx.ID_OK:
237            results = dlg.GetSelections()
238    finally:
239        dlg.Destroy()
240    copyList = []
241    for i in results: 
242        copyList.append(histList[i])
243
244    if 'Limits' in choiceList: # Limits
245        data = G2frame.PatternTree.GetItemPyData(
246            G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId,'Limits'))
247        for item in copyList:
248            Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
249            G2frame.PatternTree.SetItemPyData(
250                G2gd.GetPatternTreeItemId(G2frame,Id,'Limits'),
251                copy.deepcopy(data))
252    if 'Background' in choiceList:  # Background
253        data = G2frame.PatternTree.GetItemPyData(
254            G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId,'Background'))
255        for item in copyList:
256            Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
257            G2frame.PatternTree.SetItemPyData(
258                G2gd.GetPatternTreeItemId(G2frame,Id,'Background'),
259                copy.deepcopy(data))
260    if 'Instrument Parameters' in choiceList:  # Instrument Parameters
261        # for now all items in Inst. parms are copied
262        data,data1 = G2frame.PatternTree.GetItemPyData(
263            G2gd.GetPatternTreeItemId(
264                G2frame,G2frame.PatternId,'Instrument Parameters'))
265        for item in copyList:
266            Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
267            G2frame.PatternTree.GetItemPyData(
268                G2gd.GetPatternTreeItemId(G2frame,Id,'Instrument Parameters')
269                )[0].update(copy.deepcopy(data))
270            G2frame.PatternTree.GetItemPyData(
271                G2gd.GetPatternTreeItemId(G2frame,Id,'Instrument Parameters')
272                )[1].update(copy.deepcopy(data1))
273    if 'Sample Parameters' in choiceList:  # Sample Parameters
274        data = G2frame.PatternTree.GetItemPyData(
275            G2gd.GetPatternTreeItemId(
276                G2frame,G2frame.PatternId,'Sample Parameters'))
277        # selects items to be copied
278        histType,copyNames = SetCopyNames(hst,data['Type'],
279            addNames = ['Omega','Chi','Phi','Gonio. radius','InstrName'])
280        copyDict = {parm:data[parm] for parm in copyNames}
281        for item in copyList:
282            Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
283            G2frame.PatternTree.GetItemPyData(
284                G2gd.GetPatternTreeItemId(G2frame,Id,'Sample Parameters')
285                ).update(copy.deepcopy(copyDict))
286                         
287################################################################################
288#####  Powder Peaks
289################################################################################           
290       
291def UpdatePeakGrid(G2frame, data):
292    '''respond to selection of PWDR powder peaks data tree item.
293    '''
294    if G2frame.dataDisplay:
295        G2frame.dataFrame.Clear()
296       
297    def OnAutoSearch(event):
298        PatternId = G2frame.PatternId
299        PickId = G2frame.PickId
300        limits = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Limits'))[1]
301        inst,inst2 = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Instrument Parameters'))
302        profile = G2frame.PatternTree.GetItemPyData(PatternId)[1]
303        x0 = profile[0]
304        iBeg = np.searchsorted(x0,limits[0])
305        iFin = np.searchsorted(x0,limits[1])
306        x = x0[iBeg:iFin]
307        y0 = profile[1][iBeg:iFin]
308        y1 = copy.copy(y0)
309        ysig = np.std(y1)
310        offset = [-1,1]
311        ymask = ma.array(y0,mask=(y0<ysig))
312        for off in offset:
313            ymask = ma.array(ymask,mask=(ymask-np.roll(y0,off)<=0.))
314        indx = ymask.nonzero()
315        mags = ymask[indx]
316        poss = x[indx]
317        refs = zip(poss,mags)
318        if 'C' in Inst['Type'][0]:   
319            refs = G2mth.sortArray(refs,0,reverse=True)     #small 2-Thetas first
320        else:   #'T'OF
321            refs = G2mth.sortArray(refs,0,reverse=False)    #big TOFs first
322        for i,ref1 in enumerate(refs):
323            for ref2 in refs[i+1:]:
324                if abs(ref2[0]-ref1[0]) < 0.1*G2pwd.getFWHM(ref1[0],inst):
325                    del(refs[i])
326        if 'C' in Inst['Type'][0]:   
327            refs = G2mth.sortArray(refs,1,reverse=True)
328        else:   #'T'OF
329            refs = G2mth.sortArray(refs,1,reverse=False)
330        for pos,mag in refs:
331            data['peaks'].append(G2mth.setPeakparms(inst,inst2,pos,mag))
332        UpdatePeakGrid(G2frame,data)
333        G2plt.PlotPatterns(G2frame,plotType='PWDR')
334       
335    def OnCopyPeaks(event):
336        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
337        histList = GetHistsLikeSelected(G2frame)
338        if not histList:
339            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
340            return
341        copyList = []
342        dlg = G2gd.G2MultiChoiceDialog(
343            G2frame.dataFrame, 
344            'Copy peak list from\n'+str(hst[5:])+' to...',
345            'Copy peaks', histList)
346        try:
347            if dlg.ShowModal() == wx.ID_OK:
348                for i in dlg.GetSelections():
349                    copyList.append(histList[i])
350        finally:
351            dlg.Destroy()
352        for item in copyList:
353            Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
354            G2frame.PatternTree.SetItemPyData(
355                G2gd.GetPatternTreeItemId(G2frame,Id,'Peak List'),copy.deepcopy(data))
356   
357    def OnUnDo(event):
358        DoUnDo()
359        G2frame.dataFrame.UnDo.Enable(False)
360       
361    def DoUnDo():
362        print 'Undo last refinement'
363        file = open(G2frame.undofile,'rb')
364        PatternId = G2frame.PatternId
365        for item in ['Background','Instrument Parameters','Peak List']:
366            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, item),cPickle.load(file))
367            if G2frame.dataDisplay.GetName() == item:
368                if item == 'Background':
369                    UpdateBackground(G2frame,G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, item)))
370                elif item == 'Instrument Parameters':
371                    UpdateInstrumentGrid(G2frame,G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, item)))
372                elif item == 'Peak List':
373                    UpdatePeakGrid(G2frame,G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, item)))
374            print item,' recovered'
375        file.close()
376       
377    def SaveState():
378        G2frame.undofile = os.path.join(G2frame.dirname,'GSASII.save')
379        file = open(G2frame.undofile,'wb')
380        PatternId = G2frame.PatternId
381        for item in ['Background','Instrument Parameters','Peak List']:
382            cPickle.dump(G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId,item)),file,1)
383        file.close()
384        G2frame.dataFrame.UnDo.Enable(True)
385       
386    def OnLSQPeakFit(event):
387        if not G2frame.GSASprojectfile:            #force a save of the gpx file so SaveState can wirte in the same directory
388            G2frame.OnFileSaveas(event)
389        OnPeakFit('LSQ')
390       
391    def OnOneCycle(event):
392        OnPeakFit('LSQ',oneCycle=True)
393       
394    def OnSeqPeakFit(event):
395        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
396        histList = GetHistsLikeSelected(G2frame)
397        if not histList:
398            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
399            return
400        sel = []
401        dlg = G2gd.G2MultiChoiceDialog(G2frame.dataFrame, 'Sequential peak fits',
402             'Select dataset to include',histList)
403        dlg.SetSelections(sel)
404        names = []
405        if dlg.ShowModal() == wx.ID_OK:
406            for sel in dlg.GetSelections():
407                names.append(histList[sel])
408        dlg.Destroy()
409        SeqResult = {}
410        Reverse = False
411        CopyForward = False
412        choice = ['Reverse sequence','Copy from prev.',]
413        dlg = wx.MultiChoiceDialog(G2frame.dataFrame,'Sequential controls','Select controls',choice)
414        if dlg.ShowModal() == wx.ID_OK:
415            for sel in dlg.GetSelections():
416                if sel:
417                    CopyForward = True
418                else:
419                    Reverse = True
420        dlg.Destroy()
421        dlg = wx.ProgressDialog('Sequential peak fit','Data set name = '+names[0],len(names), 
422            style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE|wx.PD_REMAINING_TIME|wx.PD_CAN_ABORT)
423        Controls = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.root, 'Controls'))
424        controls = {'deriv type':'analytic','min dM/M':0.0001,}
425        Controls['ShowCell'] = False
426        print 'Peak Fitting with '+controls['deriv type']+' derivatives:'
427        oneCycle = False
428        FitPgm = 'LSQ'
429        prevVaryList = []
430        Names = []
431        if Reverse:
432            names.reverse()
433        try:
434            for i,name in enumerate(names):
435                print ' Sequential fit for ',name
436                GoOn = dlg.Update(i,newmsg='Data set name = '+name)[0]
437                if not GoOn:
438                    break
439                PatternId =  G2gd.GetPatternTreeItemId(G2frame,G2frame.root,name)
440                if i and CopyForward:
441                    G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Peak List'),copy.deepcopy(peaks))
442                    prevVaryList = varyList[:]
443                peaks = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Peak List'))
444                background = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Background'))
445                limits = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Limits'))[1]
446                inst,inst2 = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Instrument Parameters'))
447                data = G2frame.PatternTree.GetItemPyData(PatternId)[1]
448                wx.BeginBusyCursor()
449                dlg2 = wx.ProgressDialog('Residual','Peak fit Rwp = ',101.0, 
450                    style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE|wx.PD_REMAINING_TIME|wx.PD_CAN_ABORT)
451                screenSize = wx.ClientDisplayRect()
452                Size = dlg.GetSize()
453                dlg2.SetPosition(wx.Point(screenSize[2]-Size[0]-305,screenSize[1]+5))
454                try:
455                    peaks['sigDict'],result,sig,Rvals,varyList,parmDict,fullvaryList,badVary = G2pwd.DoPeakFit(FitPgm,peaks['peaks'],
456                        background,limits,inst,inst2,data,prevVaryList,oneCycle,controls,dlg2)
457                finally:
458                    dlg2.Destroy()
459                if len(result[0]) != len(fullvaryList):
460                    print ' ***** Sequential peak fit stopped at '+name+' *****'
461                    break
462                else:
463                    Names.append(name)   
464                    G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Peak List'),copy.deepcopy(peaks))
465                    SeqResult[name] = {'variables':result[0],'varyList':varyList,'sig':sig,'Rvals':Rvals,
466                        'covMatrix':np.eye(len(result[0])),'title':name,'parmDict':parmDict,
467                        'fullVary':fullvaryList,'badVary':badVary}
468            dlg.Destroy()
469            print ' ***** Sequential peak fit successful *****'
470        finally:
471            wx.EndBusyCursor()
472        SeqResult['histNames'] = Names
473        Id =  G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Sequential results')
474        if Id:
475            G2frame.PatternTree.SetItemPyData(Id,SeqResult)
476        else:
477            Id = G2frame.PatternTree.AppendItem(parent=G2frame.root,text='Sequential results')
478            G2frame.PatternTree.SetItemPyData(Id,SeqResult)
479        G2frame.PatternTree.SelectItem(Id)
480       
481    def OnClearPeaks(event):
482        dlg = wx.MessageDialog(G2frame,'Delete all peaks?','Clear peak list',wx.OK|wx.CANCEL)
483        try:
484            if dlg.ShowModal() == wx.ID_OK:
485                peaks = {'peaks':[],'sigDict':{}}
486        finally:
487            dlg.Destroy()
488        UpdatePeakGrid(G2frame,peaks)
489        G2plt.PlotPatterns(G2frame,plotType='PWDR')
490       
491    def OnPeakFit(FitPgm,oneCycle=False):
492        SaveState()
493        controls = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.root, 'Controls'))
494        if not controls:
495            controls = {'deriv type':'analytic','min dM/M':0.0001,}     #fill in defaults if needed
496        print 'Peak Fitting with '+controls['deriv type']+' derivatives:'
497        PatternId = G2frame.PatternId
498        PickId = G2frame.PickId
499        peaks = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Peak List'))
500        if not peaks:
501            G2frame.ErrorDialog('No peaks!','Nothing to fit!')
502            return
503        background = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Background'))
504        limits = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Limits'))[1]
505        inst,inst2 = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Instrument Parameters'))
506        data = G2frame.PatternTree.GetItemPyData(PatternId)[1]
507        wx.BeginBusyCursor()
508        dlg = wx.ProgressDialog('Residual','Peak fit Rwp = ',101.0, 
509            style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE|wx.PD_REMAINING_TIME|wx.PD_CAN_ABORT)
510        screenSize = wx.ClientDisplayRect()
511        Size = dlg.GetSize()
512        dlg.SetPosition(wx.Point(screenSize[2]-Size[0]-305,screenSize[1]+5))
513        try:
514            peaks['sigDict'] = G2pwd.DoPeakFit(FitPgm,peaks['peaks'],background,limits,inst,inst2,data,[],oneCycle,controls,dlg)[0]
515        finally:
516            wx.EndBusyCursor()   
517        G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Peak List'),copy.copy(peaks))
518        UpdatePeakGrid(G2frame,copy.copy(peaks))
519        G2plt.PlotPatterns(G2frame,plotType='PWDR')
520        print 'finished'
521        return
522       
523    def OnResetSigGam(event):
524        PatternId = G2frame.PatternId
525        PickId = G2frame.PickId
526        Inst,Inst2 = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Instrument Parameters'))
527        peaks = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Peak List'))
528        if not peaks['peaks']:
529            G2frame.ErrorDialog('No peaks!','Nothing to do!')
530            return
531        newpeaks = {'peaks':[],'sigDict':{}}
532        for peak in peaks['peaks']:
533            newpeaks['peaks'].append(G2mth.setPeakparms(Inst,Inst2,peak[0],peak[2]))
534        G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Peak List'),newpeaks)
535        UpdatePeakGrid(G2frame,newpeaks)
536               
537    def RefreshPeakGrid(event):
538        r,c =  event.GetRow(),event.GetCol()
539       
540        event.StopPropagation()
541        data['peaks'] = G2frame.PeakTable.GetData()
542        T = []
543        for peak in data['peaks']:T.append(peak[0])
544        D = dict(zip(T,data['peaks']))
545        T.sort()
546        X = []
547        for key in T: X.append(D[key])
548        data['peaks'] = X       
549       
550    def setBackgroundColors():
551       for r in range(G2frame.dataDisplay.GetNumberRows()):
552           for c in range(G2frame.dataDisplay.GetNumberCols()):
553               if G2frame.dataDisplay.GetColLabelValue(c) in ['position','intensity','alpha','beta','sigma','gamma']:
554                   if float(G2frame.dataDisplay.GetCellValue(r,c)) < 0.:
555                       G2frame.dataDisplay.SetCellBackgroundColour(r,c,wx.RED)
556                   else:
557                       G2frame.dataDisplay.SetCellBackgroundColour(r,c,wx.WHITE)
558                                                 
559    def KeyEditPeakGrid(event):
560        rowList = G2frame.dataDisplay.GetSelectedRows()
561        colList = G2frame.dataDisplay.GetSelectedCols()
562        selectList = G2frame.dataDisplay.GetSelectedCells()
563        data = G2frame.PatternTree.GetItemPyData(G2frame.PickId)
564        if event.GetKeyCode() == wx.WXK_RETURN:
565            event.Skip(True)
566        elif event.GetKeyCode() == wx.WXK_CONTROL:
567            event.Skip(True)
568        elif event.GetKeyCode() == wx.WXK_SHIFT:
569            event.Skip(True)
570        elif rowList:
571            G2frame.dataDisplay.ClearSelection()
572            if event.GetKeyCode() == wx.WXK_DELETE:
573                G2frame.dataDisplay.ClearGrid()
574                rowList.sort()
575                rowList.reverse()
576                nDel = 0
577                for row in rowList:
578                    G2frame.PeakTable.DeleteRow(row)
579                    nDel += 1
580                if nDel:
581                    msg = wg.GridTableMessage(G2frame.PeakTable, 
582                        wg.GRIDTABLE_NOTIFY_ROWS_DELETED,0,nDel)
583                    G2frame.dataDisplay.ProcessTableMessage(msg)
584                data = G2frame.PeakTable.GetData()
585                G2frame.PatternTree.SetItemPyData(G2frame.PickId,data[:-nDel])
586                G2frame.dataDisplay.ForceRefresh()
587                setBackgroundColors()
588                       
589        elif colList:
590            G2frame.dataDisplay.ClearSelection()
591            key = event.GetKeyCode()
592            for col in colList:
593                if G2frame.PeakTable.GetTypeName(0,col) == wg.GRID_VALUE_BOOL:
594                    if key == 89: #'Y'
595                        for row in range(G2frame.PeakTable.GetNumberRows()): data['peaks'][row][col]=True
596                    elif key == 78:  #'N'
597                        for row in range(G2frame.PeakTable.GetNumberRows()): data['peaks'][row][col]=False
598        elif selectList:
599            G2frame.dataDisplay.ClearSelection()
600            key = event.GetKeyCode()
601            for row,col in selectList:
602                if G2frame.PeakTable.GetTypeName(row,col) == wg.GRID_VALUE_BOOL:
603                    if key == 89: #'Y'
604                        data['peaks'][row][col]=True
605                    elif key == 78:  #'N'
606                        data['peaks'][row][col]=False
607        G2plt.PlotPatterns(G2frame,plotType='PWDR')
608           
609    G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.PeakMenu)
610    if not G2frame.dataFrame.GetStatusBar():
611        Status = G2frame.dataFrame.CreateStatusBar()
612    Status.SetStatusText('Global refine: select refine column & press Y or N')
613    G2frame.Bind(wx.EVT_MENU, OnAutoSearch, id=G2gd.wxID_AUTOSEARCH)
614    G2frame.Bind(wx.EVT_MENU, OnCopyPeaks, id=G2gd.wxID_PEAKSCOPY)
615    G2frame.Bind(wx.EVT_MENU, OnUnDo, id=G2gd.wxID_UNDO)
616    G2frame.Bind(wx.EVT_MENU, OnLSQPeakFit, id=G2gd.wxID_LSQPEAKFIT)
617    G2frame.Bind(wx.EVT_MENU, OnOneCycle, id=G2gd.wxID_LSQONECYCLE)
618    G2frame.Bind(wx.EVT_MENU, OnSeqPeakFit, id=G2gd.wxID_SEQPEAKFIT)
619    G2frame.Bind(wx.EVT_MENU, OnClearPeaks, id=G2gd.wxID_CLEARPEAKS)
620    G2frame.Bind(wx.EVT_MENU, OnResetSigGam, id=G2gd.wxID_RESETSIGGAM)
621    if data['peaks']:
622        G2frame.dataFrame.AutoSearch.Enable(False)
623        G2frame.dataFrame.PeakCopy.Enable(True)
624        G2frame.dataFrame.PeakFit.Enable(True)
625        G2frame.dataFrame.PFOneCycle.Enable(True)
626        G2frame.dataFrame.SeqPeakFit.Enable(True)
627    else:
628        G2frame.dataFrame.PeakFit.Enable(False)
629        G2frame.dataFrame.PeakCopy.Enable(False)
630        G2frame.dataFrame.PFOneCycle.Enable(False)
631        G2frame.dataFrame.AutoSearch.Enable(True)
632        G2frame.dataFrame.SeqPeakFit.Enable(False)
633    G2frame.PickTable = []
634    rowLabels = []
635    PatternId = G2frame.PatternId
636    Inst = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Instrument Parameters'))[0]
637    for i in range(len(data['peaks'])): rowLabels.append(str(i+1))
638    if 'C' in Inst['Type'][0]:
639        colLabels = ['position','refine','intensity','refine','sigma','refine','gamma','refine']
640        Types = [wg.GRID_VALUE_FLOAT+':10,4',wg.GRID_VALUE_BOOL,
641            wg.GRID_VALUE_FLOAT+':10,1',wg.GRID_VALUE_BOOL,
642            wg.GRID_VALUE_FLOAT+':10,5',wg.GRID_VALUE_BOOL,
643            wg.GRID_VALUE_FLOAT+':10,5',wg.GRID_VALUE_BOOL]
644    else:
645        colLabels = ['position','refine','intensity','refine','alpha','refine',
646            'beta','refine','sigma','refine','gamma','refine']
647        Types = [wg.GRID_VALUE_FLOAT+':10,1',wg.GRID_VALUE_BOOL,
648            wg.GRID_VALUE_FLOAT+':10,4',wg.GRID_VALUE_BOOL,
649            wg.GRID_VALUE_FLOAT+':10,4',wg.GRID_VALUE_BOOL,
650            wg.GRID_VALUE_FLOAT+':10,5',wg.GRID_VALUE_BOOL,
651            wg.GRID_VALUE_FLOAT+':10,5',wg.GRID_VALUE_BOOL,
652            wg.GRID_VALUE_FLOAT+':10,5',wg.GRID_VALUE_BOOL]
653    T = []
654    for peak in data['peaks']:
655        T.append(peak[0])
656    D = dict(zip(T,data['peaks']))
657    T.sort()
658    if 'T' in Inst['Type'][0]:  #want big TOF's first
659        T.reverse()
660    X = []
661    for key in T: X.append(D[key])
662    data['peaks'] = X
663    G2frame.PatternTree.SetItemPyData(G2frame.PickId,data)
664    G2frame.PeakTable = G2gd.Table(data['peaks'],rowLabels=rowLabels,colLabels=colLabels,types=Types)
665    G2frame.dataFrame.SetLabel('Peak List')
666    G2frame.dataDisplay = G2gd.GSGrid(parent=G2frame.dataFrame)
667    G2frame.dataDisplay.SetTable(G2frame.PeakTable, True)
668    setBackgroundColors()                         
669    G2frame.dataDisplay.Bind(wg.EVT_GRID_CELL_CHANGE, RefreshPeakGrid)
670    G2frame.dataDisplay.Bind(wx.EVT_KEY_DOWN, KeyEditPeakGrid)
671    G2frame.dataDisplay.SetMargins(0,0)
672    G2frame.dataDisplay.AutoSizeColumns(False)
673    G2frame.dataFrame.setSizePosLeft([535,350])
674    G2frame.dataFrame.SendSizeEvent()
675       
676################################################################################
677#####  Background
678################################################################################           
679       
680def UpdateBackground(G2frame,data):
681    '''respond to selection of PWDR background data tree item.
682    '''
683    if len(data) < 2:       #add Debye diffuse & peaks scattering here
684        data.append({'nDebye':0,'debyeTerms':[],'nPeaks':0,'peaksList':[]})
685    if 'nPeaks' not in data[1]:
686        data[1].update({'nPeaks':0,'peaksList':[]})
687    ValObj = {}
688   
689    def OnBackFlagCopy(event):
690        flag = data[0][1]
691        backDict = data[-1]
692        if backDict['nDebye']:
693            DBflags = []
694            for term in backDict['debyeTerms']:
695                DBflags.append(term[1::2])
696        if backDict['nPeaks']:
697            PKflags = []
698            for term in backDict['peaksList']:
699                PKflags.append(term[1::2])           
700        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
701        histList = GetHistsLikeSelected(G2frame)
702        if not histList:
703            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
704            return
705        dlg = G2gd.G2MultiChoiceDialog(
706            G2frame.dataFrame, 
707            'Copy bkg ref. flags from\n'+str(hst[5:])+' to...',
708            'Copy bkg flags', histList)
709        copyList = []
710        try:
711            if dlg.ShowModal() == wx.ID_OK:
712                for i in dlg.GetSelections(): 
713                    copyList.append(histList[i])
714        finally:
715            dlg.Destroy()
716        for item in copyList:
717            Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
718            backData = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Background'))
719            backData[0][1] = copy.copy(flag)
720            bkDict = backData[-1]
721            if bkDict['nDebye'] == backDict['nDebye']:
722                for i,term in enumerate(bkDict['debyeTerms']):
723                    term[1::2] = copy.copy(DBflags[i])
724            if bkDict['nPeaks'] == backDict['nPeaks']:
725                for i,term in enumerate(bkDict['peaksList']):
726                    term[1::2] = copy.copy(PKflags[i])                   
727           
728    def OnBackCopy(event):
729        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
730        histList = GetHistsLikeSelected(G2frame)
731        if not histList:
732            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
733            return
734        copyList = []
735        dlg = G2gd.G2MultiChoiceDialog(
736            G2frame.dataFrame, 
737            'Copy bkg params from\n'+str(hst[5:])+' to...',
738            'Copy parameters', histList)
739        try:
740            if dlg.ShowModal() == wx.ID_OK:
741                for i in dlg.GetSelections():
742                    copyList.append(histList[i])
743        finally:
744            dlg.Destroy()
745        for item in copyList:
746            Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
747            G2frame.PatternTree.SetItemPyData(
748                G2gd.GetPatternTreeItemId(G2frame,Id,'Background'),copy.copy(data))
749       
750    def BackSizer():
751       
752        def OnNewType(event):
753            data[0][0] = bakType.GetValue()
754           
755        def OnBakRef(event):
756            data[0][1] = bakRef.GetValue()
757           
758        def OnBakTerms(event):
759            data[0][2] = int(bakTerms.GetValue())
760            M = len(data[0])
761            N = data[0][2]+3
762            item = data[0]
763            if N > M:       #add terms
764                for i in range(M,N): 
765                    item.append(0.0)
766            elif N < M:     #delete terms
767                for i in range(N,M):
768                    del(item[-1])
769            G2frame.PatternTree.SetItemPyData(BackId,data)
770            #wx.CallAfter(UpdateBackground,G2frame,data)
771            wx.CallLater(100,UpdateBackground,G2frame,data)
772           
773        def OnBakVal(event):
774            Obj = event.GetEventObject()
775            item = ValObj[Obj.GetId()][0]
776            try:
777                value = float(Obj.GetValue())
778            except ValueError:
779                value = data[0][item]
780            data[0][item] = value
781            Obj.SetValue('%10.4f'%(value))
782       
783        backSizer = wx.BoxSizer(wx.VERTICAL)
784        topSizer = wx.BoxSizer(wx.HORIZONTAL)
785        topSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' Background function: '),0,WACV)
786        bakType = wx.ComboBox(G2frame.dataDisplay,value=data[0][0],
787                choices=Choices,style=wx.CB_READONLY|wx.CB_DROPDOWN)
788        bakType.Bind(wx.EVT_COMBOBOX, OnNewType)
789        topSizer.Add(bakType)
790        topSizer.Add((5,0),0)
791        bakRef = wx.CheckBox(G2frame.dataDisplay,label=' Refine?')
792        bakRef.SetValue(bool(data[0][1]))
793        bakRef.Bind(wx.EVT_CHECKBOX, OnBakRef)
794        topSizer.Add(bakRef,0,WACV)
795        topSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' No. coeff.: '),0,WACV)
796        bakTerms = wx.ComboBox(G2frame.dataDisplay,-1,value=str(data[0][2]),choices=[str(i+1) for i in range(36)],
797            style=wx.CB_READONLY|wx.CB_DROPDOWN)
798        bakTerms.Bind(wx.EVT_COMBOBOX,OnBakTerms)
799        topSizer.Add(bakTerms,0,WACV)
800        topSizer.Add((5,0),0)
801        backSizer.Add(topSizer)
802        backSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' Background coefficients:'),0,WACV)
803        bakSizer = wx.FlexGridSizer(0,5,5,5)
804        for i,value in enumerate(data[0][3:]):
805            bakVal = wx.TextCtrl(G2frame.dataDisplay,wx.ID_ANY,'%10.4f'%(value),style=wx.TE_PROCESS_ENTER)
806            bakSizer.Add(bakVal,0,WACV)
807            ValObj[bakVal.GetId()] = [i+3]
808            bakVal.Bind(wx.EVT_TEXT_ENTER,OnBakVal)
809            bakVal.Bind(wx.EVT_KILL_FOCUS,OnBakVal)
810        backSizer.Add(bakSizer)
811        return backSizer
812       
813    def DebyeSizer():
814       
815        def OnDebTerms(event):
816            data[1]['nDebye'] = int(debTerms.GetValue())
817            M = len(data[1]['debyeTerms'])
818            N = data[1]['nDebye']
819            if N > M:       #add terms
820                for i in range(M,N): 
821                    data[1]['debyeTerms'].append([1.0,False,1.0,False,0.010,False])
822            elif N < M:     #delete terms
823                for i in range(N,M):
824                    del(data[1]['debyeTerms'][-1])
825            #wx.CallAfter(UpdateBackground,G2frame,data)
826            wx.CallLater(100,UpdateBackground,G2frame,data)
827
828        def KeyEditPeakGrid(event):
829            colList = debyeGrid.GetSelectedCols()
830            if event.GetKeyCode() == wx.WXK_RETURN:
831                event.Skip(True)
832            elif event.GetKeyCode() == wx.WXK_CONTROL:
833                event.Skip(True)
834            elif event.GetKeyCode() == wx.WXK_SHIFT:
835                event.Skip(True)
836            elif colList:
837                debyeGrid.ClearSelection()
838                key = event.GetKeyCode()
839                for col in colList:
840                    if debyeTable.GetTypeName(0,col) == wg.GRID_VALUE_BOOL:
841                        if key == 89: #'Y'
842                            for row in range(debyeGrid.GetNumberRows()): data[1]['debyeTerms'][row][col]=True
843                        elif key == 78:  #'N'
844                            for row in range(debyeGrid.GetNumberRows()): data[1]['debyeTerms'][row][col]=False
845
846       
847        debSizer = wx.BoxSizer(wx.VERTICAL)
848        topSizer = wx.BoxSizer(wx.HORIZONTAL)
849        topSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' Debye scattering: '),0,WACV)
850        topSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' No. coeff.: '),0,WACV)
851        debTerms = wx.ComboBox(G2frame.dataDisplay,-1,value=str(data[1]['nDebye']),choices=[str(i) for i in range(12)],
852            style=wx.CB_READONLY|wx.CB_DROPDOWN)
853        debTerms.Bind(wx.EVT_COMBOBOX,OnDebTerms)
854        topSizer.Add(debTerms,0,WACV)
855        topSizer.Add((5,0),0)
856        debSizer.Add(topSizer)
857        if data[1]['nDebye']:
858            debSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' Debye diffuse terms:'),0,WACV)       
859            rowLabels = []
860            for i in range(len(data[1]['debyeTerms'])): rowLabels.append(str(i))
861            colLabels = ['A','refine','R','refine','U','refine']
862            Types = [wg.GRID_VALUE_FLOAT+':10,2',wg.GRID_VALUE_BOOL,
863            wg.GRID_VALUE_FLOAT+':10,3',wg.GRID_VALUE_BOOL,
864            wg.GRID_VALUE_FLOAT+':10,5',wg.GRID_VALUE_BOOL]
865            debyeTable = G2gd.Table(data[1]['debyeTerms'],rowLabels=rowLabels,colLabels=colLabels,types=Types)
866            debyeGrid = G2gd.GSGrid(parent=G2frame.dataDisplay)
867            debyeGrid.SetTable(debyeTable, True)
868            debyeGrid.Bind(wx.EVT_KEY_DOWN, KeyEditPeakGrid)
869            debyeGrid.AutoSizeColumns(False)
870            debSizer.Add(debyeGrid)       
871        return debSizer
872     
873    def PeaksSizer():
874
875        def OnPeaks(event):
876            data[1]['nPeaks'] = int(peaks.GetValue())
877            M = len(data[1]['peaksList'])
878            N = data[1]['nPeaks']
879            if N > M:       #add terms
880                for i in range(M,N): 
881                    data[1]['peaksList'].append([1.0,False,1.0,False,0.10,False,0.10,False])
882            elif N < M:     #delete terms
883                for i in range(N,M):
884                    del(data[1]['peaksList'][-1])
885            #wx.CallAfter(UpdateBackground,G2frame,data)
886            wx.CallLater(100,UpdateBackground,G2frame,data)
887           
888        def KeyEditPeakGrid(event):
889            colList = peaksGrid.GetSelectedCols()
890            if event.GetKeyCode() == wx.WXK_RETURN:
891                event.Skip(True)
892            elif event.GetKeyCode() == wx.WXK_CONTROL:
893                event.Skip(True)
894            elif event.GetKeyCode() == wx.WXK_SHIFT:
895                event.Skip(True)
896            elif colList:
897                peaksGrid.ClearSelection()
898                key = event.GetKeyCode()
899                for col in colList:
900                    if peaksTable.GetTypeName(0,col) == wg.GRID_VALUE_BOOL:
901                        if key == 89: #'Y'
902                            for row in range(peaksGrid.GetNumberRows()): data[1]['peaksList'][row][col]=True
903                        elif key == 78:  #'N'
904                            for row in range(peaksGrid.GetNumberRows()): data[1]['peaksList'][row][col]=False
905
906        peaksSizer = wx.BoxSizer(wx.VERTICAL)
907        topSizer = wx.BoxSizer(wx.HORIZONTAL)
908        topSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' Peaks in background: '),0,WACV)
909        topSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' No. peaks: '),0,WACV)
910        peaks = wx.ComboBox(G2frame.dataDisplay,-1,value=str(data[1]['nPeaks']),choices=[str(i) for i in range(12)],
911            style=wx.CB_READONLY|wx.CB_DROPDOWN)
912        peaks.Bind(wx.EVT_COMBOBOX,OnPeaks)
913        topSizer.Add(peaks,0,WACV)
914        topSizer.Add((5,0),0)
915        peaksSizer.Add(topSizer)
916        if data[1]['nPeaks']:
917            peaksSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' Peak list:'),0,WACV)       
918            rowLabels = []
919            for i in range(len(data[1]['peaksList'])): rowLabels.append(str(i))
920            colLabels = ['pos','refine','int','refine','sig','refine','gam','refine']
921            Types = [wg.GRID_VALUE_FLOAT+':10,2',wg.GRID_VALUE_BOOL,
922            wg.GRID_VALUE_FLOAT+':10,3',wg.GRID_VALUE_BOOL,
923            wg.GRID_VALUE_FLOAT+':10,3',wg.GRID_VALUE_BOOL,
924            wg.GRID_VALUE_FLOAT+':10,5',wg.GRID_VALUE_BOOL]
925            peaksTable = G2gd.Table(data[1]['peaksList'],rowLabels=rowLabels,colLabels=colLabels,types=Types)
926            peaksGrid = G2gd.GSGrid(parent=G2frame.dataDisplay)
927            peaksGrid.SetTable(peaksTable, True)
928            peaksGrid.Bind(wx.EVT_KEY_DOWN, KeyEditPeakGrid)
929            peaksGrid.AutoSizeColumns(False)
930            peaksSizer.Add(peaksGrid)       
931        return peaksSizer
932               
933    if G2frame.dataDisplay:
934#        G2frame.dataFrame.Clear()
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        G2gd.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 = G2gd.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 = G2gd.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 = G2gd.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 = G2gd.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 = G2gd.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 = G2gd.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 = G2gd.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        G2gd.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 = G2gd.G2CheckBox(G2frame.dataDisplay,' '+lbl,data[key],1)
1960            parmSizer.Add(parmRef,0,WACV|wx.EXPAND)
1961            parmVal = G2gd.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 = G2gd.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 = G2gd.ValidatedTxtCtrl(G2frame.dataDisplay,Controls,key,typeHint=str,
1977                                        notBlank=False)
1978        parmSizer.Add(parmVal,1,wx.EXPAND)
1979        parmVal = G2gd.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    IndexId = G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Index Peak List')
2036    Inst = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Instrument Parameters'))[0]
2037    def RefreshIndexPeaksGrid(event):
2038        r,c =  event.GetRow(),event.GetCol()
2039        peaks = G2frame.IndexPeaksTable.GetData()
2040        if c == 2:
2041            if peaks[r][c]:
2042                peaks[r][c] = False
2043            else:
2044                peaks[r][c] = True
2045            G2frame.IndexPeaksTable.SetData(peaks)
2046            G2frame.PatternTree.SetItemPyData(IndexId,[peaks,data[1]])
2047            G2frame.dataDisplay.ForceRefresh()
2048           
2049    def OnReload(event):
2050        peaks = []
2051        sigs = []
2052        Peaks = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Peak List'))
2053        for ip,peak in enumerate(Peaks['peaks']):
2054            dsp = G2lat.Pos2dsp(Inst,peak[0])
2055            peaks.append([peak[0],peak[2],True,False,0,0,0,dsp,0.0])    #SS?
2056            try:
2057                sig = Peaks['sigDict']['pos'+str(ip)]
2058            except KeyError:
2059                sig = 0.
2060            sigs.append(sig)
2061        data = [peaks,sigs]
2062        G2frame.PatternTree.SetItemPyData(IndexId,data)
2063        UpdateIndexPeaksGrid(G2frame,data)
2064       
2065    def KeyEditPickGrid(event):
2066        colList = G2frame.dataDisplay.GetSelectedCols()
2067        rowList = G2frame.dataDisplay.GetSelectedRows()
2068        data = G2frame.PatternTree.GetItemPyData(IndexId)
2069        if event.GetKeyCode() == wx.WXK_RETURN:
2070            event.Skip(True)
2071        elif event.GetKeyCode() == wx.WXK_CONTROL:
2072            event.Skip(True)
2073        elif event.GetKeyCode() == wx.WXK_SHIFT:
2074            event.Skip(True)
2075        elif colList:
2076            G2frame.dataDisplay.ClearSelection()
2077            key = event.GetKeyCode()
2078            for col in colList:
2079                if G2frame.IndexPeaksTable.GetColLabelValue(col) in ['use','refine']:
2080                    if key == 89: #'Y'
2081                        for row in range(G2frame.IndexPeaksTable.GetNumberRows()): data[0][row][col]=True
2082                    elif key == 78:  #'N'
2083                        for row in range(G2frame.IndexPeaksTable.GetNumberRows()): data[0][row][col]=False
2084           
2085    if G2frame.dataDisplay:
2086        G2frame.dataFrame.Clear()
2087    if not G2frame.dataFrame.GetStatusBar():
2088        Status = G2frame.dataFrame.CreateStatusBar()
2089    if 'PWD' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
2090        G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.IndPeaksMenu)
2091        G2frame.Bind(wx.EVT_MENU, OnReload, id=G2gd.wxID_INDXRELOAD)
2092    G2frame.dataFrame.IndexPeaks.Enable(False)
2093    G2frame.IndexPeaksTable = []
2094    if len(data[0]):
2095        G2frame.dataFrame.IndexPeaks.Enable(True)
2096        cells = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Unit Cells List'))
2097        if cells:   #what if SS?
2098            cellist = cells[2]
2099            dmin = cells[3]
2100            G2frame.HKL = []
2101            for i,cell in enumerate(cellist):
2102                if cell[-1]:        #selected cell from table - no SS
2103                    ibrav = cell[2]
2104                    A = G2lat.cell2A(cell[3:9])
2105                    G2frame.HKL = G2lat.GenHBravais(dmin,ibrav,A)
2106                    G2indx.IndexPeaks(data[0],G2frame.HKL)
2107                    for hkl in G2frame.HKL:
2108                        hkl.append(G2lat.Dsp2pos(Inst,hkl[3]))
2109    rowLabels = []
2110    for i in range(len(data[0])): rowLabels.append(str(i+1))
2111    colLabels = ['position','intensity','use','indexed','h','k','l','d-obs','d-calc']
2112    Types = [wg.GRID_VALUE_FLOAT+':10,4',wg.GRID_VALUE_FLOAT+':10,1',]+2*[wg.GRID_VALUE_BOOL,]+ \
2113        3*[wg.GRID_VALUE_LONG,]+2*[wg.GRID_VALUE_FLOAT+':10,5',]
2114    if len(data[0][0]) > 9:
2115        colLabels = ['position','intensity','use','indexed','h','k','l','m','d-obs','d-calc']
2116        Types = [wg.GRID_VALUE_FLOAT+':10,4',wg.GRID_VALUE_FLOAT+':10,1',]+2*[wg.GRID_VALUE_BOOL,]+ \
2117            4*[wg.GRID_VALUE_LONG,]+2*[wg.GRID_VALUE_FLOAT+':10,5',]
2118    G2frame.PatternTree.SetItemPyData(IndexId,data)
2119    G2frame.IndexPeaksTable = G2gd.Table(data[0],rowLabels=rowLabels,colLabels=colLabels,types=Types)
2120    G2frame.dataFrame.SetLabel('Index Peak List')
2121    G2frame.dataDisplay = G2gd.GSGrid(parent=G2frame.dataFrame)               
2122    G2frame.dataDisplay.SetTable(G2frame.IndexPeaksTable, True)
2123    XY = []
2124    Sigs = []
2125    for r in range(G2frame.dataDisplay.GetNumberRows()):
2126        for c in range(G2frame.dataDisplay.GetNumberCols()):
2127            if c == 2:
2128                G2frame.dataDisplay.SetReadOnly(r,c,isReadOnly=False)
2129            else:
2130                G2frame.dataDisplay.SetReadOnly(r,c,isReadOnly=True)
2131        if data[0][r][2] and data[0][r][3]:
2132            XY.append([data[0][r][-1],data[0][r][0]])
2133            try:
2134                sig = data[1][r]
2135            except IndexError:
2136                sig = 0.
2137            Sigs.append(sig)
2138    G2frame.dataDisplay.Bind(wg.EVT_GRID_CELL_LEFT_CLICK, RefreshIndexPeaksGrid)
2139    G2frame.dataDisplay.Bind(wx.EVT_KEY_DOWN, KeyEditPickGrid)                 
2140    G2frame.dataDisplay.SetMargins(0,0)
2141    G2frame.dataDisplay.AutoSizeColumns(False)
2142    G2frame.dataFrame.setSizePosLeft([490,300])
2143    if len(XY):
2144        XY = np.array(XY)
2145        G2plt.PlotCalib(G2frame,Inst,XY,Sigs,newPlot=True)
2146    G2frame.dataFrame.SendSizeEvent()
2147     
2148################################################################################
2149#####  Unit cells
2150################################################################################           
2151       
2152def UpdateUnitCellsGrid(G2frame, data):
2153    '''respond to selection of PWDR Unit Cells data tree item.
2154    '''
2155    UnitCellsId = G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Unit Cells List')
2156    SPGlist = G2spc.spglist
2157    bravaisSymb = ['Fm3m','Im3m','Pm3m','R3-H','P6/mmm','I4/mmm',
2158        'P4/mmm','Fmmm','Immm','Cmmm','Pmmm','C2/m','P2/m','P1']
2159    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',
2160        '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']
2161    Inst = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Instrument Parameters'))[0]
2162    if 'C' in Inst['Type'][0]:
2163        wave = G2mth.getWave(Inst)
2164    else:
2165        difC = Inst['difC'][1]
2166   
2167    def SetLattice(controls):
2168        ibrav = bravaisSymb.index(controls[5])
2169        if ibrav in [0,1,2]:
2170            controls[7] = controls[8] = controls[6]
2171            controls[9] = controls[10] = controls[11] = 90.
2172        elif ibrav in [3,4,5,6]:
2173            controls[7] = controls[6]
2174            controls[9] = controls[10] = controls[11] = 90.
2175            if ibrav in [3,4]:
2176                controls[11] = 120.
2177        elif ibrav in [7,8,9,10]:
2178            controls[9] = controls[10] = controls[11] = 90.
2179        elif ibrav in [11,12]:
2180            controls[9] = controls[11] = 90.  # b unique
2181        if len(controls) < 13: controls.append(0)
2182        controls[12] = G2lat.calc_V(G2lat.cell2A(controls[6:12]))
2183        return ibrav
2184       
2185    def OnNcNo(event):
2186        controls[2] = NcNo.GetValue()
2187       
2188    def OnStartVol(event):
2189        try:
2190            stVol = int(float(startVol.GetValue()))
2191            if stVol < 25:
2192                raise ValueError
2193        except ValueError:
2194            stVol = 25
2195        controls[3] = stVol
2196        startVol.SetValue("%d"%(stVol))
2197       
2198    def OnBravais(event):
2199        Obj = event.GetEventObject()
2200        bravais[bravList.index(Obj.GetId())] = Obj.GetValue()
2201       
2202    def OnZero(event):
2203        try:
2204            Zero = min(5.0,max(-5.0,float(zero.GetValue())))
2205        except ValueError:
2206            Zero = 0.0
2207        controls[1] = Zero
2208        zero.SetValue("%.4f"%(Zero))
2209       
2210    def OnZeroVar(event):
2211        controls[0] = zeroVar.GetValue()
2212       
2213    def OnSSopt(event):
2214        if controls[5] in ['Fm3m','Im3m','Pm3m']:
2215            SSopt.SetValue(False)
2216            G2frame.ErrorDialog('Cubic lattice', 'Superlattice not allowed for a cubic lattice')
2217            return
2218        ssopt['Use'] = SSopt.GetValue()
2219        wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)
2220       
2221    def OnSelMG(event):
2222        ssopt['ssSymb'] = selMG.GetValue()
2223        Vec = ssopt['ModVec']
2224        modS = G2spc.splitSSsym(ssopt['ssSymb'])[0]
2225        ssopt['ModVec'] = G2spc.SSGModCheck(Vec,modS)[0]
2226        OnHklShow(event)
2227        wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)
2228       
2229    def OnModVal(event):
2230        Obj = event.GetEventObject()
2231        ObjId = Obj.GetId()
2232        Id = Indx[ObjId]
2233        try:
2234            value = min(1.0,max(0.,float(Obj.GetValue())))
2235        except ValueError:
2236            value = ssopt['ModVec'][Id]
2237        Obj.SetValue('%.4f'%(value))
2238        ssopt['ModVec'][Id] = value
2239        OnHklShow(event)
2240       
2241    def OnMoveMod(event):
2242        Obj = event.GetEventObject()
2243        ObjId = Obj.GetId()
2244        Id,valObj = Indx[ObjId]
2245        move = Obj.GetValue()*0.002
2246        Obj.SetValue(0)
2247        value = min(1.0,max(.0,float(valObj.GetValue())+move))
2248        valObj.SetValue('%.4f'%(value)) 
2249        ssopt['ModVec'][Id] = value
2250        OnHklShow(event)
2251       
2252    def OnMaxMH(event):
2253        ssopt['maxH'] = int(maxMH.GetValue())
2254        OnHklShow(event)
2255       
2256    def OnBravSel(event):
2257        brav = bravSel.GetString(bravSel.GetSelection())
2258        controls[5] = brav
2259        controls[13] = SPGlist[brav][0]       
2260        wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)
2261       
2262    def OnSpcSel(event):
2263        controls[13] = spcSel.GetString(spcSel.GetSelection())
2264       
2265    def SetCellValue(Obj,ObjId,value):
2266        ibrav = bravaisSymb.index(controls[5])
2267        if ibrav in [0,1,2]:
2268            controls[6] = controls[7] = controls[8] = value
2269            controls[9] = controls[10] = controls[11] = 90.0
2270            Obj.SetValue("%.5f"%(controls[6]))
2271        elif ibrav in [3,4,5,6]:
2272            if ObjId == 0:
2273                controls[6] = controls[7] = value
2274                Obj.SetValue("%.5f"%(controls[6]))
2275            else:
2276                controls[8] = value
2277                Obj.SetValue("%.5f"%(controls[8]))
2278            controls[9] = controls[10] = controls[11] = 90.0
2279            if ibrav in [3,4]:
2280                controls[11] = 120.
2281        elif ibrav in [7,8,9,10]:
2282            controls[6+ObjId] = value
2283            Obj.SetValue("%.5f"%(controls[6+ObjId]))
2284            controls[9] = controls[10] = controls[11] = 90.0
2285        elif ibrav in [11,12]:
2286            controls[9] = controls[11] = 90.0
2287            if ObjId != 3:
2288                controls[6+ObjId] = value
2289                Obj.SetValue("%.5f"%(controls[6+ObjId]))
2290            else:
2291                controls[10] = value
2292                Obj.SetValue("%.3f"%(controls[10]))
2293        else:
2294            controls[6+ObjId] = value
2295            if ObjId < 3:
2296                Obj.SetValue("%.5f"%(controls[6+ObjId]))
2297            else:
2298                Obj.SetValue("%.3f"%(controls[6+ObjId]))
2299        controls[12] = G2lat.calc_V(G2lat.cell2A(controls[6:12]))
2300        volVal.SetValue("%.3f"%(controls[12]))
2301       
2302    def OnMoveCell(event):
2303        Obj = event.GetEventObject()
2304        ObjId = cellList.index(Obj.GetId())
2305        valObj = valDict[Obj.GetId()]
2306        if ObjId/2 < 3:
2307            move = Obj.GetValue()*0.01
2308        else:
2309            move = Obj.GetValue()*0.1
2310        Obj.SetValue(0)
2311        value = float(valObj.GetValue())+move 
2312        SetCellValue(valObj,ObjId/2,value)
2313        OnHklShow(event)
2314       
2315    def OnCellChange(event):
2316        Obj = event.GetEventObject()
2317        ObjId = cellList.index(Obj.GetId())
2318        try:
2319            value = max(1.0,float(Obj.GetValue()))
2320        except ValueError:
2321            if ObjId/2 < 3:               #bad cell edge - reset
2322                value = controls[6+ObjId/2]
2323            else:                       #bad angle
2324                value = 90.
2325        SetCellValue(Obj,ObjId/2,value)
2326       
2327    def OnHklShow(event):
2328        PatternId = G2frame.PatternId
2329        PickId = G2frame.PickId   
2330        peaks = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Index Peak List'))[0]
2331        limits = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Limits'))[1]
2332        controls,bravais,cells,dmin,ssopt = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Unit Cells List'))
2333        cell = controls[6:12]
2334        A = G2lat.cell2A(cell)
2335        ibrav = bravaisSymb.index(controls[5])
2336        spc = controls[13]
2337        SGData = G2spc.SpcGroup(spc)[1]
2338        if 'C' in Inst['Type'][0]:
2339            dmin = G2lat.Pos2dsp(Inst,limits[1])
2340        else:   #TOF - use other limit!
2341            dmin = G2lat.Pos2dsp(Inst,limits[0])
2342        if ssopt.get('Use',False):
2343            SSGData = G2spc.SSpcGroup(SGData,ssopt['ssSymb'])
2344            Vec = ssopt['ModVec']
2345            maxH = ssopt['maxH']
2346            G2frame.HKL = G2pwd.getHKLMpeak(dmin,SGData,SSGData,Vec,maxH,A)
2347        else:
2348            G2frame.HKL = G2pwd.getHKLpeak(dmin,SGData,A)
2349        G2indx.IndexPeaks(peaks,G2frame.HKL)
2350        for peak in peaks: print peak
2351        for hkl in G2frame.HKL:
2352            hkl.append(G2lat.Dsp2pos(Inst,hkl[-2])+controls[1])
2353        if 'PKS' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
2354            G2plt.PlotPowderLines(G2frame)
2355        else:
2356            G2plt.PlotPatterns(G2frame)
2357           
2358    def OnSortCells(event):
2359        controls,bravais,cells,dmin,ssopt = G2frame.PatternTree.GetItemPyData(UnitCellsId)
2360        c =  event.GetCol()
2361        if colLabels[c] == 'M20':
2362            cells = G2indx.sortM20(cells)
2363        elif colLabels[c] == 'Volume':
2364            cells = G2indx.sortVolume(cells)
2365        else:
2366            return
2367        data = [controls,bravais,cells,dmin,ssopt]
2368        G2frame.PatternTree.SetItemPyData(UnitCellsId,data)
2369        wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)
2370       
2371    def CopyUnitCell(event):
2372        controls,bravais,cells,dmin,ssopt = G2frame.PatternTree.GetItemPyData(UnitCellsId)
2373        for Cell in cells:
2374            if Cell[-2]:
2375                break
2376        cell = Cell[2:9]
2377        controls[4] = 1
2378        controls[5] = bravaisSymb[cell[0]]
2379        controls[6:12] = cell[1:8]
2380        controls[12] = G2lat.calc_V(G2lat.cell2A(controls[6:12]))
2381        controls[13] = spaceGroups[bravaisSymb.index(controls[5])]
2382        G2frame.PatternTree.SetItemPyData(UnitCellsId,[controls,bravais,cells,dmin,ssopt])
2383        G2frame.dataFrame.RefineCell.Enable(True)
2384        wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)       
2385               
2386    def RefineCell(event):
2387        def cellPrint(ibrav,A):
2388            cell = G2lat.A2cell(A)
2389            Vol = G2lat.calc_V(A)
2390            if ibrav in [0,1,2]:
2391                print "%s%10.6f" % ('a =',cell[0])
2392            elif ibrav in [3,4,5,6]:
2393                print "%s%10.6f %s%10.6f %s%12.3f" % ('a =',cell[0],' c =',cell[2],' volume =',Vol)
2394            elif ibrav in [7,8,9,10]:
2395                print "%s%10.6f %s%10.6f %s%10.6f %s%12.3f" % ('a =',cell[0],'b =',cell[1],'c =',cell[2],' volume =',Vol)
2396            elif ibrav in [11,12]:
2397                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)
2398            else:
2399                print "%s%10.6f %s%10.6f %s%10.6f" % ('a =',cell[0],'b =',cell[1],'c =',cell[2])
2400                print "%s%8.3f %s%8.3f %s%8.3f %s%12.3f" % ('alpha =',cell[3],'beta =',cell[4],'gamma =',cell[5],' volume =',Vol)
2401             
2402        PatternId = G2frame.PatternId
2403        PickId = G2frame.PickId   
2404        peaks = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Index Peak List'))
2405        if not peaks[0]:
2406            G2frame.ErrorDialog('No peaks!', 'Nothing to refine!')
2407            return       
2408        print 'Refine cell'
2409        controls,bravais,cells,dmin,ssopt = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Unit Cells List'))
2410        cell = controls[6:12]
2411        A = G2lat.cell2A(cell)
2412        ibrav = bravaisSymb.index(controls[5])
2413        SGData = G2spc.SpcGroup(controls[13])[1]
2414        dmin = G2indx.getDmin(peaks[0])-0.005
2415        G2frame.HKL = G2pwd.getHKLpeak(dmin,SGData,A)
2416        G2indx.IndexPeaks(peaks[0],G2frame.HKL)
2417        if 'C' in Inst['Type'][0]:
2418            Lhkl,M20,X20,Aref,Zero = G2indx.refinePeaksZ(peaks[0],wave,ibrav,A,controls[1],controls[0])
2419        else:   #'T'OF
2420            Lhkl,M20,X20,Aref,Zero = G2indx.refinePeaksT(peaks[0],difC,ibrav,A,controls[1],controls[0])           
2421        controls[1] = Zero
2422        controls[6:12] = G2lat.A2cell(Aref)
2423        controls[12] = G2lat.calc_V(Aref)
2424        data = [controls,bravais,cells,dmin,ssopt]
2425        cells = G2frame.PatternTree.GetItemPyData(UnitCellsId)[2]
2426        for cell in cells:
2427            cell[-2] = False
2428        cells.insert(0,[M20,X20,ibrav]+controls[6:13]+[True,False])
2429        data[2] = cells
2430        G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Unit Cells List'),data)
2431        G2frame.HKL = G2lat.GenHBravais(dmin,ibrav,Aref)
2432        print "%s%10.3f" % ('refinement M20 = ',M20)
2433        print 'unindexed lines = ',X20
2434        cellPrint(ibrav,Aref)
2435        for hkl in G2frame.HKL:
2436            hkl.append(G2lat.Dsp2pos(Inst,hkl[3])+controls[1])
2437        if 'PKS' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
2438            G2plt.PlotPowderLines(G2frame)
2439        else:
2440            G2plt.PlotPatterns(G2frame)
2441        wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)
2442       
2443    def IndexPeaks(event):
2444        PatternId = G2frame.PatternId   
2445        print 'Peak Indexing'
2446        keepcells = []
2447        try:
2448            controls,bravais,cells,dmin,ssopt = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Unit Cells List'))
2449            for cell in cells:
2450                if cell[11]:
2451                    keepcells.append(cell)
2452        except IndexError:
2453            pass
2454        except ValueError:
2455            G2frame.ErrorDialog('Error','Need to set controls in Unit Cell List first')
2456            return
2457        if True not in bravais:
2458            G2frame.ErrorDialog('Error','No Bravais lattices selected')
2459            return
2460        G2frame.dataFrame.CopyCell.Enable(False)
2461        G2frame.dataFrame.RefineCell.Enable(False)
2462        OK,dmin,newcells = G2indx.DoIndexPeaks(peaks[0],controls,bravais)
2463        cells = keepcells+newcells
2464        cells = G2indx.sortM20(cells)
2465        cells[0][10] = True
2466        if OK:
2467            data = [controls,bravais,cells,dmin,ssopt]
2468            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Unit Cells List'),data)
2469            bestCell = cells[0]
2470            if bestCell[0] > 10.:
2471                G2frame.HKL = G2lat.GenHBravais(dmin,bestCell[2],G2lat.cell2A(bestCell[3:9]))
2472                for hkl in G2frame.HKL:
2473                    hkl.append(G2lat.Dsp2pos(Inst,hkl[3])+controls[1])
2474                if 'PKS' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
2475                    G2plt.PlotPowderLines(G2frame)
2476                else:
2477                    G2plt.PlotPatterns(G2frame)
2478            G2frame.dataFrame.CopyCell.Enable(True)
2479            G2frame.dataFrame.IndexPeaks.Enable(True)
2480            G2frame.dataFrame.MakeNewPhase.Enable(True)
2481        wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)
2482               
2483    def RefreshUnitCellsGrid(event):
2484        data =G2frame.PatternTree.GetItemPyData(UnitCellsId)
2485        cells,dmin = data[2:4]
2486        r,c =  event.GetRow(),event.GetCol()
2487        if cells:
2488            if c == 2:
2489                for i in range(len(cells)):
2490                    cells[i][-2] = False
2491                    UnitCellsTable.SetValue(i,c,False)
2492                UnitCellsTable.SetValue(r,c,True)
2493                gridDisplay.ForceRefresh()
2494                cells[r][-2] = True
2495                ibrav = cells[r][2]
2496                A = G2lat.cell2A(cells[r][3:9])
2497                G2frame.HKL = G2lat.GenHBravais(dmin,ibrav,A)
2498                for hkl in G2frame.HKL:
2499                    hkl.append(G2lat.Dsp2pos(Inst,hkl[3])+controls[1])
2500                if 'PKS' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
2501                    G2plt.PlotPowderLines(G2frame)
2502                else:
2503                    G2plt.PlotPatterns(G2frame)
2504            elif c == 11:
2505                if UnitCellsTable.GetValue(r,c):
2506                    UnitCellsTable.SetValue(r,c,False)
2507                    cells[r][c] = False
2508                else:
2509                    cells[r][c] = True
2510                    UnitCellsTable.SetValue(r,c,True)
2511                gridDisplay.ForceRefresh()
2512            G2frame.PatternTree.SetItemPyData(UnitCellsId,data)               
2513       
2514    def MakeNewPhase(event):
2515        if not G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Phases'):
2516            sub = G2frame.PatternTree.AppendItem(parent=G2frame.root,text='Phases')
2517        else:
2518            sub = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Phases')
2519        PhaseName = ''
2520        dlg = wx.TextEntryDialog(None,'Enter a name for this phase','Phase Name Entry','New phase',
2521            style=wx.OK)
2522        try:
2523            if dlg.ShowModal() == wx.ID_OK:
2524                PhaseName = dlg.GetValue()
2525                cells = G2frame.PatternTree.GetItemPyData(UnitCellsId)[2]
2526                for Cell in cells:
2527                    if Cell[-2]:
2528                        break
2529                cell = Cell[2:10]       
2530                sub = G2frame.PatternTree.AppendItem(parent=sub,text=PhaseName)
2531                E,SGData = G2spc.SpcGroup(controls[13])
2532                G2frame.PatternTree.SetItemPyData(sub, \
2533                    G2IO.SetNewPhase(Name=PhaseName,SGData=SGData,cell=cell[1:]))
2534                Status.SetStatusText('Change space group from '+str(controls[13])+' if needed')
2535        finally:
2536            dlg.Destroy()
2537           
2538    if G2frame.dataDisplay:
2539        G2frame.dataFrame.Clear()
2540    G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.IndexMenu)
2541    if not G2frame.dataFrame.GetStatusBar():
2542        Status = G2frame.dataFrame.CreateStatusBar()
2543    G2frame.Bind(wx.EVT_MENU, IndexPeaks, id=G2gd.wxID_INDEXPEAKS)
2544    G2frame.Bind(wx.EVT_MENU, CopyUnitCell, id=G2gd.wxID_COPYCELL)
2545    G2frame.Bind(wx.EVT_MENU, RefineCell, id=G2gd.wxID_REFINECELL)
2546    G2frame.Bind(wx.EVT_MENU, MakeNewPhase, id=G2gd.wxID_MAKENEWPHASE)
2547   
2548    controls,bravais,cells,dmin,ssopt = data
2549    if len(controls) < 13:              #add cell volume if missing
2550        controls.append(G2lat.calc_V(G2lat.cell2A(controls[6:12])))
2551    if len(controls) < 14:              #add space gropu used in indexing
2552        controls.append(spaceGroups[bravaisSymb.index(controls[5])])
2553    G2frame.PatternTree.SetItemPyData(UnitCellsId,data)            #update with volume
2554    bravaisNames = ['Cubic-F','Cubic-I','Cubic-P','Trigonal-R','Trigonal/Hexagonal-P',
2555        'Tetragonal-I','Tetragonal-P','Orthorhombic-F','Orthorhombic-I','Orthorhombic-C',
2556        'Orthorhombic-P','Monoclinic-C','Monoclinic-P','Triclinic']
2557    cellGUIlist = [[[0,1,2],4,zip([" Unit cell: a = "," Vol = "],["%.5f","%.3f"],[True,False],[0,0])],
2558    [[3,4,5,6],6,zip([" Unit cell: a = "," c = "," Vol = "],["%.5f","%.5f","%.3f"],[True,True,False],[0,2,0])],
2559    [[7,8,9,10],8,zip([" Unit cell: a = "," b = "," c = "," Vol = "],["%.5f","%.5f","%.5f","%.3f"],
2560        [True,True,True,False],[0,1,2,0])],
2561    [[11,12],10,zip([" Unit cell: a = "," b = "," c = "," beta = "," Vol = "],
2562        ["%.5f","%.5f","%.5f","%.3f","%.3f"],[True,True,True,True,False],[0,1,2,4,0])],
2563    [[13,],8,zip([" Unit cell: a = "," b = "," c = "," Vol = "," alpha = "," beta = "," gamma = "],
2564        ["%.5f","%.5f","%.5f","%.3f","%.3f","%.3f","%.3f"],
2565        [True,True,True,False,True,True,True],[0,1,2,0,3,4,5])]]
2566   
2567    G2frame.dataFrame.SetLabel('Unit Cells List')
2568    G2frame.sp = wx.SplitterWindow(G2frame.dataFrame)
2569    G2frame.dataDisplay = wx.Panel(G2frame.sp, style=wx.SUNKEN_BORDER)
2570    G2frame.dataFrame.IndexPeaks.Enable(False)
2571    peaks = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Index Peak List'))
2572    if peaks:
2573        G2frame.dataFrame.IndexPeaks.Enable(True)
2574    G2frame.dataFrame.RefineCell.Enable(False)
2575    if controls[12] > 1.0:                               #if a "real" volume (i.e. not default)
2576        G2frame.dataFrame.RefineCell.Enable(True)   
2577    G2frame.dataFrame.CopyCell.Enable(False)
2578    G2frame.dataFrame.MakeNewPhase.Enable(False)       
2579    if cells:
2580        G2frame.bottom = wx.Panel(G2frame.sp, style=wx.SUNKEN_BORDER)
2581        G2frame.sp.SplitHorizontally(G2frame.dataDisplay,G2frame.bottom,0)
2582        G2frame.dataFrame.CopyCell.Enable(True)
2583        G2frame.dataFrame.MakeNewPhase.Enable(True)       
2584    mainSizer = wx.BoxSizer(wx.VERTICAL)
2585    mainSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Indexing controls: '),0,WACV)
2586    mainSizer.Add((5,5),0)
2587    littleSizer = wx.FlexGridSizer(0,5,5,5)
2588    littleSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Max Nc/Nobs '),0,WACV)
2589    NcNo = wx.SpinCtrl(G2frame.dataDisplay)
2590    NcNo.SetRange(2,6)
2591    NcNo.SetValue(controls[2])
2592    NcNo.Bind(wx.EVT_SPINCTRL,OnNcNo)
2593    littleSizer.Add(NcNo,0,WACV)
2594    littleSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Start Volume '),0,WACV)
2595    startVol = wx.TextCtrl(G2frame.dataDisplay,value=str('%d'%(controls[3])),style=wx.TE_PROCESS_ENTER)
2596    startVol.Bind(wx.EVT_TEXT_ENTER,OnStartVol)
2597    startVol.Bind(wx.EVT_KILL_FOCUS,OnStartVol)
2598    littleSizer.Add(startVol,0,WACV)
2599    mainSizer.Add(littleSizer,0)
2600    mainSizer.Add((5,5),0)
2601    mainSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Select Bravais Lattices for indexing: '),
2602        0,WACV)
2603    mainSizer.Add((5,5),0)
2604    littleSizer = wx.FlexGridSizer(0,7,5,5)
2605    bravList = []
2606    bravs = zip(bravais,bravaisNames)
2607    for brav,bravName in bravs:
2608        bravCk = wx.CheckBox(G2frame.dataDisplay,label=bravName)
2609        bravList.append(bravCk.GetId())
2610        bravCk.SetValue(brav)
2611        bravCk.Bind(wx.EVT_CHECKBOX,OnBravais)
2612        littleSizer.Add(bravCk,0,WACV)
2613    mainSizer.Add(littleSizer,0)
2614    mainSizer.Add((5,5),0)
2615   
2616    mainSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Cell Refinement: '),0,WACV)
2617    mainSizer.Add((5,5),0)
2618    littleSizer = wx.BoxSizer(wx.HORIZONTAL)
2619    littleSizer.Add(wx.StaticText(G2frame.dataDisplay,label=" Bravais lattice "),0,WACV)
2620    bravSel = wx.Choice(G2frame.dataDisplay,choices=bravaisSymb)
2621    bravSel.SetSelection(bravaisSymb.index(controls[5]))
2622    bravSel.Bind(wx.EVT_CHOICE,OnBravSel)
2623    littleSizer.Add(bravSel,0,WACV)
2624    littleSizer.Add(wx.StaticText(G2frame.dataDisplay,label=" Space group "),0,WACV)
2625    spcSel = wx.Choice(G2frame.dataDisplay,choices=SPGlist[controls[5]])
2626    spcSel.SetSelection(SPGlist[controls[5]].index(controls[13]))
2627    spcSel.Bind(wx.EVT_CHOICE,OnSpcSel)
2628    littleSizer.Add(spcSel,0,WACV)
2629    littleSizer.Add(wx.StaticText(G2frame.dataDisplay,label=" Zero offset"),0,WACV)
2630    zero = wx.TextCtrl(G2frame.dataDisplay,value="%.4f"%(controls[1]),style=wx.TE_PROCESS_ENTER)
2631    zero.Bind(wx.EVT_TEXT_ENTER,OnZero)
2632    zero.Bind(wx.EVT_KILL_FOCUS,OnZero)
2633    littleSizer.Add(zero,0,WACV)
2634    zeroVar = wx.CheckBox(G2frame.dataDisplay,label="Refine?")
2635    zeroVar.SetValue(controls[0])
2636    zeroVar.Bind(wx.EVT_CHECKBOX,OnZeroVar)
2637    littleSizer.Add(zeroVar,0,WACV)
2638    SSopt = wx.CheckBox(G2frame.dataDisplay,label="Super lattice?")
2639    SSopt.SetValue(ssopt.get('Use',False))
2640    SSopt.Bind(wx.EVT_CHECKBOX,OnSSopt)
2641    littleSizer.Add(SSopt,0,WACV)
2642    hklShow = wx.Button(G2frame.dataDisplay,label="Show hkl positions")
2643    hklShow.Bind(wx.EVT_BUTTON,OnHklShow)
2644    littleSizer.Add(hklShow,0,WACV)
2645    mainSizer.Add(littleSizer,0)
2646   
2647    mainSizer.Add((5,5),0)
2648    ibrav = SetLattice(controls)
2649    for cellGUI in cellGUIlist:
2650        if ibrav in cellGUI[0]:
2651            useGUI = cellGUI
2652    cellList = []
2653    valDict = {}
2654    littleSizer = wx.FlexGridSizer(0,useGUI[1],5,5)
2655    for txt,fmt,ifEdit,Id in useGUI[2]:
2656        littleSizer.Add(wx.StaticText(G2frame.dataDisplay,label=txt),0,WACV)
2657        if ifEdit:          #a,b,c,etc.
2658            cellVal = wx.TextCtrl(G2frame.dataDisplay,value=(fmt%(controls[6+Id])),style=wx.TE_PROCESS_ENTER)
2659            cellVal.Bind(wx.EVT_TEXT_ENTER,OnCellChange)       
2660            cellVal.Bind(wx.EVT_KILL_FOCUS,OnCellChange)
2661            valSizer = wx.BoxSizer(wx.HORIZONTAL)
2662            valSizer.Add(cellVal,0,WACV)
2663            cellSpin = wx.SpinButton(G2frame.dataDisplay,style=wx.SP_VERTICAL,size=wx.Size(20,20))
2664            cellSpin.SetValue(0)
2665            cellSpin.SetRange(-1,1)
2666            cellSpin.Bind(wx.EVT_SPIN, OnMoveCell)
2667            valSizer.Add(cellSpin,0,WACV)
2668            littleSizer.Add(valSizer,0,WACV)
2669            cellList.append(cellVal.GetId())
2670            cellList.append(cellSpin.GetId())
2671            valDict[cellSpin.GetId()] = cellVal
2672        else:               #volume
2673            volVal = wx.TextCtrl(G2frame.dataDisplay,value=(fmt%(controls[12])),style=wx.TE_READONLY)
2674            volVal.SetBackgroundColour(VERY_LIGHT_GREY)
2675            littleSizer.Add(volVal,0,WACV)
2676    mainSizer.Add(littleSizer,0)
2677    if ssopt.get('Use',False):        #super lattice display
2678        indChoice = ['1','2','3','4',]
2679        SpSg = controls[13]
2680        ssChoice = G2spc.ssdict[SpSg]
2681        if ssopt['ssSymb'] not in ssChoice:
2682            ssopt['ssSymb'] = ssChoice[0]
2683        ssSizer = wx.BoxSizer(wx.HORIZONTAL)
2684        ssSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Supersymmetry space group: '+SpSg+' '),0,WACV)
2685        selMG = wx.ComboBox(G2frame.dataDisplay,value=ssopt['ssSymb'],
2686                choices=ssChoice,style=wx.CB_READONLY|wx.CB_DROPDOWN)
2687        selMG.Bind(wx.EVT_COMBOBOX, OnSelMG)
2688        ssSizer.Add(selMG,0,WACV)
2689        ssSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Mod. vector: '),0,WACV)
2690        modS = G2spc.splitSSsym(ssopt['ssSymb'])[0]
2691        Vec = ssopt['ModVec']
2692        Vec,ifShow = G2spc.SSGModCheck(Vec,modS)
2693        Indx = {}
2694        for i,[val,show] in enumerate(zip(Vec,ifShow)):
2695            if show:
2696                valSizer = wx.BoxSizer(wx.HORIZONTAL)
2697                modVal = wx.TextCtrl(G2frame.dataDisplay,value=('%.4f'%(val)),
2698                    size=wx.Size(50,20),style=wx.TE_PROCESS_ENTER)
2699                modVal.Bind(wx.EVT_TEXT_ENTER,OnModVal)       
2700                modVal.Bind(wx.EVT_KILL_FOCUS,OnModVal)
2701                valSizer.Add(modVal,0,WACV)
2702                modSpin = wx.SpinButton(G2frame.dataDisplay,style=wx.SP_VERTICAL,size=wx.Size(20,20))
2703                modSpin.SetValue(0)
2704                modSpin.SetRange(-1,1)
2705                modSpin.Bind(wx.EVT_SPIN, OnMoveMod)
2706                valSizer.Add(modSpin,0,WACV)
2707                ssSizer.Add(valSizer,0,WACV)
2708                Indx[modVal.GetId()] = i
2709                Indx[modSpin.GetId()] = [i,modVal]
2710            else:
2711                modVal = wx.TextCtrl(G2frame.dataDisplay,value=('%.3f'%(val)),
2712                    size=wx.Size(50,20),style=wx.TE_READONLY)
2713                modVal.SetBackgroundColour(VERY_LIGHT_GREY)
2714                ssSizer.Add(modVal,0,WACV)
2715        ssSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Max. M: '),0,WACV)
2716        maxMH = wx.ComboBox(G2frame.dataDisplay,value=str(ssopt['maxH']),
2717            choices=indChoice,style=wx.CB_READONLY|wx.CB_DROPDOWN)
2718        maxMH.Bind(wx.EVT_COMBOBOX, OnMaxMH)
2719        ssSizer.Add(maxMH,0,WACV)
2720        mainSizer.Add(ssSizer,0)
2721
2722    mainSizer.Layout()   
2723    G2frame.dataDisplay.SetSizer(mainSizer)
2724    topSize = mainSizer.Fit(G2frame.dataFrame)
2725    G2frame.dataDisplay.SetSize(topSize)
2726    if cells:
2727        if ibrav == 13:
2728            topSize[1] += 230
2729        else:
2730            topSize[1] += 200
2731    G2frame.dataFrame.setSizePosLeft(topSize)   
2732   
2733    if cells:
2734        bottomSize = topSize        #screwy but bottom doesn't have a size in linux!
2735        bottomSize[0] -= 20         #to reveal slider
2736        if ibrav == 13:
2737            bottomSize[1] -= 240
2738        else:
2739            bottomSize[1] -= 210
2740        wx.StaticText(parent=G2frame.bottom,label=' Indexing Result ')
2741        rowLabels = []
2742        colLabels = ['M20','X20','use','Bravais','a','b','c','alpha','beta','gamma','Volume','Keep']
2743        Types = [wg.GRID_VALUE_FLOAT+':10,2',wg.GRID_VALUE_NUMBER,wg.GRID_VALUE_BOOL,wg.GRID_VALUE_STRING,]+ \
2744            3*[wg.GRID_VALUE_FLOAT+':10,5',]+3*[wg.GRID_VALUE_FLOAT+':10,3',]+ \
2745            [wg.GRID_VALUE_FLOAT+':10,2',wg.GRID_VALUE_BOOL]
2746        numRows = len(cells)
2747        table = []
2748        for cell in cells:
2749            rowLabels.append('')
2750            row = cell[0:2]+[cell[-2]]+[bravaisSymb[cell[2]]]+cell[3:10]+[cell[11],]
2751            if cell[-2]:
2752                A = G2lat.cell2A(cell[3:9])
2753                G2frame.HKL = G2lat.GenHBravais(dmin,cell[2],A)
2754                for hkl in G2frame.HKL:
2755                    hkl.append(G2lat.Dsp2pos(Inst,hkl[3])+controls[1])
2756            table.append(row)
2757        UnitCellsTable = G2gd.Table(table,rowLabels=rowLabels,colLabels=colLabels,types=Types)
2758        gridDisplay = G2gd.GSGrid(G2frame.bottom)
2759        gridDisplay.SetPosition(wx.Point(0,20))               
2760        gridDisplay.SetTable(UnitCellsTable, True)
2761        G2frame.dataFrame.CopyCell.Enable(True)
2762        gridDisplay.Bind(wg.EVT_GRID_CELL_LEFT_CLICK,RefreshUnitCellsGrid)
2763        gridDisplay.Bind(wg.EVT_GRID_LABEL_LEFT_DCLICK,OnSortCells)
2764        gridDisplay.SetMargins(0,0)
2765        gridDisplay.SetRowLabelSize(0)
2766        gridDisplay.AutoSizeColumns(False)
2767        for r in range(gridDisplay.GetNumberRows()):
2768            for c in range(gridDisplay.GetNumberCols()):
2769                if c == 2:
2770                    gridDisplay.SetReadOnly(r,c,isReadOnly=False)
2771                else:
2772                    gridDisplay.SetReadOnly(r,c,isReadOnly=True)
2773        gridDisplay.SetSize(bottomSize)
2774
2775################################################################################
2776#####  Reflection list
2777################################################################################           
2778       
2779def UpdateReflectionGrid(G2frame,data,HKLF=False,Name=''):
2780    '''respond to selection of PWDR Reflections data tree item.
2781    '''
2782    def OnPlotHKL(event):
2783        FoMax = np.max(refList.T[8+Super])
2784        Hmin = np.array([int(np.min(refList.T[0])),int(np.min(refList.T[1])),int(np.min(refList.T[2]))])
2785        Hmax = np.array([int(np.max(refList.T[0])),int(np.max(refList.T[1])),int(np.max(refList.T[2]))])
2786        controls = {'Type' : 'Fo','ifFc' : True,'HKLmax' : Hmax,'HKLmin' : Hmin,
2787            'FoMax' : FoMax,'Zone' : '001','Layer' : 0,'Scale' : 1.0,'Super':Super,'SuperVec':SuperVec}
2788        G2plt.PlotSngl(G2frame,newPlot=True,Data=controls,hklRef=refList,Title=phaseName)
2789       
2790    def OnPlot3DHKL(event):
2791        FoMax = np.max(refList.T[8+Super])
2792        Hmin = np.array([int(np.min(refList.T[0])),int(np.min(refList.T[1])),int(np.min(refList.T[2]))])
2793        Hmax = np.array([int(np.max(refList.T[0])),int(np.max(refList.T[1])),int(np.max(refList.T[2]))])
2794        Vpoint = [int(np.mean(refList.T[0])),int(np.mean(refList.T[1])),int(np.mean(refList.T[2]))]
2795        controls = {'Type':'Fosq','Iscale':False,'HKLmax':Hmax,'HKLmin':Hmin,
2796            'FoMax' : FoMax,'Scale' : 1.0,'Drawing':{'viewPoint':[Vpoint,[]],'default':Vpoint[:],
2797            'backColor':[0,0,0],'depthFog':False,'Zclip':10.0,'cameraPos':10.,'Zstep':0.05,
2798            'Scale':1.0,'oldxy':[],'viewDir':[1,0,0]},'Super':Super,'SuperVec':SuperVec}
2799        G2plt.Plot3DSngl(G2frame,newPlot=True,Data=controls,hklRef=refList,Title=phaseName)
2800       
2801    def OnSelectPhase(event):
2802        dlg = wx.SingleChoiceDialog(G2frame,'Select','Phase',phases)
2803        try:
2804            if dlg.ShowModal() == wx.ID_OK:
2805                sel = dlg.GetSelection()
2806                G2frame.RefList = phases[sel]
2807                UpdateReflectionGrid(G2frame,data)
2808        finally:
2809            dlg.Destroy()
2810        G2plt.PlotPatterns(G2frame)
2811           
2812    if not data:
2813        print 'No phases, no reflections'
2814        return
2815    if HKLF:
2816        G2frame.RefList = 1
2817        phaseName = IsHistogramInAnyPhase(G2frame,Name)
2818    else:
2819        phaseName = G2frame.RefList
2820        phases = data.keys()
2821    if G2frame.dataDisplay:
2822        G2frame.dataFrame.Clear()
2823    Inst = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Instrument Parameters'))[0]
2824    if phaseName:
2825        pId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Phases')
2826        phaseId =  G2gd.GetPatternTreeItemId(G2frame,pId,phaseName)
2827        General = G2frame.PatternTree.GetItemPyData(phaseId)['General']
2828        Super = General.get('Super',0)
2829        SuperVec = General.get('SuperVec',[])
2830    else:
2831        Super = 0
2832        SuperVec = []       
2833    rowLabels = []
2834    if HKLF:
2835        G2gd.SetDataMenuBar(G2frame)
2836        refList = data[1]['RefList']
2837        G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.ReflMenu)
2838        if not G2frame.dataFrame.GetStatusBar():
2839            Status = G2frame.dataFrame.CreateStatusBar()   
2840        G2frame.Bind(wx.EVT_MENU, OnPlotHKL, id=G2gd.wxID_PWDHKLPLOT)
2841        G2frame.Bind(wx.EVT_MENU, OnPlot3DHKL, id=G2gd.wxID_PWD3DHKLPLOT)
2842        G2frame.dataFrame.SelectPhase.Enable(False)
2843        refs = refList
2844    else:
2845        G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.ReflMenu)
2846        if not G2frame.dataFrame.GetStatusBar():
2847            Status = G2frame.dataFrame.CreateStatusBar()   
2848        G2frame.Bind(wx.EVT_MENU, OnSelectPhase, id=G2gd.wxID_SELECTPHASE)
2849        G2frame.Bind(wx.EVT_MENU, OnPlotHKL, id=G2gd.wxID_PWDHKLPLOT)
2850        G2frame.Bind(wx.EVT_MENU, OnPlot3DHKL, id=G2gd.wxID_PWD3DHKLPLOT)
2851        G2frame.dataFrame.SelectPhase.Enable(False)
2852        if len(data) > 1:
2853            G2frame.dataFrame.SelectPhase.Enable(True)
2854        try:            #patch for old reflection lists
2855            refList = np.array(data[G2frame.RefList]['RefList'])
2856            I100 = refList.T[8+Super]*refList.T[11+Super]
2857        except TypeError:
2858            refList = np.array([refl[:11+Super] for refl in data[G2frame.RefList]])
2859            I100 = refList.T[8+Super]*np.array([refl[11+Super] for refl in data[G2frame.RefList]])
2860        Imax = np.max(I100)
2861        if Imax:
2862            I100 *= 100.0/Imax
2863        if 'C' in Inst['Type'][0]:
2864            refs = np.vstack((refList.T[:15+Super],I100)).T
2865        elif 'T' in Inst['Type'][0]:
2866            refs = np.vstack((refList.T[:18+Super],I100)).T
2867           
2868    for i in range(len(refs)): rowLabels.append(str(i))
2869    Types = (4+Super)*[wg.GRID_VALUE_LONG,]+4*[wg.GRID_VALUE_FLOAT+':10,4',]+ \
2870        2*[wg.GRID_VALUE_FLOAT+':10,2',]+[wg.GRID_VALUE_FLOAT+':10,3',]+ \
2871        [wg.GRID_VALUE_FLOAT+':10,3',]
2872    superLabels = ['M1','M2','M3']
2873    if HKLF:
2874        colLabels = ['H','K','L','mul','d','Fosq','sig','Fcsq','FoTsq','FcTsq','phase','ExtC',]
2875        if 'T' in Inst['Type'][0]:
2876            colLabels = ['H','K','L','mul','d','Fosq','sig','Fcsq','FoTsq','FcTsq','phase','ExtC','wave','tbar']
2877            Types += 2*[wg.GRID_VALUE_FLOAT+':10,3',]
2878        if Super:
2879            for i in range(Super):
2880                colLabels.insert(3+i,superLabels[i])
2881    else:
2882        if 'C' in Inst['Type'][0]:
2883            colLabels = ['H','K','L','mul','d','pos','sig','gam','Fosq','Fcsq','phase','Icorr','Prfo','Trans','ExtP','I100']
2884            Types += 4*[wg.GRID_VALUE_FLOAT+':10,3',]
2885        elif 'T' in Inst['Type'][0]:
2886            colLabels = ['H','K','L','mul','d','pos','sig','gam','Fosq','Fcsq','phase','Icorr','alp','bet','wave','Prfo','Abs','Ext','I100']
2887            Types += 7*[wg.GRID_VALUE_FLOAT+':10,3',]
2888        if Super:
2889            for i in range(Super):
2890                colLabels.insert(3+i,superLabels[i])
2891           
2892    G2frame.PeakTable = G2gd.Table(refs,rowLabels=rowLabels,colLabels=colLabels,types=Types)
2893    G2frame.dataFrame.SetLabel('Reflection List for '+phaseName)
2894    G2frame.dataDisplay = G2gd.GSGrid(parent=G2frame.dataFrame)
2895    G2frame.dataDisplay.SetTable(G2frame.PeakTable, True)
2896    G2frame.dataDisplay.EnableEditing(False)
2897    G2frame.dataDisplay.SetMargins(0,0)
2898    G2frame.dataDisplay.AutoSizeColumns(False)
2899    G2frame.dataDisplay.Fit()
2900    size = G2frame.dataDisplay.GetSize()
2901    G2frame.dataFrame.setSizePosLeft([size[0]+32,350])
2902   
2903################################################################################
2904#####  SASD Substances
2905################################################################################
2906           
2907def UpdateSubstanceGrid(G2frame,data):
2908    '''respond to selection of SASD Substance data tree item.
2909    '''
2910    import Substances as substFile
2911   
2912    def OnLoadSubstance(event):
2913        names = substFile.Substances.keys()
2914        names.sort()
2915        dlg = wx.SingleChoiceDialog(G2frame, 'Which substance?', 'Select substance', names, wx.CHOICEDLG_STYLE)
2916        try:
2917            if dlg.ShowModal() == wx.ID_OK:
2918                name = names[dlg.GetSelection()]
2919            else:
2920                return
2921        finally:
2922            dlg.Destroy()
2923        data['Substances'][name] = {'Elements':{},'Volume':1.0,'Density':1.0,
2924            'Scatt density':0.0,'XAnom density':0.0,'XAbsorption':0.0}
2925        subst = substFile.Substances[name]
2926        ElList = subst['Elements'].keys()
2927        for El in ElList:
2928            Info = G2elem.GetAtomInfo(El.strip().capitalize())
2929            Info.update(subst['Elements'][El])
2930            data['Substances'][name]['Elements'][El] = Info
2931            if 'Volume' in subst:
2932                data['Substances'][name]['Volume'] = subst['Volume']
2933                data['Substances'][name]['Density'] = \
2934                    G2mth.Vol2Den(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])
2935            elif 'Density' in subst:
2936                data['Substances'][name]['Density'] = subst['Density']
2937                data['Substances'][name]['Volume'] = \
2938                    G2mth.Den2Vol(data['Substances'][name]['Elements'],data['Substances'][name]['Density'])
2939            else:
2940                data['Substances'][name]['Volume'] = G2mth.El2EstVol(data['Substances'][name]['Elements'])
2941                data['Substances'][name]['Density'] = \
2942                    G2mth.Vol2Den(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])
2943            data['Substances'][name]['Scatt density'] = \
2944                G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])[0]
2945            contrst,absorb = G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'],wave)         
2946            data['Substances'][name]['XAnom density'] = contrst
2947            data['Substances'][name]['XAbsorption'] = absorb
2948                         
2949        UpdateSubstanceGrid(G2frame,data)
2950       
2951    def OnCopySubstance(event):
2952        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
2953        histList = GetHistsLikeSelected(G2frame)
2954        if not histList:
2955            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
2956            return
2957        copyList = []
2958        dlg = G2gd.G2MultiChoiceDialog(
2959            G2frame.dataFrame, 
2960            'Copy substances from\n'+hst[5:]+' to...',
2961            'Copy substances', histList)
2962        try:
2963            if dlg.ShowModal() == wx.ID_OK:
2964                for i in dlg.GetSelections(): 
2965                    copyList.append(histList[i])
2966        finally:
2967            dlg.Destroy()       
2968        for item in copyList:
2969            Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
2970            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Substances'),
2971                copy.copy(data))
2972   
2973    def OnAddSubstance(event):
2974        dlg = wx.TextEntryDialog(None,'Enter a name for this substance','Substance Name Entry','New substance',
2975            style=wx.OK)
2976        if dlg.ShowModal() == wx.ID_OK:
2977            Name = dlg.GetValue()
2978            data['Substances'][Name] = {'Elements':{},'Volume':1.0,'Density':1.0,
2979                'Scatt density':0.0,'XAnom density':0.,'XAbsorption':0.}
2980        dlg.Destroy()
2981        AddElement(Name)
2982        UpdateSubstanceGrid(G2frame,data)
2983       
2984    def OnDeleteSubstance(event):
2985        TextList = []
2986        for name in data['Substances']:
2987            if name != 'vacuum':
2988                TextList += [name,]
2989        if not TextList:
2990            return
2991        dlg = wx.SingleChoiceDialog(G2frame, 'Which substance?', 'Select substance to delete', TextList, wx.CHOICEDLG_STYLE)
2992        try:
2993            if dlg.ShowModal() == wx.ID_OK:
2994                name = TextList[dlg.GetSelection()]
2995            else:
2996                return
2997        finally:
2998            dlg.Destroy()
2999        del(data['Substances'][name])
3000        UpdateSubstanceGrid(G2frame,data)       
3001               
3002    def OnAddElement(event):       
3003        TextList = []
3004        for name in data['Substances']:
3005            if name != 'vacuum':
3006                TextList += [name,]
3007        if not TextList:
3008            return
3009        dlg = wx.SingleChoiceDialog(G2frame, 'Which substance?', 'Select substance', TextList, wx.CHOICEDLG_STYLE)
3010        try:
3011            if dlg.ShowModal() == wx.ID_OK:
3012                name = TextList[dlg.GetSelection()]
3013            else:
3014                return
3015        finally:
3016            dlg.Destroy()
3017        AddElement(name)
3018        UpdateSubstanceGrid(G2frame,data)
3019       
3020    def AddElement(name):
3021        ElList = data['Substances'][name]['Elements'].keys()
3022        dlg = G2elemGUI.PickElements(G2frame,ElList)
3023        if dlg.ShowModal() == wx.ID_OK:
3024            for El in dlg.Elem:
3025                El = El.strip().capitalize()
3026                Info = G2elem.GetAtomInfo(El)
3027                Info.update({'Num':1})
3028                data['Substances'][name]['Elements'][El] = Info
3029                data['Substances'][name]['Volume'] = G2mth.El2EstVol(data['Substances'][name]['Elements'])
3030                data['Substances'][name]['Density'] = \
3031                    G2mth.Vol2Den(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])
3032                data['Substances'][name]['Scatt density'] = \
3033                    G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])[0]
3034                contrst,absorb = G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'],wave)         
3035                data['Substances'][name]['XAnom density'] = contrst
3036                data['Substances'][name]['XAbsorption'] = absorb
3037        dlg.Destroy()
3038       
3039    def OnDeleteElement(event):
3040        TextList = []
3041        for name in data['Substances']:
3042            if name != 'vacuum':
3043                TextList += [name,]
3044        if not TextList:
3045            return
3046        dlg = wx.SingleChoiceDialog(G2frame, 'Which substance?', 'Select substance', TextList, wx.CHOICEDLG_STYLE)
3047        try:
3048            if dlg.ShowModal() == wx.ID_OK:
3049                name = TextList[dlg.GetSelection()]
3050            else:
3051                return
3052        finally:
3053            dlg.Destroy()
3054        ElList = data['Substances'][name]['Elements'].keys()
3055        if len(ElList):
3056            DE = G2elemGUI.DeleteElement(G2frame,ElList)
3057            if DE.ShowModal() == wx.ID_OK:
3058                El = DE.GetDeleteElement().strip().upper()
3059                del(data['Substances'][name]['Elements'][El])
3060                data['Substances'][name]['Volume'] = G2mth.El2EstVol(data['Substances'][name]['Elements'])
3061                data['Substances'][name]['Density'] = \
3062                    G2mth.Vol2Den(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])
3063                data['Substances'][name]['Scatt density'] = \
3064                    G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])[0]
3065                contrst,absorb = G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'],wave)         
3066                data['Substances'][name]['XAnom density'] = contrst
3067                data['Substances'][name]['XAbsorption'] = absorb
3068        UpdateSubstanceGrid(G2frame,data)
3069               
3070    def SubstSizer():
3071       
3072        def OnValueChange(event):
3073            Obj = event.GetEventObject()
3074            if len(Indx[Obj.GetId()]) == 3:
3075                name,El,keyId = Indx[Obj.GetId()]
3076                try:
3077                    value = max(0,float(Obj.GetValue()))
3078                except ValueError:
3079                    value = 0
3080                    Obj.SetValue('%.2f'%(value))
3081                data['Substances'][name]['Elements'][El][keyId] = value
3082                data['Substances'][name]['Volume'] = G2mth.El2EstVol(data['Substances'][name]['Elements'])
3083                data['Substances'][name]['Density'] = \
3084                    G2mth.Vol2Den(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])
3085            else:
3086                name,keyId = Indx[Obj.GetId()]
3087                try:
3088                    value = max(0,float(Obj.GetValue()))
3089                except ValueError:
3090                    value = 1.0
3091                data['Substances'][name][keyId] = value
3092                if keyId in 'Volume':
3093                    data['Substances'][name]['Density'] = \
3094                        G2mth.Vol2Den(data['Substances'][name]['Elements'],value)
3095                elif keyId in 'Density':
3096                    data['Substances'][name]['Volume'] = \
3097                        G2mth.Den2Vol(data['Substances'][name]['Elements'],value)
3098            data['Substances'][name]['Scatt density'] = \
3099                G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])[0]
3100            contrst,absorb = G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'],wave)         
3101            data['Substances'][name]['XAnom density'] = contrst
3102            data['Substances'][name]['XAbsorption'] = absorb
3103            wx.CallAfter(UpdateSubstanceGrid,G2frame,data)
3104       
3105        Indx = {}
3106        substSizer = wx.BoxSizer(wx.VERTICAL)
3107        substSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Substance list: wavelength: %.5fA'%(wave)),
3108            0,WACV)
3109        for name in data['Substances']:
3110            G2gd.HorizontalLine(substSizer,G2frame.dataDisplay)   
3111            substSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Data for '+name+':'),
3112                0,WACV)
3113            if name == 'vacuum':
3114                substSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label='        Not applicable'),
3115                    0,WACV)
3116            else:   
3117                elSizer = wx.FlexGridSizer(0,6,5,5)
3118                Substance = data['Substances'][name]
3119                Elems = Substance['Elements']
3120                for El in Elems:    #do elements as pull downs for isotopes for neutrons
3121                    elSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' '+El+': '),
3122                        0,WACV)
3123                    num = wx.TextCtrl(G2frame.dataDisplay,value='%.2f'%(Elems[El]['Num']),style=wx.TE_PROCESS_ENTER)
3124                    Indx[num.GetId()] = [name,El,'Num']
3125                    num.Bind(wx.EVT_TEXT_ENTER,OnValueChange)       
3126                    num.Bind(wx.EVT_KILL_FOCUS,OnValueChange)
3127                    elSizer.Add(num,0,WACV)
3128                substSizer.Add(elSizer,0)
3129                vdsSizer = wx.FlexGridSizer(0,4,5,5)
3130                vdsSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Volume: '),
3131                    0,WACV)
3132                vol = wx.TextCtrl(G2frame.dataDisplay,value='%.3f'%(Substance['Volume']),style=wx.TE_PROCESS_ENTER)
3133                Indx[vol.GetId()] = [name,'Volume']
3134                vol.Bind(wx.EVT_TEXT_ENTER,OnValueChange)       
3135                vol.Bind(wx.EVT_KILL_FOCUS,OnValueChange)
3136                vdsSizer.Add(vol,0,WACV)               
3137                vdsSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Density: '),
3138                    0,WACV)
3139                den = wx.TextCtrl(G2frame.dataDisplay,value='%.3f'%(Substance['Density']),style=wx.TE_PROCESS_ENTER)
3140                Indx[den.GetId()] = [name,'Density']
3141                den.Bind(wx.EVT_TEXT_ENTER,OnValueChange)       
3142                den.Bind(wx.EVT_KILL_FOCUS,OnValueChange)
3143                vdsSizer.Add(den,0,WACV)
3144                substSizer.Add(vdsSizer,0)
3145                substSizer.Add(wx.StaticText(G2frame.dataDisplay,
3146                    label=' Scattering density  : %.2f *10%scm%s'%(Substance['Scatt density'],Pwr10,Pwrm2)),
3147                    0,WACV)               
3148                substSizer.Add(wx.StaticText(G2frame.dataDisplay,       #allow neutrons here into NAnom density & NAbsorption
3149                    label=' Anomalous density : %.2f *10%scm%s'%(Substance['XAnom density'],Pwr10,Pwrm2)),
3150                    0,WACV)               
3151                substSizer.Add(wx.StaticText(G2frame.dataDisplay,
3152                    label=' X-ray absorption   : %.2f cm%s'%(Substance['XAbsorption'],Pwrm1)),
3153                    0,WACV)               
3154        return substSizer
3155           
3156    Inst = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Instrument Parameters'))[0]
3157    wave = G2mth.getWave(Inst)
3158    if G2frame.dataDisplay:
3159        G2frame.dataFrame.DestroyChildren()
3160    G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.SubstanceMenu)
3161    if not G2frame.dataFrame.GetStatusBar():
3162        Status = G2frame.dataFrame.CreateStatusBar()
3163    G2frame.dataDisplay = wxscroll.ScrolledPanel(G2frame.dataFrame)
3164    G2frame.dataFrame.SetLabel('Substances')
3165    G2frame.dataFrame.Bind(wx.EVT_MENU, OnLoadSubstance, id=G2gd.wxID_LOADSUBSTANCE)   
3166    G2frame.dataFrame.Bind(wx.EVT_MENU, OnAddSubstance, id=G2gd.wxID_ADDSUBSTANCE)
3167    G2frame.dataFrame.Bind(wx.EVT_MENU, OnCopySubstance, id=G2gd.wxID_COPYSUBSTANCE)
3168    G2frame.dataFrame.Bind(wx.EVT_MENU, OnDeleteSubstance, id=G2gd.wxID_DELETESUBSTANCE)   
3169    G2frame.dataFrame.Bind(wx.EVT_MENU, OnAddElement, id=G2gd.wxID_ELEMENTADD)
3170    G2frame.dataFrame.Bind(wx.EVT_MENU, OnDeleteElement, id=G2gd.wxID_ELEMENTDELETE)
3171    mainSizer = wx.BoxSizer(wx.VERTICAL)
3172    mainSizer.Add(SubstSizer(),0)
3173
3174    mainSizer.Layout()   
3175    G2frame.dataDisplay.SetSizer(mainSizer)
3176    G2frame.dataDisplay.SetAutoLayout(1)
3177    G2frame.dataDisplay.SetupScrolling()
3178    Size = mainSizer.Fit(G2frame.dataFrame)
3179    Size[0] += 25
3180    G2frame.dataDisplay.SetSize(Size)
3181    G2frame.dataFrame.setSizePosLeft(Size)   
3182       
3183################################################################################
3184#####  SASD Models
3185################################################################################           
3186       
3187def UpdateModelsGrid(G2frame,data):
3188    '''respond to selection of SASD Models data tree item.
3189    '''
3190    #patches
3191    if 'Current' not in data:
3192        data['Current'] = 'Size dist.'
3193    if 'logBins' not in data['Size']:
3194        data['Size']['logBins'] = True
3195    if 'MinMaxDiam' in data['Size']:
3196        data['Size']['MinDiam'] = 50.
3197        data['Size']['MaxDiam'] = 10000.
3198        del data['Size']['MinMaxDiam']
3199    if isinstance(data['Size']['MaxEnt']['Sky'],float):
3200        data['Size']['MaxEnt']['Sky'] = -3
3201    if 'Power' not in data['Size']['IPG']:
3202        data['Size']['IPG']['Power'] = -1
3203    if 'Matrix' not in data['Particle']:
3204        data['Particle']['Matrix'] = {'Name':'vacuum','VolFrac':[0.0,False]}
3205    if 'BackFile' not in data:
3206        data['BackFile'] = ''
3207    #end patches
3208   
3209    def RefreshPlots(newPlot=False):
3210        PlotText = G2frame.G2plotNB.nb.GetPageText(G2frame.G2plotNB.nb.GetSelection())
3211        if 'Powder' in PlotText:
3212            G2plt.PlotPatterns(G2frame,plotType='SASD',newPlot=newPlot)
3213        elif 'Size' in PlotText:
3214            G2plt.PlotSASDSizeDist(G2frame)
3215               
3216    def OnAddModel(event):
3217        if data['Current'] == 'Particle fit':
3218            material = 'vacuum'
3219            if len(data['Particle']['Levels']):
3220                material = data['Particle']['Levels'][-1]['Controls']['Material']
3221            data['Particle']['Levels'].append({
3222                'Controls':{'FormFact':'Sphere','DistType':'LogNormal','Material':material,
3223                    'FFargs':{},'SFargs':{},'NumPoints':50,'Cutoff':0.01,'Contrast':0.0,
3224                    'SlitSmear':[0.0,False],'StrFact':'Dilute'},    #last 2 not used - future?
3225                'LogNormal':{'Volume':[0.05,False],'Mean':[1000.,False],'StdDev':[0.5,False],'MinSize':[10.,False],},
3226                'Gaussian':{'Volume':[0.05,False],'Mean':[1000.,False],'StdDev':[300.,False],},
3227                'LSW':{'Volume':[0.05,False],'Mean':[1000.0,False],},
3228                'Schulz-Zimm':{'Volume':[0.05,False],'Mean':[1000.,False],'StdDev':[300.,False],},
3229                'Unified':{'G':[1.e3,False],'Rg':[100,False],'B':[1.e-5,False],'P':[4,False],'Cutoff':[1e-5,False],},
3230                'Porod':{'B':[1.e-4,False],'P':[4,False],'Cutoff':[1e-5,False],},
3231                'Monodisperse':{'Volume':[0.05,False],'Radius':[100,False],},   #OK for spheres
3232                'Bragg':{'PkInt':[100,False],'PkPos':[0.2,False],
3233                    'PkSig':[10,False],'PkGam':[10,False],},        #reasonable 31A peak
3234                })
3235            G2sasd.ModelFxn(Profile,ProfDict,Limits,Sample,data)
3236            RefreshPlots(True)
3237                   
3238        wx.CallAfter(UpdateModelsGrid,G2frame,data)
3239       
3240    def OnCopyModel(event):
3241        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
3242        histList = GetHistsLikeSelected(G2frame)
3243        if not histList:
3244            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
3245            return
3246        copyList = []
3247        dlg = G2gd.G2MultiChoiceDialog(
3248            G2frame.dataFrame, 
3249            'Copy models from\n'+hst[5:]+' to...',
3250            'Copy models', histList)
3251        try:
3252            if dlg.ShowModal() == wx.ID_OK:
3253                for i in dlg.GetSelections(): 
3254                    copyList.append(histList[i])
3255        finally:
3256            dlg.Destroy()       
3257        for item in copyList:
3258            Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
3259            newdata = copy.deepcopy(data)
3260            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Models'),newdata)
3261            if newdata['BackFile']:
3262                Profile = G2frame.PatternTree.GetItemPyData(Id)[1]
3263                BackId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,newdata['BackFile'])
3264                BackSample = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,BackId, 'Sample Parameters'))
3265                Profile[5] = BackSample['Scale'][0]*G2frame.PatternTree.GetItemPyData(BackId)[1][1]
3266        RefreshPlots(True)
3267               
3268    def OnCopyFlags(event):
3269        thisModel = copy.deepcopy(data)
3270        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
3271        histList = GetHistsLikeSelected(G2frame)
3272        if not histList:
3273            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
3274            return
3275        dlg = G2gd.G2MultiChoiceDialog(
3276            G2frame.dataFrame, 
3277            'Copy sample ref. flags from\n'+str(hst[5:])+' to...',
3278            'Copy sample flags', histList)
3279        distChoice = ['LogNormal','Gaussian','LSW','Schulz-Zimm','Bragg','Unified',
3280            'Porod','Monodisperse',]
3281        parmOrder = ['Volume','Radius','Mean','StdDev','G','Rg','B','P',
3282            'Cutoff','PkInt','PkPos','PkSig','PkGam','VolFr','Dist',]
3283        try:
3284            if dlg.ShowModal() == wx.ID_OK:
3285                result = dlg.GetSelections()
3286                for i in result: 
3287                    item = histList[i]
3288                    Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
3289                    newModel = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Models'))
3290                    newModel['Back'][1] = copy.copy(thisModel['Back'][1])
3291                    for ilev,level in enumerate(newModel['Particle']['Levels']):
3292                        for form in level:
3293                            if form in distChoice:
3294                                thisForm = thisModel['Particle']['Levels'][ilev][form]                               
3295                                for item in parmOrder:
3296                                    if item in thisForm:
3297                                       level[form][item][1] = copy.copy(thisForm[item][1])
3298                            elif form == 'Controls':
3299                                thisForm = thisModel['Particle']['Levels'][ilev][form]['SFargs']
3300                                for item in parmOrder:
3301                                    if item in thisForm:
3302                                        level[form]['SFargs'][item][1] = copy.copy(thisForm[item][1])
3303        finally:
3304            dlg.Destroy()
3305               
3306    def OnFitModelAll(event):
3307        choices = G2gd.GetPatternTreeDataNames(G2frame,['SASD',])
3308        sel = []
3309        dlg = G2gd.G2MultiChoiceDialog(G2frame.dataFrame, 'Sequential SASD refinement',
3310             'Select dataset to include',choices)
3311        dlg.SetSelections(sel)
3312        names = []
3313        if dlg.ShowModal() == wx.ID_OK:
3314            for sel in dlg.GetSelections():
3315                names.append(choices[sel])
3316        dlg.Destroy()
3317        SeqResult = {'histNames':names}
3318        Reverse = False
3319        CopyForward = False
3320        choice = ['Reverse sequence','Copy from prev.']
3321        dlg = wx.MultiChoiceDialog(G2frame.dataFrame,'Sequential controls','Select controls',choice)
3322        if dlg.ShowModal() == wx.ID_OK:
3323            for sel in dlg.GetSelections():
3324                if sel:
3325                    CopyForward = True
3326                else:
3327                    Reverse = True
3328        dlg.Destroy()
3329        dlg = wx.ProgressDialog('SASD Sequential fit','Data set name = '+names[0],len(names), 
3330            style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE|wx.PD_REMAINING_TIME|wx.PD_CAN_ABORT)
3331        wx.BeginBusyCursor()
3332        if Reverse:
3333            names.reverse()
3334        try:
3335            for i,name in enumerate(names):
3336                print ' Sequential fit for ',name
3337                GoOn = dlg.Update(i,newmsg='Data set name = '+name)[0]
3338                if not GoOn:
3339                    break
3340                Id =  G2gd.GetPatternTreeItemId(G2frame,G2frame.root,name)
3341                if i and CopyForward:
3342                    G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Models'),JModel)
3343                IProfDict,IProfile = G2frame.PatternTree.GetItemPyData(Id)[:2]
3344                IModel = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Models'))
3345                ISample = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Sample Parameters'))
3346                ILimits = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Limits'))
3347                IInst = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Instrument Parameters'))
3348                IfOK,result,varyList,sig,Rvals,covMatrix,parmDict,Msg = G2sasd.ModelFit(IProfile,IProfDict,ILimits,ISample,IModel)
3349                JModel = copy.deepcopy(IModel)
3350                if not IfOK:
3351                    G2frame.ErrorDialog('Failed sequential refinement for data '+name,
3352                        ' Msg: '+Msg+'\nYou need to rethink your selection of parameters\n'+    \
3353                        ' Model restored to previous version for'+name)
3354                    SeqResult['histNames'] = names[:i]
3355                    dlg.Destroy()
3356                    break
3357                else:
3358                    G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Models'),copy.deepcopy(IModel))
3359               
3360                G2sasd.ModelFxn(IProfile,IProfDict,ILimits,ISample,IModel)
3361                SeqResult[name] = {'variables':result[0],'varyList':varyList,'sig':sig,'Rvals':Rvals,
3362                    'covMatrix':covMatrix,'title':name,'parmDict':parmDict}
3363            else:
3364                dlg.Destroy()
3365                print ' ***** Small angle sequential refinement successful *****'
3366        finally:
3367            wx.EndBusyCursor()   
3368        Id =  G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Sequential results')
3369        if Id:
3370            G2frame.PatternTree.SetItemPyData(Id,SeqResult)
3371        else:
3372            Id = G2frame.PatternTree.AppendItem(parent=G2frame.root,text='Sequential results')
3373            G2frame.PatternTree.SetItemPyData(Id,SeqResult)
3374        G2frame.PatternTree.SelectItem(Id)
3375       
3376    def OnFitModel(event):
3377        if data['Current'] == 'Size dist.':
3378            if not any(Sample['Contrast']):
3379                G2frame.ErrorDialog('No contrast; your sample is a vacuum!',
3380                    'You need to define a scattering substance!\n'+    \
3381                    ' Do Substances and then Sample parameters')
3382                return
3383            G2sasd.SizeDistribution(Profile,ProfDict,Limits,Sample,data)
3384            G2plt.PlotSASDSizeDist(G2frame)
3385            RefreshPlots(True)
3386           
3387        elif data['Current'] == 'Particle fit':
3388            SaveState()
3389            Results = G2sasd.ModelFit(Profile,ProfDict,Limits,Sample,data)
3390            if not Results[0]:
3391                    G2frame.ErrorDialog('Failed refinement',
3392                        ' Msg: '+Results[-1]+'\nYou need to rethink your selection of parameters\n'+    \
3393                        ' Model restored to previous version')
3394            G2sasd.ModelFxn(Profile,ProfDict,Limits,Sample,data)
3395            RefreshPlots(True)
3396            wx.CallAfter(UpdateModelsGrid,G2frame,data)
3397           
3398    def OnUnDo(event):
3399        DoUnDo()
3400        data = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,
3401            G2frame.PatternId,'Models'))
3402        G2frame.dataFrame.SasdUndo.Enable(False)
3403        UpdateModelsGrid(G2frame,data)
3404        G2sasd.ModelFxn(Profile,ProfDict,Limits,Sample,data)
3405        RefreshPlots(True)
3406
3407    def DoUnDo():
3408        print 'Undo last refinement'
3409        file = open(G2frame.undosasd,'rb')
3410        PatternId = G2frame.PatternId
3411        G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Models'),cPickle.load(file))
3412        print ' Models recovered'
3413        file.close()
3414       
3415    def SaveState():
3416        G2frame.undosasd = os.path.join(G2frame.dirname,'GSASIIsasd.save')
3417        file = open(G2frame.undosasd,'wb')
3418        PatternId = G2frame.PatternId
3419        for item in ['Models']:
3420            cPickle.dump(G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId,item)),file,1)
3421        file.close()
3422        G2frame.dataFrame.SasdUndo.Enable(True)
3423       
3424    def OnSelectFit(event):
3425        data['Current'] = fitSel.GetValue()
3426        wx.CallAfter(UpdateModelsGrid,G2frame,data)
3427       
3428    def OnCheckBox(event):
3429        Obj = event.GetEventObject()
3430        item,ind = Indx[Obj.GetId()]
3431        item[ind] = Obj.GetValue()
3432       
3433    def OnIntVal(event):
3434        Obj = event.GetEventObject()
3435        item,ind,minVal = Indx[Obj.GetId()]
3436        try:
3437            value = int(Obj.GetValue())
3438            if value <= minVal:
3439                raise ValueError
3440        except ValueError:
3441            value = item[ind]
3442        Obj.SetValue(str(value))
3443        item[ind] = value
3444
3445    def SizeSizer():
3446       
3447        def OnShape(event):
3448            data['Size']['Shape'][0] = partsh.GetValue()
3449            wx.CallAfter(UpdateModelsGrid,G2frame,data)
3450           
3451        def OnMethod(event):
3452            data['Size']['Method'] = method.GetValue()
3453            wx.CallAfter(UpdateModelsGrid,G2frame,data)
3454           
3455        def OnPartVal(event):
3456            try:
3457                val = max(0.0,float(partprm.GetValue()))
3458            except ValueError:
3459                val = 1
3460            data['Size']['Shape'][1] = val
3461            partprm.SetValue('%.3f'%(val))
3462           
3463        sizeSizer = wx.BoxSizer(wx.VERTICAL)
3464        sizeSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Size distribution parameters: '),0,WACV)
3465        binSizer = wx.FlexGridSizer(0,7,5,5)
3466        binSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' No. size bins: '),0,WACV)
3467        bins = ['50','100','150','200']
3468        nbins = wx.ComboBox(G2frame.dataDisplay,value=str(data['Size']['Nbins']),choices=bins,
3469            style=wx.CB_READONLY|wx.CB_DROPDOWN)
3470        Indx[nbins.GetId()] = [data['Size'],'Nbins',0]
3471        nbins.Bind(wx.EVT_COMBOBOX,OnIntVal)       
3472        binSizer.Add(nbins,0,WACV)
3473        binSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Min diam.: '),0,WACV)
3474        minDias = ['10','25','50','100','150','200']
3475        mindiam = wx.ComboBox(G2frame.dataDisplay,value=str(data['Size']['MinDiam']),choices=minDias,
3476            style=wx.CB_DROPDOWN)
3477        mindiam.Bind(wx.EVT_LEAVE_WINDOW,OnIntVal)
3478        mindiam.Bind(wx.EVT_TEXT_ENTER,OnIntVal)       
3479        mindiam.Bind(wx.EVT_KILL_FOCUS,OnIntVal)
3480        Indx[mindiam.GetId()] = [data['Size'],'MinDiam',0]
3481        binSizer.Add(mindiam,0,WACV)
3482        binSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Max diam.: '),0,WACV)
3483        maxDias = [str(1000*(i+1)) for i in range(10)]
3484        maxdiam = wx.ComboBox(G2frame.dataDisplay,value=str(data['Size']['MaxDiam']),choices=maxDias,
3485            style=wx.CB_DROPDOWN)
3486        maxdiam.Bind(wx.EVT_LEAVE_WINDOW,OnIntVal)
3487        maxdiam.Bind(wx.EVT_TEXT_ENTER,OnIntVal)       
3488        maxdiam.Bind(wx.EVT_KILL_FOCUS,OnIntVal)
3489        Indx[maxdiam.GetId()] = [data['Size'],'MaxDiam',0]
3490        binSizer.Add(maxdiam,0,WACV)
3491        logbins = wx.CheckBox(G2frame.dataDisplay,label='Log bins?')
3492        Indx[logbins.GetId()] = [data['Size'],'logBins']
3493        logbins.SetValue(data['Size']['logBins'])
3494        logbins.Bind(wx.EVT_CHECKBOX, OnCheckBox)
3495        binSizer.Add(logbins,0,WACV)
3496        sizeSizer.Add(binSizer,0)
3497        sizeSizer.Add((5,5),0)
3498        partSizer = wx.BoxSizer(wx.HORIZONTAL)
3499        partSizer.Add(wx.StaticText(G2frame.dataDisplay,label='Particle description: '),0,WACV)
3500        shapes = {'Spheroid':' Aspect ratio: ','Cylinder':' Diameter ','Cylinder AR':' Aspect ratio: ',
3501            'Unified sphere':'','Unified rod':' Diameter: ','Unified rod AR':' Aspect ratio: ',
3502            'Unified disk':' Thickness: '}
3503        partsh = wx.ComboBox(G2frame.dataDisplay,value=str(data['Size']['Shape'][0]),choices=shapes.keys(),
3504            style=wx.CB_READONLY|wx.CB_DROPDOWN)
3505        partsh.Bind(wx.EVT_COMBOBOX,OnShape)       
3506        partSizer.Add(partsh,0,WACV)
3507        if data['Size']['Shape'][0] not in ['Unified sphere',]:
3508            partSizer.Add(wx.StaticText(G2frame.dataDisplay,label=shapes[data['Size']['Shape'][0]]),0,WACV)
3509            partprm = wx.TextCtrl(G2frame.dataDisplay,value='%.3f'%(data['Size']['Shape'][1]),
3510                style=wx.TE_PROCESS_ENTER)
3511            partprm.Bind(wx.EVT_TEXT_ENTER,OnPartVal)       
3512            partprm.Bind(wx.EVT_KILL_FOCUS,OnPartVal)
3513            partSizer.Add(partprm,0,WACV)
3514        sizeSizer.Add(partSizer,0)
3515        sizeSizer.Add((5,5),0)
3516        fitSizer = wx.BoxSizer(wx.HORIZONTAL)
3517        methods = ['MaxEnt','IPG',]
3518        fitSizer.Add(wx.StaticText(G2frame.dataDisplay,label='Fitting method: '),0,WACV)
3519        method = wx.ComboBox(G2frame.dataDisplay,value=data['Size']['Method'],choices=methods,
3520            style=wx.CB_READONLY|wx.CB_DROPDOWN)
3521        method.Bind(wx.EVT_COMBOBOX,OnMethod)
3522        fitSizer.Add(method,0,WACV)
3523        iters = ['10','25','50','100','150','200']       
3524        fitSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' No. iterations: '),0,WACV)
3525        Method = data['Size']['Method']
3526        iter = wx.ComboBox(G2frame.dataDisplay,value=str(data['Size'][Method]['Niter']),choices=iters,
3527            style=wx.CB_READONLY|wx.CB_DROPDOWN)
3528        Indx[iter.GetId()] = [data['Size'][Method],'Niter',0]
3529        iter.Bind(wx.EVT_COMBOBOX,OnIntVal)
3530        fitSizer.Add(iter,0,WACV)
3531        if 'MaxEnt' in data['Size']['Method']:
3532            fitSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Log floor factor: '),0,WACV)
3533            floors = [str(-i) for i in range(9)]
3534            floor = wx.ComboBox(G2frame.dataDisplay,value=str(data['Size']['MaxEnt']['Sky']),choices=floors,
3535                style=wx.CB_READONLY|wx.CB_DROPDOWN)
3536            Indx[floor.GetId()] = [data['Size']['MaxEnt'],'Sky',-10]
3537            floor.Bind(wx.EVT_COMBOBOX,OnIntVal)
3538            fitSizer.Add(floor,0,WACV)
3539        elif 'IPG' in data['Size']['Method']:
3540            fitSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Q power weight (-1 for sigma): '),0,WACV)
3541            choices = ['-1','0','1','2','3','4']
3542            power = wx.ComboBox(G2frame.dataDisplay,value=str(data['Size']['IPG']['Power']),choices=choices,
3543                style=wx.CB_READONLY|wx.CB_DROPDOWN)
3544            Indx[power.GetId()] = [data['Size']['IPG'],'Power',-2]
3545            power.Bind(wx.EVT_COMBOBOX,OnIntVal)
3546            fitSizer.Add(power,0,WACV)
3547        sizeSizer.Add(fitSizer,0)
3548
3549        return sizeSizer
3550       
3551    def PartSizer():
3552       
3553        FormFactors = {'Sphere':{},'Spheroid':{'Aspect ratio':[1.0,False]},
3554            'Cylinder':{'Length':[100.,False]},'Cylinder diam':{'Diameter':[100.,False]},
3555            'Cylinder AR':{'Aspect ratio':[1.0,False]},'Unified sphere':{},
3556            'Unified rod':{'Length':[100.,False]},'Unified rod AR':{'Aspect ratio':[1.0,False]},
3557            'Unified disk':{'Thickness':[100.,False]},
3558            'Unified tube':{'Length':[100.,False],'Thickness':[10.,False]},}
3559               
3560        StructureFactors = {'Dilute':{},'Hard sphere':{'VolFr':[0.1,False],'Dist':[100.,False]},
3561            'Sticky hard sphere':{'VolFr':[0.1,False],'Dist':[100.,False],'epis':[0.05,False],'Sticky':[0.2,False]},
3562            'Square well':{'VolFr':[0.1,False],'Dist':[100.,False],'Depth':[0.1,False],'Width':[1.,False]},
3563            'InterPrecipitate':{'VolFr':[0.1,False],'Dist':[100.,False]},}
3564               
3565        ffDistChoices =  ['Sphere','Spheroid','Cylinder','Cylinder diam',
3566            'Cylinder AR','Unified sphere','Unified rod','Unified rod AR',
3567            'Unified disk','Unified tube',]
3568               
3569        ffMonoChoices = ['Sphere','Spheroid','Cylinder','Cylinder AR',]
3570       
3571        sfChoices = ['Dilute','Hard sphere','Sticky hard sphere','Square well','InterPrecipitate',]
3572           
3573        slMult = 1000.
3574                 
3575        def OnValue(event):
3576            Obj = event.GetEventObject()
3577            item,key,sldrObj = Indx[Obj.GetId()]
3578            try:
3579                value = float(Obj.GetValue())
3580                if value <= 0.:
3581                    raise ValueError
3582            except ValueError:
3583                value = item[key][0]
3584            item[key][0] = value
3585            Obj.SetValue('%.3g'%(value))
3586            if key in ['P','epis','Sticky','Depth','Width','VolFr','Dist']:
3587                sldrObj.SetValue(slMult*value)
3588            else:
3589                logv = np.log10(value)
3590                valMinMax = [logv-1,logv+1]
3591                sldrObj.SetRange(slMult*valMinMax[0],slMult*valMinMax[1])
3592                sldrObj.SetValue(slMult*logv)
3593            G2sasd.ModelFxn(Profile,ProfDict,Limits,Sample,data)
3594            RefreshPlots()
3595           
3596        def OnSelect(event):
3597            Obj = event.GetEventObject()
3598            item,key = Indx[Obj.GetId()]
3599            item[key] = Obj.GetValue()
3600            if 'Refine' not in Obj.GetLabel():
3601                if 'FormFact' in key :
3602                    item['FFargs'] = FormFactors[Obj.GetValue()]
3603                elif 'StrFact' in key:
3604                    item['SFargs'] = StructureFactors[Obj.GetValue()]
3605                wx.CallAfter(UpdateModelsGrid,G2frame,data)
3606                G2sasd.ModelFxn(Profile,ProfDict,Limits,Sample,data)
3607                RefreshPlots()
3608               
3609        def OnDelLevel(event):
3610            Obj = event.GetEventObject()
3611            item = Indx[Obj.GetId()]
3612            del data['Particle']['Levels'][item]
3613            wx.CallAfter(UpdateModelsGrid,G2frame,data)
3614            G2sasd.ModelFxn(Profile,ProfDict,Limits,Sample,data)
3615            RefreshPlots()
3616           
3617        def OnParmSlider(event):
3618            Obj = event.GetEventObject()
3619            item,key,pvObj = Indx[Obj.GetId()]
3620            slide = Obj.GetValue()
3621            if key in ['P','epis','Sticky','Depth','Width','VolFr','Dist']:
3622                value = float(slide/slMult)
3623            else:
3624                value = 10.**float(slide/slMult)
3625            item[key][0] = value
3626            pvObj.SetValue('%.3g'%(item[key][0]))
3627            G2sasd.ModelFxn(Profile,ProfDict,Limits,Sample,data)
3628            RefreshPlots()
3629           
3630        def SizeSizer():
3631            sizeSizer = wx.FlexGridSizer(0,4,5,5)
3632            sizeSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Distribution: '),0,WACV)
3633            Distchoice = ['LogNormal','Gaussian','LSW','Schulz-Zimm','Bragg','Unified','Porod','Monodisperse',]
3634            distChoice = wx.ComboBox(G2frame.dataDisplay,value=level['Controls']['DistType'],choices=Distchoice,
3635                style=wx.CB_READONLY|wx.CB_DROPDOWN)
3636            Indx[distChoice.GetId()] = [level['Controls'],'DistType']
3637            distChoice.Bind(wx.EVT_COMBOBOX,OnSelect)
3638            sizeSizer.Add(distChoice,0,WACV)    #put structure factor choices here
3639            if level['Controls']['DistType'] not in ['Bragg','Unified','Porod',]:
3640                sizeSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Form Factor: '),0,WACV)
3641                if 'Mono' in level['Controls']['DistType']:
3642                    ffChoice = wx.ComboBox(G2frame.dataDisplay,value=level['Controls']['FormFact'],choices=ffMonoChoices,
3643                        style=wx.CB_READONLY|wx.CB_DROPDOWN)
3644                else:
3645                    ffChoice = wx.ComboBox(G2frame.dataDisplay,value=level['Controls']['FormFact'],choices=ffDistChoices,
3646                        style=wx.CB_READONLY|wx.CB_DROPDOWN)
3647                Indx[ffChoice.GetId()] = [level['Controls'],'FormFact']
3648                ffChoice.Bind(wx.EVT_COMBOBOX,OnSelect)
3649                sizeSizer.Add(ffChoice,0,WACV)
3650               
3651                sizeSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Material: '),0,WACV)
3652                matSel = wx.ComboBox(G2frame.dataDisplay,value=level['Controls']['Material'],
3653                    choices=Substances['Substances'].keys(),style=wx.CB_READONLY|wx.CB_DROPDOWN)
3654                Indx[matSel.GetId()] = [level['Controls'],'Material']
3655                matSel.Bind(wx.EVT_COMBOBOX,OnSelect)       
3656                sizeSizer.Add(matSel,0,WACV) #do neutron test here?
3657                rho = Substances['Substances'][level['Controls']['Material']].get('XAnom density',0.0)
3658                level['Controls']['Contrast'] = contrast = (rho-rhoMat)**2                 
3659                sizeSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Resonant X-ray contrast: '),0,WACV)
3660                sizeSizer.Add(wx.StaticText(G2frame.dataDisplay,label=%.2f 10%scm%s'%(contrast,Pwr20,Pwrm4)),0,WACV)
3661                if 'Mono' not in level['Controls']['DistType']:
3662                    sizeSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Num. radii: '),0,WACV)
3663                    radii = ['25','50','75','100','200']
3664                    nRadii = wx.ComboBox(G2frame.dataDisplay,value=str(level['Controls']['NumPoints']),choices=radii,
3665                        style=wx.CB_READONLY|wx.CB_DROPDOWN)
3666                    Indx[nRadii.GetId()] = [level['Controls'],'NumPoints']
3667                    nRadii.Bind(wx.EVT_COMBOBOX,OnSelect)
3668                    sizeSizer.Add(nRadii,0,WACV)
3669                    sizeSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' R dist. cutoff: '),0,WACV)
3670                    rCutoff = G2gd.ValidatedTxtCtrl(G2frame.dataDisplay,level['Controls'],'Cutoff',
3671                        min=0.001,max=0.1,typeHint=float)
3672                    sizeSizer.Add(rCutoff,0,WACV)
3673            elif level['Controls']['DistType']  in ['Unified',]:
3674                Parms = level['Unified']
3675                Best = G2sasd.Bestimate(Parms['G'][0],Parms['Rg'][0],Parms['P'][0])
3676                sizeSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Estimated Dist B: %12.4g'%(Best)),0,WACV)
3677            return sizeSizer
3678           
3679        def ParmSizer():
3680            parmSizer = wx.FlexGridSizer(0,3,5,5)
3681            parmSizer.AddGrowableCol(2,1)
3682            parmSizer.SetFlexibleDirection(wx.HORIZONTAL)
3683            Parms = level[level['Controls']['DistType']]
3684            FFargs = level['Controls']['FFargs']
3685            SFargs = level['Controls'].get('SFargs',{})
3686            parmOrder = ['Volume','Radius','Mean','StdDev','MinSize','G','Rg','B','P','Cutoff',
3687                'PkInt','PkPos','PkSig','PkGam',]
3688            for parm in parmOrder:
3689                if parm in Parms:
3690                    if parm == 'MinSize':
3691                        parmSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Dist '+parm),0,wx.ALIGN_CENTER)
3692                    else:
3693                        parmVar = wx.CheckBox(G2frame.dataDisplay,label='Refine? Dist '+parm) 
3694                        parmVar.SetValue(Parms[parm][1])
3695                        parmVar.Bind(wx.EVT_CHECKBOX, OnSelect)
3696                        parmSizer.Add(parmVar,0,WACV)
3697                        Indx[parmVar.GetId()] = [Parms[parm],1]
3698                    parmValue = wx.TextCtrl(G2frame.dataDisplay,value='%.3g'%(Parms[parm][0]),
3699                        style=wx.TE_PROCESS_ENTER)
3700                    parmValue.Bind(wx.EVT_TEXT_ENTER,OnValue)       
3701                    parmValue.Bind(wx.EVT_KILL_FOCUS,OnValue)
3702                    parmSizer.Add(parmValue,0,WACV)
3703                    if parm == 'P':
3704                        value = Parms[parm][0]
3705                        valMinMax = [0.1,4.2]
3706                    else:
3707                        value = np.log10(Parms[parm][0])
3708                        valMinMax = [value-1,value+1]
3709                    parmSldr = wx.Slider(G2frame.dataDisplay,minValue=slMult*valMinMax[0],
3710                        maxValue=slMult*valMinMax[1],value=slMult*value)
3711                    Indx[parmValue.GetId()] = [Parms,parm,parmSldr]
3712                    Indx[parmSldr.GetId()] = [Parms,parm,parmValue]
3713                    parmSldr.Bind(wx.EVT_SLIDER,OnParmSlider)
3714                    parmSizer.Add(parmSldr,1,wx.EXPAND)
3715            if level['Controls']['DistType'] not in ['Bragg']:
3716                parmOrder = ['Aspect ratio','Length','Diameter','Thickness','VolFr','Dist','epis','Sticky','Depth','Width']
3717                fTypes = ['FF ','SF ']
3718                for iarg,Args in enumerate([FFargs,SFargs]):
3719                    for parm in parmOrder:
3720                        if parm in Args:
3721                            parmVar = wx.CheckBox(G2frame.dataDisplay,label='Refine? '+fTypes[iarg]+parm) 
3722                            parmVar.SetValue(Args[parm][1])
3723                            Indx[parmVar.GetId()] = [Args[parm],1]
3724                            parmVar.Bind(wx.EVT_CHECKBOX, OnSelect)
3725                            parmSizer.Add(parmVar,0,WACV)
3726                            parmValue = wx.TextCtrl(G2frame.dataDisplay,value='%.3g'%(Args[parm][0]),
3727                                style=wx.TE_PROCESS_ENTER)
3728                            parmValue.Bind(wx.EVT_TEXT_ENTER,OnValue)       
3729                            parmValue.Bind(wx.EVT_KILL_FOCUS,OnValue)
3730                            parmSizer.Add(parmValue,0,WACV)
3731                            value = Args[parm][0]
3732                            if parm == 'epis':
3733                                valMinMax = [0,.1]
3734                            elif parm in ['Sticky','Width',]:
3735                                valMinMax = [0,1.]
3736                            elif parm == 'Depth':
3737                                valMinMax = [-2.,2.]
3738                            elif parm == 'Dist':
3739                                valMinMax = [100.,1000.]
3740                            elif parm == 'VolFr':
3741                                valMinMax = [1.e-4,1.]
3742                            else:
3743                                value = np.log10(Args[parm][0])
3744                                valMinMax = [value-1,value+1]
3745                            parmSldr = wx.Slider(G2frame.dataDisplay,minValue=slMult*valMinMax[0],
3746                                maxValue=slMult*valMinMax[1],value=slMult*value)
3747                            Indx[parmVar.GetId()] = [Args[parm],1]
3748                            Indx[parmValue.GetId()] = [Args,parm,parmSldr]
3749                            Indx[parmSldr.GetId()] = [Args,parm,parmValue]
3750                            parmSldr.Bind(wx.EVT_SLIDER,OnParmSlider)
3751                            parmSizer.Add(parmSldr,1,wx.EXPAND)
3752            return parmSizer               
3753           
3754        Indx = {}
3755        partSizer = wx.BoxSizer(wx.VERTICAL)
3756        topSizer = wx.BoxSizer(wx.HORIZONTAL)
3757        topSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Particle fit parameters: '),0,WACV)
3758        topSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Matrix: '),0,WACV)
3759        matsel = wx.ComboBox(G2frame.dataDisplay,value=data['Particle']['Matrix']['Name'],
3760            choices=Substances['Substances'].keys(),style=wx.CB_READONLY|wx.CB_DROPDOWN)
3761        Indx[matsel.GetId()] = [data['Particle']['Matrix'],'Name'] 
3762        matsel.Bind(wx.EVT_COMBOBOX,OnSelect) #Do neutron test here?
3763        rhoMat = Substances['Substances'][data['Particle']['Matrix']['Name']].get('XAnom density',0.0)       
3764        topSizer.Add(matsel,0,WACV)
3765        topSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Volume fraction: '),0,WACV)
3766        volfrac = G2gd.ValidatedTxtCtrl(G2frame.dataDisplay,data['Particle']['Matrix']['VolFrac'],0,
3767                typeHint=float)
3768        topSizer.Add(volfrac,0,WACV)
3769        volVar = wx.CheckBox(G2frame.dataDisplay,label=' Refine?')
3770        volVar.SetValue(data['Particle']['Matrix']['VolFrac'][1])
3771        Indx[volVar.GetId()] = [data['Particle']['Matrix']['VolFrac'],1]
3772        volVar.Bind(wx.EVT_CHECKBOX, OnSelect)
3773        topSizer.Add(volVar,0,WACV)
3774        partSizer.Add(topSizer,0,)
3775        for ilev,level in enumerate(data['Particle']['Levels']):
3776            G2gd.HorizontalLine(partSizer,G2frame.dataDisplay)
3777            topLevel = wx.BoxSizer(wx.HORIZONTAL)
3778            topLevel.Add(wx.StaticText(G2frame.dataDisplay,label=' Model component %d: '%(ilev)),0,WACV)
3779            delBtn = wx.Button(G2frame.dataDisplay,label=' Delete?')
3780            Indx[delBtn.GetId()] = ilev
3781            delBtn.Bind(wx.EVT_BUTTON,OnDelLevel)
3782            topLevel.Add(delBtn,0,WACV)
3783            partSizer.Add(topLevel,0)
3784            partSizer.Add(SizeSizer())
3785            if level['Controls']['DistType'] not in ['Bragg','Unified','Porod',]:
3786                topLevel.Add(wx.StaticText(G2frame.dataDisplay,label=' Structure factor: '),0,WACV)
3787                strfctr = wx.ComboBox(G2frame.dataDisplay,value=level['Controls']['StrFact'],
3788                    choices=sfChoices,style=wx.CB_READONLY|wx.CB_DROPDOWN)
3789                Indx[strfctr.GetId()] = [level['Controls'],'StrFact']
3790                strfctr.Bind(wx.EVT_COMBOBOX,OnSelect)
3791                topLevel.Add(strfctr,0,WACV)
3792            partSizer.Add(ParmSizer(),0,wx.EXPAND)
3793        return partSizer
3794       
3795    def OnEsdScale(event):
3796        try:
3797            value = float(esdScale.GetValue())
3798            if value <= 0.:
3799                raise ValueError
3800        except ValueError:
3801            value = 1./np.sqrt(ProfDict['wtFactor'])
3802        ProfDict['wtFactor'] = 1./value**2
3803        esdScale.SetValue('%.3f'%(value))
3804        RefreshPlots(True)
3805       
3806    def OnBackChange(event):
3807        try:
3808            value = float(backVal.GetValue())
3809        except ValueError:
3810            value = 0.0
3811        backVal.SetValue('%.3g'%(value))
3812        data['Back'][0] = value
3813        Profile[4][:] = value
3814        RefreshPlots()
3815       
3816    def OnBackFile(event):  #multiple backgrounds?
3817        data['BackFile'] = backFile.GetValue()
3818        if data['BackFile']:
3819            fixBack =  data['Back'][0]
3820            BackId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,data['BackFile'])
3821            BackSample = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,BackId, 'Sample Parameters'))
3822            Profile[5] = BackSample['Scale'][0]*G2frame.PatternTree.GetItemPyData(BackId)[1][1]
3823        else:
3824            Profile[5] = np.zeros(len(Profile[5]))
3825        RefreshPlots(True)
3826           
3827    Sample = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Sample Parameters'))
3828    Limits = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Limits'))
3829    Inst = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Instrument Parameters'))
3830    Substances = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Substances'))
3831    ProfDict,Profile = G2frame.PatternTree.GetItemPyData(G2frame.PatternId)[:2]
3832    if data['BackFile']:
3833        BackId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,data['BackFile'])
3834        BackSample = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,BackId, 'Sample Parameters'))
3835        Profile[5] = BackSample['Scale'][0]*G2frame.PatternTree.GetItemPyData(BackId)[1][1]
3836    if G2frame.dataDisplay:
3837        G2frame.dataFrame.DestroyChildren()
3838    G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.ModelMenu)
3839    if not G2frame.dataFrame.GetStatusBar():
3840        Status = G2frame.dataFrame.CreateStatusBar()
3841    G2frame.dataFrame.SetLabel('Modelling')
3842    G2frame.dataDisplay = wxscroll.ScrolledPanel(G2frame.dataFrame)
3843    G2frame.dataFrame.Bind(wx.EVT_MENU, OnCopyModel, id=G2gd.wxID_MODELCOPY)
3844    G2frame.dataFrame.Bind(wx.EVT_MENU, OnCopyFlags, id=G2gd.wxID_MODELCOPYFLAGS)
3845    G2frame.dataFrame.Bind(wx.EVT_MENU, OnFitModel, id=G2gd.wxID_MODELFIT)
3846    G2frame.dataFrame.Bind(wx.EVT_MENU, OnFitModelAll, id=G2gd.wxID_MODELFITALL)
3847    G2frame.dataFrame.Bind(wx.EVT_MENU, OnUnDo, id=G2gd.wxID_MODELUNDO)
3848    G2frame.dataFrame.Bind(wx.EVT_MENU, OnAddModel, id=G2gd.wxID_MODELADD)
3849    Indx = {}
3850    mainSizer = wx.BoxSizer(wx.VERTICAL)
3851    topSizer = wx.BoxSizer(wx.HORIZONTAL)
3852    models = ['Size dist.','Particle fit']
3853    topSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Modeling by: '),0,WACV)
3854    fitSel = wx.ComboBox(G2frame.dataDisplay,value=data['Current'],choices=models,
3855        style=wx.CB_READONLY|wx.CB_DROPDOWN)
3856    fitSel.Bind(wx.EVT_COMBOBOX,OnSelectFit)       
3857    topSizer.Add(fitSel,0,WACV)
3858    topSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Error multiplier: '),0,WACV)
3859    esdScale = wx.TextCtrl(G2frame.dataDisplay,value='%.3f'%(1./np.sqrt(ProfDict['wtFactor'])),style=wx.TE_PROCESS_ENTER)
3860    esdScale.Bind(wx.EVT_TEXT_ENTER,OnEsdScale)       
3861    esdScale.Bind(wx.EVT_KILL_FOCUS,OnEsdScale)
3862    topSizer.Add(esdScale,0,WACV)
3863    mainSizer.Add(topSizer)
3864    G2gd.HorizontalLine(mainSizer,G2frame.dataDisplay)
3865    if 'Size' in data['Current']:
3866        if 'MaxEnt' in data['Size']['Method']:
3867            Status.SetStatusText('Size distribution by Maximum entropy')
3868        elif 'IPG' in data['Size']['Method']:
3869            Status.SetStatusText('Size distribution by Interior-Point Gradient')
3870        mainSizer.Add(SizeSizer())       
3871    elif 'Particle' in data['Current']:
3872        mainSizer.Add(PartSizer(),1,wx.ALIGN_LEFT|wx.EXPAND)
3873    G2gd.HorizontalLine(mainSizer,G2frame.dataDisplay)   
3874    backSizer = wx.BoxSizer(wx.HORIZONTAL)
3875    backSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Background:'),0,WACV)
3876    backVal = wx.TextCtrl(G2frame.dataDisplay,value='%.3g'%(data['Back'][0]),style=wx.TE_PROCESS_ENTER)
3877    Indx[backVal.GetId()] = ['Back',0,'%.3g']
3878    backVal.Bind(wx.EVT_TEXT_ENTER,OnBackChange)       
3879    backVal.Bind(wx.EVT_KILL_FOCUS,OnBackChange)
3880    backSizer.Add(backVal,0,WACV)
3881    backVar = wx.CheckBox(G2frame.dataDisplay,label='Refine?')
3882    Indx[backVar.GetId()] = [data['Back'],1]
3883    backVar.SetValue(data['Back'][1])
3884    backVar.Bind(wx.EVT_CHECKBOX, OnCheckBox)
3885    backSizer.Add(backVar,0,WACV)
3886    #multiple background files?
3887    backSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' Background file: '),0,WACV)
3888    Choices = ['',]+G2gd.GetPatternTreeDataNames(G2frame,['SASD',])
3889    backFile = wx.ComboBox(parent=G2frame.dataDisplay,value=data['BackFile'],choices=Choices,
3890        style=wx.CB_READONLY|wx.CB_DROPDOWN)
3891    backFile.Bind(wx.EVT_COMBOBOX,OnBackFile)
3892    backSizer.Add(backFile)   
3893    mainSizer.Add(backSizer)
3894
3895    mainSizer.Layout()   
3896    G2frame.dataDisplay.SetSizer(mainSizer)
3897    G2frame.dataDisplay.SetAutoLayout(1)
3898    G2frame.dataDisplay.SetupScrolling()
3899    Size = mainSizer.Fit(G2frame.dataFrame)
3900    Size[0] += 25
3901    G2frame.dataDisplay.SetSize(Size)
3902    G2frame.dataFrame.setSizePosLeft(Size)   
3903   
3904################################################################################
3905#####  PDF controls
3906################################################################################           
3907       
3908def UpdatePDFGrid(G2frame,data):
3909    '''respond to selection of PWDR PDF data tree item.
3910    '''
3911    global inst
3912    tth2q = lambda t,w:4.0*math.pi*sind(t/2.0)/w
3913    dataFile = G2frame.PatternTree.GetItemText(G2frame.PatternId)
3914    powName = 'PWDR'+dataFile[4:]
3915    powId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root, powName)
3916    fullLimits,limits = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,powId, 'Limits'))[:2]
3917    inst = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,powId, 'Instrument Parameters'))[0]
3918    if 'Lam' in inst:
3919        keV = 12.397639/inst['Lam'][1]
3920    else:
3921        keV = 12.397639/inst['Lam1'][0]
3922    wave = 12.397639/keV
3923    qLimits = [tth2q(fullLimits[0],wave),tth2q(fullLimits[1],wave)]
3924    data['QScaleLim'][1] = min(qLimits[1],data['QScaleLim'][1])
3925    if data['QScaleLim'][0]:
3926        data['QScaleLim'][0] = max(qLimits[0],data['QScaleLim'][0])
3927    else:                                #initial setting at 90% of max Q
3928        data['QScaleLim'][0] = 0.90*data['QScaleLim'][1]
3929    polariz = inst['Polariz.'][1]
3930    azimuth = inst['Azimuth'][1]
3931    itemDict = {}
3932   
3933    def FillFileSizer(fileSizer,key):
3934        #fileSizer is a FlexGridSizer(3,6)
3935       
3936        def OnSelectFile(event):
3937            Obj = event.GetEventObject()
3938            fileKey,itemKey,fmt = itemDict[Obj.GetId()]
3939            if itemKey == 'Name':
3940                value = Obj.GetValue()
3941            Obj.SetValue(fmt%(value))
3942            data[fileKey][itemKey] = value
3943            UpdatePDFGrid(G2frame,data)
3944       
3945        def OnValueChange(event):
3946            Obj = event.GetEventObject()
3947            fileKey,itemKey,fmt = itemDict[Obj.GetId()]
3948            try:
3949                value = float(Obj.GetValue())
3950            except ValueError:
3951                value = -1.0
3952            Obj.SetValue(fmt%(value))
3953            data[fileKey][itemKey] = value
3954            auxPlot = ComputePDF(data)
3955            G2plt.PlotISFG(G2frame,newPlot=True)
3956                       
3957        item = data[key]
3958        fileList = np.array(GetFileList('PWDR')).T[1]
3959        fileSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' '+key+' file:'),0,WACV)
3960        fileName = wx.ComboBox(G2frame.dataDisplay,value=item['Name'],choices=fileList,
3961            style=wx.CB_READONLY|wx.CB_DROPDOWN)
3962        itemDict[fileName.GetId()] = [key,'Name','%s']
3963        fileName.Bind(wx.EVT_COMBOBOX,OnSelectFile)       
3964        fileSizer.Add(fileName,0,)
3965        fileSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label='Multiplier:'),0,WACV)
3966        mult = wx.TextCtrl(G2frame.dataDisplay,value='%.3f'%(item['Mult']),style=wx.TE_PROCESS_ENTER)
3967        itemDict[mult.GetId()] = [key,'Mult','%.3f']
3968        mult.Bind(wx.EVT_TEXT_ENTER,OnValueChange)       
3969        mult.Bind(wx.EVT_KILL_FOCUS,OnValueChange)
3970        fileSizer.Add(mult,0,)
3971        fileSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label='Add:'),0,WACV)
3972        add = wx.TextCtrl(G2frame.dataDisplay,value='%.0f'%(item['Add']),style=wx.TE_PROCESS_ENTER)
3973        itemDict[add.GetId()] = [key,'Add','%.0f']
3974        add.Bind(wx.EVT_TEXT_ENTER,OnValueChange)       
3975        add.Bind(wx.EVT_KILL_FOCUS,OnValueChange)
3976        fileSizer.Add(add,0,)
3977       
3978    def SumElementVolumes():
3979        sumVol = 0.
3980        ElList = data['ElList']
3981        for El in ElList:
3982            Avol = (4.*math.pi/3.)*ElList[El]['Drad']**3
3983            sumVol += Avol*ElList[El]['FormulaNo']
3984        return sumVol
3985        auxPlot = ComputePDF(data)
3986        G2plt.PlotISFG(G2frame,newPlot=True)       
3987       
3988    def FillElemSizer(elemSizer,ElData):
3989       
3990        def OnFractionChange(event):
3991            try:
3992                value = max(0.0,float(num.GetValue()))
3993            except ValueError:
3994                value = 0.0
3995            num.SetValue('%.3f'%(value))
3996            ElData['FormulaNo'] = value
3997            data['Form Vol'] = max(10.0,SumElementVolumes())
3998            formVol.SetValue('%.2f'%(data['Form Vol']))
3999            wx.CallAfter(UpdatePDFGrid,G2frame,data)
4000            auxPlot = ComputePDF(data)
4001            G2plt.PlotISFG(G2frame,newPlot=True)       
4002       
4003        elemSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,
4004            label=' Element: '+'%2s'%(ElData['Symbol'])+' * '),0,WACV)
4005        num = wx.TextCtrl(G2frame.dataDisplay,value='%.3f'%(ElData['FormulaNo']),style=wx.TE_PROCESS_ENTER)
4006        num.Bind(wx.EVT_TEXT_ENTER,OnFractionChange)       
4007        num.Bind(wx.EVT_KILL_FOCUS,OnFractionChange)
4008        elemSizer.Add(num,0,WACV)
4009        elemSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,
4010            label="f': %.3f"%(ElData['fp'])+' f": %.3f'%(ElData['fpp'])+' mu: %.2f barns'%(ElData['mu']) ),
4011            0,WACV)
4012           
4013    def OnGeometry(event):
4014        data['Geometry'] = geometry.GetValue()
4015        UpdatePDFGrid(G2frame,data)
4016        auxPlot = ComputePDF(data)
4017        G2plt.PlotISFG(G2frame,newPlot=True)       
4018       
4019    def OnDetType(event):
4020        data['DetType'] = detType.GetValue()
4021        UpdatePDFGrid(G2frame,data)
4022        auxPlot = ComputePDF(data)
4023        G2plt.PlotISFG(G2frame,newPlot=True)       
4024       
4025    def OnFormVol(event):
4026        try:
4027            value = float(formVol.GetValue())
4028            if value <= 0.0:
4029                raise ValueError
4030        except ValueError:
4031            value = data['Form Vol']
4032        data['Form Vol'] = value
4033        UpdatePDFGrid(G2frame,data)
4034        auxPlot = ComputePDF(data)
4035        G2plt.PlotISFG(G2frame,newPlot=False)       
4036       
4037    def OnDiameter(event):
4038        try:
4039            value = float(diam.GetValue())
4040            if value <= 0.0:
4041                raise ValueError
4042        except ValueError:
4043            value = data['Diam']
4044        data['Diam'] = value
4045        UpdatePDFGrid(G2frame,data)
4046        auxPlot = ComputePDF(data)
4047        G2plt.PlotISFG(G2frame,newPlot=False)
4048       
4049    def OnPolaVal(event):
4050        try:
4051            value = float(polaVal.GetValue())
4052            if not (0.0 <= value <= 1.0):
4053                raise ValueError
4054        except ValueError:
4055            value = inst['Polariz.'][1]
4056        inst['Polariz.'][1] = value
4057        polaVal.SetValue('%.2f'%(inst['Polariz.'][1]))
4058        UpdatePDFGrid(G2frame,data)
4059        auxPlot = ComputePDF(data)
4060        G2plt.PlotISFG(G2frame,newPlot=False)
4061               
4062    def OnAzimVal(event):
4063        try:
4064            value = float(azimVal.GetValue())
4065            if not (0. <= value <= 360.):
4066                raise ValueError
4067        except ValueError:
4068            value = inst['Azimuth'][1]
4069        inst['Azimuth'][1] = value
4070        azimVal.SetValue('%.1f'%(inst['Azimuth'][1]))
4071        UpdatePDFGrid(G2frame,data)
4072        auxPlot = ComputePDF(data)
4073        G2plt.PlotISFG(G2frame,newPlot=False)
4074                       
4075    def OnObliqCoeff(event):
4076        try:
4077            value = float(obliqCoeff.GetValue())
4078            if value < 0.0:
4079                raise ValueError
4080            elif value > 1.0:
4081                value = 1.0
4082        except ValueError:
4083            value = data['ObliqCoeff']
4084        data['ObliqCoeff'] = value
4085        obliqCoeff.SetValue('%.3f'%(value))
4086        auxPlot = ComputePDF(data)
4087        G2plt.PlotISFG(G2frame,newPlot=False)
4088       
4089    def OnRulandWdt(event):
4090        try:
4091            value = float(rulandWdt.GetValue())
4092            if value <= 0.001:
4093                raise ValueError
4094            elif value > 1.0:
4095                value = 1.0
4096        except ValueError:
4097            value = data['Ruland']
4098        data['Ruland'] = value
4099        rulandWdt.SetValue('%.3f'%(value))
4100        auxPlot = ComputePDF(data)
4101        G2plt.PlotISFG(G2frame,newPlot=False)
4102       
4103    def OnRulSlider(event):
4104        value = int(rulandSldr.GetValue())/1000.
4105        data['Ruland'] = max(0.001,value)
4106        rulandWdt.SetValue('%.3f'%(data['Ruland']))
4107        auxPlot = ComputePDF(data)
4108        G2plt.PlotISFG(G2frame,newPlot=False)
4109       
4110    def OnLorch(event):
4111        data['Lorch'] = lorch.GetValue()
4112        auxPlot = ComputePDF(data)
4113        G2plt.PlotISFG(G2frame,newPlot=False)       
4114                       
4115    def OnPacking(event):
4116        try:
4117            value = float(pack.GetValue())
4118            if value <= 0.0:
4119                raise ValueError
4120        except ValueError:
4121            value = data['Pack']
4122        data['Pack'] = value
4123        UpdatePDFGrid(G2frame,data)
4124        auxPlot = ComputePDF(data)
4125        G2plt.PlotISFG(G2frame,newPlot=False)       
4126               
4127    def OnSQmin(event):
4128        try:
4129            value = float(SQmin.GetValue())
4130            if value < qLimits[0]:
4131                raise ValueError
4132        except ValueError:
4133            value = max(qLimits[0],data['QScaleLim'][0])
4134        data['QScaleLim'][0] = value
4135        SQmin.SetValue('%.1f'%(value))
4136        auxPlot = ComputePDF(data)
4137        G2plt.PlotISFG(G2frame,newPlot=True)       
4138       
4139    def OnSQmax(event):
4140        try:
4141            value = float(SQmax.GetValue())
4142            if value > qLimits[1]:
4143                raise ValueError
4144        except ValueError:
4145            value = min(qLimits[1],data['QScaleLim'][1])
4146        data['QScaleLim'][1] = value
4147        if value < data['QScaleLim'][0]:
4148            data['QScaleLim'][0] = 0.90*value
4149            SQmin.SetValue('%.1f'%(data['QScaleLim'][0]))
4150        SQmax.SetValue('%.1f'%(value))
4151        auxPlot = ComputePDF(data)
4152        G2plt.PlotISFG(G2frame,newPlot=True)
4153       
4154    def OnResetQ(event):