source: trunk/GSASIIpwdGUI.py @ 2090

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

eliminate duplicate index cells - much shorter list

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