source: trunk/GSASIIpwdGUI.py @ 1787

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

remove user reject HKL selection from Reflection List
implement rule bases user reject for HKLF reflections in Controls
user rejection changes mul to -mul; reflection list shows this in red
implement tool tip on 3Dhkl plots showing hkl indices on each point encountered

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