source: trunk/GSASIIpwdGUI.py @ 1878

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

refactor DDataGUI - mostly move event routines to be inside respective sizer routines
Enable Flack parameter - function OK; derivatives need work
Allow inversion of noncentrosymmetric structures in SymOpDialog? - to test enantiomers
some work to make pdf stuff neutron TOF friendly - not complete
fix Debye background function - now works; refactor result printing for it

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