source: trunk/GSASIIpwdGUI.py @ 1969

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

3Dhkl plots fixed - zone plots & full allow 'P' & 'N' steps on origin

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 227.6 KB
Line 
1# -*- coding: utf-8 -*-
2#GSASIIpwdGUI - powder data display routines
3########### SVN repository information ###################
4# $Date: 2015-08-31 18:53:11 +0000 (Mon, 31 Aug 2015) $
5# $Author: vondreele $
6# $Revision: 1969 $
7# $URL: trunk/GSASIIpwdGUI.py $
8# $Id: GSASIIpwdGUI.py 1969 2015-08-31 18:53:11Z 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: 1969 $")
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 wirte 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    def keycheck(keys):
1185        good = []
1186        for key in keys:
1187            if key in ['Type','U','V','W','X','Y','SH/L','I(L2)/I(L1)','alpha',
1188                'beta-0','beta-1','beta-q','sig-0','sig-1','sig-2','sig-q','Polariz.',
1189                'Lam','Azimuth','2-theta','fltPath','difC','difA','difB','Zero','Lam1','Lam2']:
1190                good.append(key)
1191        return good
1192       
1193    def updateData(inst,ref):
1194        data = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,
1195            G2frame.PatternId,'Instrument Parameters'))[0]
1196        for item in data:
1197            try:
1198                data[item] = [data[item][0],inst[item],ref[item]]
1199            except KeyError:
1200                try:
1201                    data[item] = [data[item][0],inst[item]]
1202                except KeyError:
1203                    pass        #skip 'Polariz.' for N-data
1204   
1205    def RefreshInstrumentGrid(event,doAnyway=False):
1206        if doAnyway or event.GetRow() == 1:
1207            peaks = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Peak List'))
1208            newpeaks = []
1209            for peak in peaks['peaks']:
1210                newpeaks.append(G2mth.setPeakparms(data,Inst2,peak[0],peak[2]))
1211            peaks['peaks'] = newpeaks
1212            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Peak List'),peaks)
1213           
1214    def OnCalibrate(event):
1215        Pattern = G2frame.PatternTree.GetItemPyData(G2frame.PatternId)
1216        xye = ma.array(ma.getdata(Pattern[1]))
1217        cw = np.diff(xye[0])
1218        IndexPeaks = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Index Peak List'))
1219        if not len(IndexPeaks[0]):
1220            G2frame.ErrorDialog('Can not calibrate','Index Peak List empty')
1221            return
1222        if not np.any(IndexPeaks[1]):
1223            G2frame.ErrorDialog('Can not calibrate','Peak positions not refined')
1224            return False
1225        Ok = False
1226        for peak in IndexPeaks[0]:
1227            if peak[2] and peak[3]:
1228                Ok = True
1229        if not Ok:
1230            G2frame.ErrorDialog('Can not calibrate','Index Peak List not indexed')
1231            return           
1232        if G2pwd.DoCalibInst(IndexPeaks,data):
1233            UpdateInstrumentGrid(G2frame,data)
1234            XY = []
1235            Sigs = []
1236            for ip,peak in enumerate(IndexPeaks[0]):
1237                if peak[2] and peak[3]:
1238                    binwid = cw[np.searchsorted(xye[0],peak[0])]
1239                    XY.append([peak[-1],peak[0],binwid])
1240                    Sigs.append(IndexPeaks[1][ip])
1241            if len(XY):
1242                XY = np.array(XY)
1243                G2plt.PlotCalib(G2frame,data,XY,Sigs,newPlot=True)
1244        else:
1245            G2frame.ErrorDialog('Can not calibrate','Nothing selected for refinement')
1246
1247    def OnLoad(event):
1248        '''Loads instrument parameters from a G2 .instprm file
1249        in response to the Instrument Parameters-Operations/Load Profile menu
1250       
1251        Note that similar code is found in ReadPowderInstprm (GSASII.py)
1252        '''
1253        dlg = wx.FileDialog(G2frame, 'Choose GSAS-II instrument parameters file', '.', '', 
1254            'instrument parameter files (*.instprm)|*.instprm',wx.OPEN|wx.CHANGE_DIR)
1255        try:
1256            if dlg.ShowModal() == wx.ID_OK:
1257                filename = dlg.GetPath()
1258                File = open(filename,'r')
1259                S = File.readline()
1260                newItems = []
1261                newVals = []
1262                while S:
1263                    if S[0] == '#':
1264                        S = File.readline()
1265                        continue
1266                    [item,val] = S[:-1].split(':')
1267                    newItems.append(item)
1268                    try:
1269                        newVals.append(float(val))
1270                    except ValueError:
1271                        newVals.append(val)                       
1272                    S = File.readline()               
1273                File.close()
1274                Inst,Inst2 = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId,'Instrument Parameters'))
1275                data = G2IO.makeInstDict(newItems,newVals,len(newVals)*[False,])
1276                G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId,'Instrument Parameters'),[data,Inst2])
1277                RefreshInstrumentGrid(event,doAnyway=True)          #to get peaks updated
1278                UpdateInstrumentGrid(G2frame,data)
1279                G2plt.PlotPeakWidths(G2frame)
1280        finally:
1281            dlg.Destroy()
1282       
1283    def OnSave(event):
1284        '''Respond to the Instrument Parameters Operations/Save Profile menu
1285        item: writes current parameters to a .instprm file
1286        '''
1287        dlg = wx.FileDialog(G2frame, 'Choose GSAS-II instrument parameters file', '.', '', 
1288            'instrument parameter files (*.instprm)|*.instprm',wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT|wx.CHANGE_DIR)
1289        try:
1290            if dlg.ShowModal() == wx.ID_OK:
1291                filename = dlg.GetPath()
1292                # make sure extension is .instprm
1293                filename = os.path.splitext(filename)[0]+'.instprm'
1294                File = open(filename,'w')
1295                File.write("#GSAS-II instrument parameter file; do not add/delete items!\n")
1296                for item in data:
1297                    File.write(item+':'+str(data[item][1])+'\n')
1298                File.close()
1299        finally:
1300            dlg.Destroy()
1301                                               
1302    def OnReset(event):
1303        insVal.update(insDef)
1304        updateData(insVal,insRef)
1305        RefreshInstrumentGrid(event,doAnyway=True)          #to get peaks updated
1306        UpdateInstrumentGrid(G2frame,data)
1307        G2plt.PlotPeakWidths(G2frame)
1308       
1309    def OnInstFlagCopy(event):
1310        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
1311        histList = GetHistsLikeSelected(G2frame)
1312        if not histList:
1313            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
1314            return
1315        keys = data.keys()
1316        try:
1317            keys.remove('Source')
1318        except ValueError:
1319            pass
1320        flags = dict(zip(keys,[data[key][2] for key in keys]))
1321        instType = data['Type'][0]
1322        copyList = []
1323        dlg = G2G.G2MultiChoiceDialog(
1324            G2frame.dataFrame, 
1325            'Copy inst ref. flags from\n'+hst[5:],
1326            'Copy refinement flags', histList)
1327        try:
1328            if dlg.ShowModal() == wx.ID_OK:
1329                for i in dlg.GetSelections():
1330                    copyList.append(histList[i])
1331        finally:
1332            dlg.Destroy()
1333        for item in copyList:
1334            Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
1335            instData = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Instrument Parameters'))[0]
1336            if len(data) == len(instData) and instType == instData['Type'][0]:   #don't mix data types or lam & lam1/lam2 parms!
1337                for item in instData:
1338                    if item not in ['Source',]:
1339                        instData[item][2] = copy.copy(flags[item])
1340            else:
1341                print item+' not copied - instrument parameters not commensurate'
1342       
1343    def OnInstCopy(event):
1344        #need fix for dictionary
1345        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
1346        histList = GetHistsLikeSelected(G2frame)
1347        if not histList:
1348            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
1349            return
1350        copyList = []
1351        instType = data['Type'][0]
1352        dlg = G2G.G2MultiChoiceDialog(
1353            G2frame.dataFrame, 
1354            'Copy inst params from\n'+hst,
1355            'Copy parameters', histList)
1356        try:
1357            if dlg.ShowModal() == wx.ID_OK:
1358                for i in dlg.GetSelections(): 
1359                    copyList.append(histList[i])
1360        finally:
1361            dlg.Destroy()
1362        for item in copyList:
1363            Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
1364            instData = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Instrument Parameters'))[0]
1365            if len(data) == len(instData) and instType == instData['Type'][0]:  #don't mix data types or lam & lam1/lam2 parms!
1366                instData.update(data)
1367            else:
1368                print item+' not copied - instrument parameters not commensurate'
1369                         
1370    def AfterChange(invalid,value,tc):
1371        if invalid: return
1372        updateData(insVal,insRef)
1373       
1374    def OnItemRef(event):
1375        Obj = event.GetEventObject()
1376        item = RefObj[Obj.GetId()]
1377        insRef[item] = Obj.GetValue()
1378        updateData(insVal,insRef)
1379
1380    def OnCopy1Val(event):
1381        '''Select one instrument parameter value to edit and copy to many histograms
1382        optionally allow values to be edited in a table
1383        '''
1384        updateData(insVal,insRef)
1385        G2G.SelectEdit1Var(G2frame,data,labelLst,elemKeysLst,dspLst,refFlgElem)
1386        insVal.update({key:data[key][1] for key in instkeys})
1387        insRef.update({key:data[key][2] for key in instkeys})
1388        wx.CallAfter(MakeParameterWindow)
1389       
1390    def lblWdef(lbl,dec,val):
1391        'Label parameter showing the default value'
1392        fmt = "%15."+str(dec)+"f"
1393        return " " + lbl + " (" + (fmt % val).strip() + "): "
1394
1395    def RefineBox(item):
1396        'Define a refine checkbox with binding'
1397        wid = wx.CheckBox(G2frame.dataDisplay,label=' Refine?  ')
1398        wid.SetValue(bool(insRef[item]))
1399        RefObj[wid.GetId()] = item
1400        wid.Bind(wx.EVT_CHECKBOX, OnItemRef)
1401        return wid
1402
1403    def OnLamPick(event):
1404        data['Source'][1] = lamType = event.GetEventObject().GetValue()
1405        if 'P' in insVal['Type']:
1406            insVal['Lam1'] = waves[lamType][0]
1407            insVal['Lam2'] = waves[lamType][1]
1408        elif 'S' in insVal['Type'] and 'synch' not in lamType:
1409            insVal['Lam'] = meanwaves[lamType]
1410        updateData(insVal,insRef)
1411        i,j= wx.__version__.split('.')[0:2]
1412        if int(i)+int(j)/10. > 2.8:
1413            pass # repaint crashes wxpython 2.9
1414            wx.CallLater(100, MakeParameterWindow)
1415            #wx.CallAfter(MakeParameterWindow)
1416        else:
1417            wx.CallAfter(MakeParameterWindow)
1418
1419    def MakeParameterWindow():
1420        'Displays the Instrument parameters in the datadisplay frame'
1421        if G2frame.dataDisplay:
1422            G2frame.dataFrame.Clear()
1423        G2frame.dataFrame.SetLabel('Instrument Parameters')
1424        G2frame.dataDisplay = wx.Panel(G2frame.dataFrame)
1425        mainSizer = wx.BoxSizer(wx.VERTICAL)
1426        instSizer = wx.FlexGridSizer(0,6,5,5)
1427        subSizer = wx.BoxSizer(wx.HORIZONTAL)
1428        subSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' Histogram Type: '+insVal['Type']),0,WACV)
1429        mainSizer.Add(subSizer)
1430        labelLst[:],elemKeysLst[:],dspLst[:],refFlgElem[:] = [],[],[],[]
1431        if 'P' in insVal['Type']:                   #powder data
1432            if 'C' in insVal['Type']:               #constant wavelength
1433                labelLst.append('Azimuth angle')
1434                elemKeysLst.append(['Azimuth',1])
1435                dspLst.append([10,2])
1436                refFlgElem.append(None)                   
1437                if 'Lam1' in insVal:
1438                    subSizer = wx.BoxSizer(wx.HORIZONTAL)
1439                    subSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' Azimuth: '),0,WACV)
1440                    txt = '%7.2f'%(insVal['Azimuth'])
1441                    subSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,txt.strip()),0,WACV)
1442                    subSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,'   Ka1/Ka2: '),0,WACV)
1443                    txt = u%8.6f/%8.6f\xc5'%(insVal['Lam1'],insVal['Lam2'])
1444                    subSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,txt.strip()),0,WACV)
1445                    waveSizer = wx.BoxSizer(wx.HORIZONTAL)
1446                    waveSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,'  Source type: '),0,WACV)
1447                    # PATCH?: for now at least, Source is not saved anywhere before here
1448                    if 'Source' not in data: data['Source'] = ['CuKa','?']
1449                    choice = ['TiKa','CrKa','FeKa','CoKa','CuKa','MoKa','AgKa']
1450                    lamPick = wx.ComboBox(G2frame.dataDisplay,value=data['Source'][1],choices=choice,style=wx.CB_READONLY|wx.CB_DROPDOWN)
1451                    lamPick.Bind(wx.EVT_COMBOBOX, OnLamPick)
1452                    waveSizer.Add(lamPick,0)
1453                    subSizer.Add(waveSizer,0)
1454                    mainSizer.Add(subSizer)
1455                    instSizer.Add(wx.StaticText(
1456                        G2frame.dataDisplay,-1,
1457                        lblWdef('I(L2)/I(L1)',4,insDef['I(L2)/I(L1)'])),
1458                        0,WACV)
1459                    key = 'I(L2)/I(L1)'
1460                    labelLst.append(key)
1461                    elemKeysLst.append([key,1])
1462                    dspLst.append([10,4])
1463                    refFlgElem.append([key,2])                   
1464                    ratVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,insVal,key,nDig=(10,4),typeHint=float,OnLeave=AfterChange)
1465                    instSizer.Add(ratVal,0)
1466                    instSizer.Add(RefineBox(key),0,WACV)
1467                    instSizer.Add((5,5),0)
1468                    instSizer.Add((5,5),0)
1469                    instSizer.Add((5,5),0)               
1470                else: # single wavelength
1471                    instSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' Azimuth: '),0,WACV)
1472                    txt = '%7.2f'%(insVal['Azimuth'])
1473                    instSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,txt.strip()),0,WACV)
1474                    instSizer.Add((5,5),0)
1475                    key = 'Lam'
1476                    instSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,u' Lam (\xc5): (%10.6f)'%(insDef[key])),
1477                        0,WACV)
1478                    waveVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,insVal,key,nDig=(10,6),typeHint=float,OnLeave=AfterChange)
1479                    labelLst.append(u'Lam (\xc5)')
1480                    elemKeysLst.append([key,1])
1481                    dspLst.append([10,6])
1482                    instSizer.Add(waveVal,0,WACV)
1483                    refFlgElem.append([key,2])                   
1484                    instSizer.Add(RefineBox(key),0,WACV)
1485#                    if ifHisto:
1486#                        refFlgElem.append([key,2])                   
1487#                        instSizer.Add(RefineBox(key),0,WACV)
1488#                    else:
1489#                        refFlgElem.append(None)                   
1490#                        instSizer.Add((5,5),0)
1491                for item in ['Zero','Polariz.']:
1492                    if item in insDef:
1493                        labelLst.append(item)
1494                        elemKeysLst.append([item,1])
1495                        dspLst.append([10,4])
1496                        instSizer.Add(
1497                            wx.StaticText(G2frame.dataDisplay,-1,lblWdef(item,4,insDef[item])),
1498                            0,WACV)
1499                        itemVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,insVal,item,nDig=(10,4),typeHint=float,OnLeave=AfterChange)
1500                        instSizer.Add(itemVal,0,WACV)
1501                        refFlgElem.append([item,2])
1502                        instSizer.Add(RefineBox(item),0,WACV)
1503#                        if ifHisto:
1504#                            refFlgElem.append([item,2])
1505#                            instSizer.Add(RefineBox(item),0,WACV)
1506#                        else:
1507#                            refFlgElem.append(None)                   
1508#                            instSizer.Add((5,5),0)
1509                    else:                           #skip Polariz. for neutrons
1510                        instSizer.Add((5,5),0)
1511                        instSizer.Add((5,5),0)
1512                        instSizer.Add((5,5),0)
1513                for item in ['U','V','W','','X','Y','SH/L']:
1514                    if item == '':
1515                        instSizer.Add((5,5),0)
1516                        instSizer.Add((5,5),0)
1517                        instSizer.Add((5,5),0)
1518                        continue
1519                    nDig = (10,3)
1520                    if item == 'SH/L':
1521                        nDig = (10,5)
1522                    labelLst.append(item)
1523                    elemKeysLst.append([item,1])
1524                    dspLst.append(nDig)
1525                    refFlgElem.append([item,2])
1526                    instSizer.Add(
1527                        wx.StaticText(G2frame.dataDisplay,-1,lblWdef(item,nDig[1],insDef[item])),
1528                        0,WACV)
1529                    itemVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,insVal,item,nDig=nDig,typeHint=float,OnLeave=AfterChange)
1530                    instSizer.Add(itemVal,0,WACV)
1531                    instSizer.Add(RefineBox(item),0,WACV)
1532            elif 'T' in insVal['Type']:                                   #time of flight (neutrons)
1533                subSizer = wx.BoxSizer(wx.HORIZONTAL)
1534                subSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' Fligth path: '),0,WACV)
1535                txt = '%8.3f'%(insVal['fltPath'])
1536                subSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,txt.strip()),0,WACV)
1537                labelLst.append('flight path')
1538                elemKeysLst.append(['fltpath',1])
1539                dspLst.append([10,2])
1540                refFlgElem.append(None)                   
1541                subSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,'  2-theta: '),0,WACV)
1542                txt = '%7.2f'%(insVal['2-theta'])
1543                subSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,txt.strip()),0,WACV)
1544                labelLst.append('2-theta')
1545                elemKeysLst.append(['2-theta',1])
1546                dspLst.append([10,2])
1547                refFlgElem.append(None)                   
1548                if 'Pdabc' in Inst2:
1549                    Items = ['sig-0','sig-1','sig-2','sig-q','X','Y']
1550                    subSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,'  difC: '),0,WACV)
1551                    txt = '%8.2f'%(insVal['difC'])
1552                    subSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,txt.strip()),0,WACV)
1553                    labelLst.append('difC')
1554                    elemKeysLst.append(['difC',1])
1555                    dspLst.append([10,2])
1556                    refFlgElem.append(None)
1557                    subSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,'  alpha, beta: fixed by table'),0,WACV)
1558                else:
1559                    Items = ['difC','difA','difB','Zero','alpha','beta-0','beta-1','beta-q','sig-0','sig-1','sig-2','sig-q','X','Y']
1560                mainSizer.Add((5,5),0)
1561                mainSizer.Add(subSizer)
1562                mainSizer.Add((5,5),0)
1563                for item in Items:
1564                    if item == '':
1565                        instSizer.Add((5,5),0)
1566                        instSizer.Add((5,5),0)
1567                        instSizer.Add((5,5),0)
1568                        continue
1569                    nDig = (10,3)
1570                    fmt = '%10.3f'
1571                    if 'beta' in item:
1572                        fmt = '%12.6g'
1573                        nDig = (12,6)
1574                    Fmt = ' %s: ('+fmt+')'
1575                    instSizer.Add(
1576                            wx.StaticText(G2frame.dataDisplay,-1,lblWdef(item,nDig[1],insDef[item])),
1577                            0,WACV)
1578                    itemVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,insVal,item,nDig=nDig,typeHint=float,OnLeave=AfterChange)
1579                    instSizer.Add(itemVal,0,WACV)
1580                    labelLst.append(item)
1581                    elemKeysLst.append([item,1])
1582                    dspLst.append(nDig)
1583                    refFlgElem.append([item,2])
1584                    instSizer.Add(RefineBox(item),0,WACV)
1585            elif 'PKS' in insVal['Type']:   #peak positions only
1586                key = 'Lam'
1587                instSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,u' Lam (\xc5): (%10.6f)'%(insDef[key])),
1588                    0,WACV)
1589                waveVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,insVal,key,nDig=(10,6),typeHint=float,OnLeave=AfterChange)
1590                labelLst.append(u'Lam (\xc5)')
1591                elemKeysLst.append([key,1])
1592                dspLst.append([10,6])
1593                instSizer.Add(waveVal,0,WACV)
1594                refFlgElem.append([key,2])                   
1595#                    instSizer.Add(RefineBox(key),0,WACV)
1596                for item in ['Zero',]:
1597                    if item in insDef:
1598                        labelLst.append(item)
1599                        elemKeysLst.append([item,1])
1600                        dspLst.append([10,4])
1601                        instSizer.Add(
1602                            wx.StaticText(G2frame.dataDisplay,-1,lblWdef(item,4,insDef[item])),
1603                            0,WACV)
1604                        itemVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,insVal,item,nDig=(10,4),typeHint=float,OnLeave=AfterChange)
1605                        instSizer.Add(itemVal,0,WACV)
1606                        refFlgElem.append([item,2])
1607#                        instSizer.Add(RefineBox(item),0,WACV)
1608               
1609               
1610        elif 'S' in insVal['Type']:                       #single crystal data
1611            if 'C' in insVal['Type']:               #constant wavelength
1612                instSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,u' Lam (\xc5): (%10.6f)'%(insDef['Lam'])),
1613                    0,WACV)
1614                waveVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,insVal,'Lam',nDig=(10,6),typeHint=float,OnLeave=AfterChange)
1615                instSizer.Add(waveVal,0,WACV)
1616                labelLst.append(u'Lam (\xc5)')
1617                waveSizer = wx.BoxSizer(wx.HORIZONTAL)
1618                waveSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,'  Source type: '),0,WACV)
1619                # PATCH?: for now at least, Source is not saved anywhere before here
1620                if 'Source' not in data: data['Source'] = ['CuKa','?']
1621                choice = ['synchrotron','TiKa','CrKa','FeKa','CoKa','CuKa','MoKa','AgKa']
1622                lamPick = wx.ComboBox(G2frame.dataDisplay,value=data['Source'][1],choices=choice,style=wx.CB_READONLY|wx.CB_DROPDOWN)
1623                lamPick.Bind(wx.EVT_COMBOBOX, OnLamPick)
1624                waveSizer.Add(lamPick,0,WACV)
1625                instSizer.Add(waveSizer,0,WACV)
1626                elemKeysLst.append(['Lam',1])
1627                dspLst.append([10,6])
1628                refFlgElem.append(None)
1629            else:                                   #time of flight (neutrons)
1630                pass                                #for now
1631        elif 'L' in insVal['Type']:
1632            if 'C' in insVal['Type']:       
1633                instSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,u' Lam (\xc5): (%10.6f)'%(insDef['Lam'])),
1634                    0,WACV)
1635                waveVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,insVal,'Lam',nDig=(10,6),typeHint=float,OnLeave=AfterChange)
1636                instSizer.Add(waveVal,0,WACV)
1637                labelLst.append(u'Lam (\xc5)')
1638                elemKeysLst.append(['Lam',1])
1639                dspLst.append([10,6])
1640                refFlgElem.append(None)
1641                instSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,'  Azimuth: %7.2f'%(insVal['Azimuth'])),0,WACV)
1642                labelLst.append('Azimuth angle')
1643                elemKeysLst.append(['Azimuth',1])
1644                dspLst.append([10,2])
1645                refFlgElem.append(None)                   
1646            else:                                   #time of flight (neutrons)
1647                pass                                #for now
1648
1649        mainSizer.Add(instSizer,0)
1650        mainSizer.Layout()   
1651        G2frame.dataDisplay.SetSizer(mainSizer)
1652        G2frame.dataFrame.setSizePosLeft(mainSizer.Fit(G2frame.dataFrame))
1653        G2frame.dataFrame.SendSizeEvent()  # this causes a frame repaint, even if the size does not change!
1654        # end of MakeParameterWindow
1655               
1656    # beginning of UpdateInstrumentGrid code   
1657    #patch: make sure all parameter items are lists
1658    patched = 0
1659    for key in data:
1660        if type(data[key]) is tuple:
1661            data[key] = list(data[key])
1662            patched += 1
1663    if patched: print patched,' instrument parameters changed from tuples'
1664    #end of patch
1665    labelLst,elemKeysLst,dspLst,refFlgElem = [],[],[],[]
1666    instkeys = keycheck(data.keys())
1667    if 'P' in data['Type'][0]:          #powder data
1668        insVal = dict(zip(instkeys,[data[key][1] for key in instkeys]))
1669        insDef = dict(zip(instkeys,[data[key][0] for key in instkeys]))
1670        insRef = dict(zip(instkeys,[data[key][2] for key in instkeys]))
1671        if 'NC' in data['Type'][0]:
1672            del(insDef['Polariz.'])
1673            del(insVal['Polariz.'])
1674            del(insRef['Polariz.'])
1675    elif 'S' in data['Type'][0]:                               #single crystal data
1676        insVal = dict(zip(instkeys,[data[key][1] for key in instkeys]))
1677        insDef = dict(zip(instkeys,[data[key][0] for key in instkeys]))
1678        insRef = {}
1679    elif 'L' in data['Type'][0]:                               #low angle data
1680        insVal = dict(zip(instkeys,[data[key][1] for key in instkeys]))
1681        insDef = dict(zip(instkeys,[data[key][0] for key in instkeys]))
1682        insRef = {}
1683    ValObj = {}
1684    RefObj = {}
1685    waves = {'CuKa':[1.54051,1.54433],'TiKa':[2.74841,2.75207],'CrKa':[2.28962,2.29351],
1686        'FeKa':[1.93597,1.93991],'CoKa':[1.78892,1.79278],'MoKa':[0.70926,0.713543],
1687        'AgKa':[0.559363,0.563775]}
1688    meanwaves = {'CuKa':1.5418,'TiKa':2.7496,'CrKa':2.2909,'FeKa':1.9373,
1689        'CoKa':1.7902,'MoKa':0.7107,'AgKa':0.5608}
1690    Inst2 = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,
1691            G2frame.PatternId,'Instrument Parameters'))[1]       
1692    try:
1693        histoName = G2frame.PatternTree.GetItemPyData(G2frame.PatternId)[-1]
1694        ifHisto = IsHistogramInAnyPhase(G2frame,histoName)
1695    except TypeError:       #PKS data never used in a phase as data
1696        ifhisto = False
1697    G2gd.SetDataMenuBar(G2frame)
1698    #patch
1699    if 'P' in insVal['Type']:                   #powder data
1700        if 'C' in insVal['Type']:               #constant wavelength
1701            if 'Azimuth' not in insVal:
1702                insVal['Azimuth'] = 0.0
1703                insDef['Azimuth'] = 0.0
1704                insRef['Azimuth'] = False
1705#        if 'T' in insVal['Type']:
1706#            if 'difB' not in insVal:
1707#                insVal['difB'] = 0.0
1708#                insDef['difB'] = 0.0
1709#                insRef['difB'] = False
1710    #end of patch
1711    if 'P' in insVal['Type']:                   #powder data menu commands
1712        G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.InstMenu)
1713        if not G2frame.dataFrame.GetStatusBar():
1714            Status = G2frame.dataFrame.CreateStatusBar()           
1715            Status.SetStatusText('NB: Azimuth is used for polarization only')
1716        G2frame.Bind(wx.EVT_MENU,OnCalibrate,id=G2gd.wxID_INSTCALIB)
1717        G2frame.Bind(wx.EVT_MENU,OnLoad,id=G2gd.wxID_INSTLOAD)
1718        G2frame.Bind(wx.EVT_MENU,OnSave,id=G2gd.wxID_INSTSAVE)
1719        G2frame.Bind(wx.EVT_MENU,OnReset,id=G2gd.wxID_INSTPRMRESET)
1720        G2frame.Bind(wx.EVT_MENU,OnInstCopy,id=G2gd.wxID_INSTCOPY)
1721        G2frame.Bind(wx.EVT_MENU,OnInstFlagCopy,id=G2gd.wxID_INSTFLAGCOPY)
1722        #G2frame.Bind(wx.EVT_MENU,OnWaveChange,id=G2gd.wxID_CHANGEWAVETYPE)       
1723        G2frame.Bind(wx.EVT_MENU,OnCopy1Val,id=G2gd.wxID_INST1VAL)
1724    elif 'L' in insVal['Type']:                   #SASD data menu commands
1725        G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.InstMenu)
1726        if not G2frame.dataFrame.GetStatusBar():
1727            Status = G2frame.dataFrame.CreateStatusBar()
1728        G2frame.Bind(wx.EVT_MENU,OnInstCopy,id=G2gd.wxID_INSTCOPY)
1729    MakeParameterWindow()
1730       
1731   
1732################################################################################
1733#####  Sample parameters
1734################################################################################           
1735       
1736def UpdateSampleGrid(G2frame,data):
1737    '''respond to selection of PWDR/SASD Sample Parameters
1738    data tree item.
1739    '''
1740
1741    def OnSampleSave(event):
1742        '''Respond to the Sample Parameters Operations/Save menu
1743        item: writes current parameters to a .samprm file
1744        '''
1745        dlg = wx.FileDialog(G2frame, 'Choose GSAS-II sample parameters file', '.', '', 
1746            'sample parameter files (*.samprm)|*.samprm',wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT|wx.CHANGE_DIR)
1747        try:
1748            if dlg.ShowModal() == wx.ID_OK:
1749                filename = dlg.GetPath()
1750                # make sure extension is .samprm
1751                filename = os.path.splitext(filename)[0]+'.samprm'
1752                File = open(filename,'w')
1753                File.write("#GSAS-II sample parameter file\n")
1754                File.write("'Type':'"+str(data['Type'])+"'\n")
1755                File.write("'Gonio. radius':"+str(data['Gonio. radius'])+"\n")
1756                if data.get('InstrName'):
1757                    File.write("'InstrName':'"+str(data['InstrName'])+"'\n")
1758                File.close()
1759        finally:
1760            dlg.Destroy()
1761           
1762    def OnSampleLoad(event):
1763        '''Loads sample parameters from a G2 .samprm file
1764        in response to the Sample Parameters-Operations/Load menu
1765       
1766        Note that similar code is found in ReadPowderInstprm (GSASII.py)
1767        '''
1768        dlg = wx.FileDialog(G2frame, 'Choose GSAS-II sample parameters file', '.', '', 
1769            'sample parameter files (*.samprm)|*.samprm',wx.OPEN|wx.CHANGE_DIR)
1770        try:
1771            if dlg.ShowModal() == wx.ID_OK:
1772                filename = dlg.GetPath()
1773                File = open(filename,'r')
1774                S = File.readline()
1775                newItems = {}
1776                while S:
1777                    if S[0] == '#':
1778                        S = File.readline()
1779                        continue
1780                    [item,val] = S[:-1].split(':')
1781                    newItems[item.strip("'")] = eval(val)
1782                    S = File.readline()               
1783                File.close()
1784                data.update(newItems)
1785                G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId,'Sample Parameters'),data)
1786                UpdateSampleGrid(G2frame,data)
1787        finally:
1788            dlg.Destroy()
1789           
1790    def OnAllSampleLoad(event):
1791        filename = ''
1792        dlg = wx.FileDialog(G2frame, 'Choose multihistogram metadata text file', '.', '', 
1793            'metadata file (*.*)|*.*',wx.OPEN|wx.CHANGE_DIR)
1794        try:
1795            if dlg.ShowModal() == wx.ID_OK:
1796                filename = dlg.GetPath()
1797                File = open(filename,'r')
1798                S = File.readline()
1799                newItems = []
1800                itemNames = []
1801                Comments = []
1802                while S:
1803                    if S[0] == '#':
1804                        Comments.append(S)
1805                        S = File.readline()
1806                        continue
1807                    S = S.replace(',',' ').replace('\t',' ')
1808                    Stuff = S[:-1].split()
1809                    itemNames.append(Stuff[0])
1810                    newItems.append(Stuff[1:])
1811                    S = File.readline()               
1812                File.close()
1813        finally:
1814            dlg.Destroy()
1815        if not filename:
1816            G2frame.ErrorDialog('Nothing to do','No file selected')
1817            return
1818        dataDict = dict(zip(itemNames,newItems))
1819        ifany = False
1820        Controls = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Controls'))
1821        Names = [' ','Phi','Chi','Omega','Time','Temperature','Pressure']
1822        freeNames = {}
1823        for name in ['FreePrm1','FreePrm2','FreePrm3']:
1824            freeNames[Controls[name]] = name
1825            Names.append(Controls[name])
1826        dlg = G2G.G2ColumnIDDialog( G2frame,' Choose multihistogram metadata columns:',
1827            'Select columns',Comments,Names,np.array(newItems).T)
1828        try:
1829            if dlg.ShowModal() == wx.ID_OK:
1830                colNames,newData = dlg.GetSelection()
1831                dataDict = dict(zip(itemNames,newData.T))
1832                for item in colNames:
1833                    if item != ' ':
1834                        ifany = True
1835        finally:
1836            dlg.Destroy()
1837        if not ifany:
1838            G2frame.ErrorDialog('Nothing to do','No columns identified')
1839            return
1840        histList = [G2frame.PatternTree.GetItemText(G2frame.PatternId),]
1841        histList += GetHistsLikeSelected(G2frame)
1842        colIds = {}
1843        for i,name in enumerate(colNames):
1844            if name != ' ':
1845                colIds[name] = i
1846        for hist in histList:
1847            name = hist.split()[1]  #this is file name
1848            newItems = {}
1849            for item in colIds:
1850                key = freeNames.get(item,item)
1851                newItems[key] = float(dataDict[name][colIds[item]])
1852            Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,hist)
1853            sampleData = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Sample Parameters'))
1854            sampleData.update(newItems)       
1855        UpdateSampleGrid(G2frame,data)       
1856   
1857    def OnSetScale(event):
1858        histList = []
1859        item, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)
1860        while item:
1861            name = G2frame.PatternTree.GetItemText(item)
1862            if 'SASD' in name and name != histName:
1863                histList.append(name)
1864            item, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)
1865        if not len(histList):      #nothing to copy to!
1866            return
1867        dlg = wx.SingleChoiceDialog(G2frame,'Select reference histogram for scaling',
1868            'Reference histogram',histList)
1869        try:
1870            if dlg.ShowModal() == wx.ID_OK:
1871                sel = dlg.GetSelection()
1872                refHist = histList[sel]
1873        finally:
1874            dlg.Destroy()
1875        Limits = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Limits'))
1876        Profile = G2frame.PatternTree.GetItemPyData(G2frame.PatternId)[1]
1877        Data = [Profile,Limits,data]
1878        refId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,refHist)
1879        refSample = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,refId, 'Sample Parameters'))
1880        refLimits = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,refId, 'Limits'))
1881        refProfile = G2frame.PatternTree.GetItemPyData(refId)[1]
1882        refData = [refProfile,refLimits,refSample]
1883        G2sasd.SetScale(Data,refData)
1884        G2plt.PlotPatterns(G2frame,plotType='SASD',newPlot=True)
1885        UpdateSampleGrid(G2frame,data)       
1886       
1887    def OnSampleCopy(event):
1888        histType,copyNames = SetCopyNames(histName,data['Type'],
1889            addNames = ['Omega','Chi','Phi','Gonio. radius','InstrName'])
1890        copyDict = {}
1891        for parm in copyNames:
1892            copyDict[parm] = data[parm]
1893        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
1894        histList = GetHistsLikeSelected(G2frame)
1895        if not histList:
1896            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
1897            return
1898        dlg = G2G.G2MultiChoiceDialog(
1899            G2frame.dataFrame,
1900            'Copy sample params from\n'+str(hst[5:])+' to...',
1901            'Copy sample parameters', histList)
1902        try:
1903            if dlg.ShowModal() == wx.ID_OK:
1904                result = dlg.GetSelections()
1905                for i in result: 
1906                    item = histList[i]
1907                    Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
1908                    sampleData = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Sample Parameters'))
1909                    sampleData.update(copy.deepcopy(copyDict))
1910        finally:
1911            dlg.Destroy()
1912
1913    def OnSampleCopySelected(event):
1914        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
1915        Controls = G2frame.PatternTree.GetItemPyData(
1916            G2gd.GetPatternTreeItemId(G2frame,G2frame.root, 'Controls'))
1917        histList = GetHistsLikeSelected(G2frame)
1918        if not histList:
1919            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
1920            return
1921        # Assemble a list of item labels
1922        TextTable = {key:label for key,label,dig in
1923                     SetupSampleLabels(hst,data.get('Type'),Inst['Type'][0])
1924                     }
1925        # get flexible labels
1926        TextTable.update({
1927            key:Controls[key] for key in Controls if key.startswith('FreePrm')
1928            })
1929        # add a few extra
1930        TextTable.update({
1931            'Type':'Diffractometer type',
1932            'InstrName':'Instrument Name',
1933            })
1934        # Assemble a list of dict entries that would be labeled in the Sample
1935        # params data window (drop ranId and items not used).
1936        keyList = [i for i in data.keys() if i in TextTable]
1937        keyText = [TextTable[i] for i in keyList]
1938        # sort both lists together, ordered by keyText
1939        keyText, keyList = zip(*sorted(zip(keyText,keyList))) # sort lists
1940        selectedKeys = []
1941        dlg = G2G.G2MultiChoiceDialog(
1942            G2frame.dataFrame,
1943            'Select which sample parameters\nto copy',
1944            'Select sample parameters', keyText)
1945        try:
1946            if dlg.ShowModal() == wx.ID_OK:
1947                selectedKeys = [keyList[i] for i in dlg.GetSelections()]
1948        finally:
1949            dlg.Destroy()
1950        if not selectedKeys: return # nothing to copy
1951        copyDict = {}
1952        for parm in selectedKeys:
1953            copyDict[parm] = data[parm]
1954        dlg = G2G.G2MultiChoiceDialog(
1955            G2frame.dataFrame,
1956            'Copy sample params from\n'+str(hst[5:])+' to...',
1957            'Copy sample parameters', histList)
1958        try:
1959            if dlg.ShowModal() == wx.ID_OK:
1960                result = dlg.GetSelections()
1961                for i in result: 
1962                    item = histList[i]
1963                    Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
1964                    sampleData = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Sample Parameters'))
1965                    sampleData.update(copy.deepcopy(copyDict))
1966        finally:
1967            dlg.Destroy()           
1968        G2plt.PlotPatterns(G2frame,plotType=hst[:4],newPlot=False)
1969
1970    def OnSampleFlagCopy(event):
1971        histType,copyNames = SetCopyNames(histName,data['Type'])
1972        flagDict = {}
1973        for parm in copyNames:
1974            flagDict[parm] = data[parm][1]
1975        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
1976        histList = GetHistsLikeSelected(G2frame)
1977        if not histList:
1978            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
1979            return
1980        dlg = G2G.G2MultiChoiceDialog(
1981            G2frame.dataFrame, 
1982            'Copy sample ref. flags from\n'+str(hst[5:])+' to...',
1983            'Copy sample flags', histList)
1984        try:
1985            if dlg.ShowModal() == wx.ID_OK:
1986                result = dlg.GetSelections()
1987                for i in result: 
1988                    item = histList[i]
1989                    Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
1990                    sampleData = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Sample Parameters'))
1991                    for name in copyNames:
1992                        sampleData[name][1] = copy.copy(flagDict[name])
1993        finally:
1994            dlg.Destroy()
1995
1996    def OnHistoChange():
1997        '''Called when the histogram type is changed to refresh the window
1998        '''
1999        #wx.CallAfter(UpdateSampleGrid,G2frame,data)
2000        wx.CallLater(100,UpdateSampleGrid,G2frame,data)
2001       
2002    def SetNameVal():
2003        inst = instNameVal.GetValue()
2004        data['InstrName'] = inst.strip()
2005
2006    def OnNameVal(event):
2007        event.Skip()
2008        wx.CallAfter(SetNameVal)
2009       
2010    def AfterChange(invalid,value,tc):
2011        if invalid:
2012            return
2013        if tc.key == 0 and 'SASD' in histName:          #a kluge for Scale!
2014            G2plt.PlotPatterns(G2frame,plotType='SASD',newPlot=True)
2015        elif tc.key == 'Thick':
2016            wx.CallAfter(UpdateSampleGrid,G2frame,data)           
2017           
2018    def OnMaterial(event):
2019        Obj = event.GetEventObject()
2020        id,key = Info[Obj.GetId()]
2021        if key == 'Name':
2022            data['Materials'][id][key] = Obj.GetValue()
2023        elif key == 'VolFrac':
2024            try:
2025                value = min(max(0.,float(Obj.GetValue())),1.)
2026            except ValueError:
2027                value = data['Materials'][id][key]
2028            data['Materials'][id][key] = value
2029            data['Materials'][not id][key] = 1.-value
2030        wx.CallAfter(UpdateSampleGrid,G2frame,data)
2031
2032    def OnCopy1Val(event):
2033        'Select one value to copy to many histograms and optionally allow values to be edited in a table'
2034        G2G.SelectEdit1Var(G2frame,data,labelLst,elemKeysLst,dspLst,refFlgElem)
2035        wx.CallAfter(UpdateSampleGrid,G2frame,data)
2036       
2037    ######## DEBUG #######################################################
2038    #import GSASIIpwdGUI
2039    #reload(GSASIIpwdGUI)
2040    #reload(G2gd)
2041    ######################################################################
2042    Inst = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(
2043            G2frame,G2frame.PatternId, 'Instrument Parameters'))[0]
2044    histName = G2frame.PatternTree.GetItemText(G2frame.PatternId)
2045    if G2frame.dataDisplay:
2046        G2frame.dataFrame.Clear()
2047    G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.SampleMenu)
2048    G2frame.dataFrame.SetLabel('Sample Parameters')
2049    G2frame.Bind(wx.EVT_MENU, OnSetScale, id=G2gd.wxID_SETSCALE)
2050    G2frame.Bind(wx.EVT_MENU, OnSampleCopy, id=G2gd.wxID_SAMPLECOPY)
2051    G2frame.Bind(wx.EVT_MENU, OnSampleCopySelected, id=G2gd.wxID_SAMPLECOPYSOME)
2052    G2frame.Bind(wx.EVT_MENU, OnSampleFlagCopy, id=G2gd.wxID_SAMPLEFLAGCOPY)
2053    G2frame.Bind(wx.EVT_MENU, OnSampleSave, id=G2gd.wxID_SAMPLESAVE)
2054    G2frame.Bind(wx.EVT_MENU, OnSampleLoad, id=G2gd.wxID_SAMPLELOAD)
2055    G2frame.Bind(wx.EVT_MENU, OnCopy1Val, id=G2gd.wxID_SAMPLE1VAL)
2056    G2frame.Bind(wx.EVT_MENU, OnAllSampleLoad, id=G2gd.wxID_ALLSAMPLELOAD)
2057    if 'SASD' in histName:
2058        G2frame.dataFrame.SetScale.Enable(True)
2059    if not G2frame.dataFrame.GetStatusBar():
2060        Status = G2frame.dataFrame.CreateStatusBar()   
2061    G2frame.dataDisplay = wx.Panel(G2frame.dataFrame)
2062    Controls = G2frame.PatternTree.GetItemPyData(
2063        G2gd.GetPatternTreeItemId(G2frame,G2frame.root, 'Controls'))
2064#patch
2065    if 'ranId' not in data:
2066        data['ranId'] = ran.randint(0,sys.maxint)
2067    if not 'Gonio. radius' in data:
2068        data['Gonio. radius'] = 200.0
2069    if not 'Omega' in data:
2070        data.update({'Omega':0.0,'Chi':0.0,'Phi':0.0})
2071    if 'Azimuth' not in data:
2072        data['Azimuth'] = 0.0
2073    if type(data['Temperature']) is int:
2074        data['Temperature'] = float(data['Temperature'])
2075    if 'Time' not in data:
2076        data['Time'] = 0.0
2077    if 'FreePrm1' not in Controls:
2078        Controls['FreePrm1'] = 'Sample humidity (%)'
2079    if 'FreePrm2' not in Controls:
2080        Controls['FreePrm2'] = 'Sample voltage (V)'
2081    if 'FreePrm3' not in Controls:
2082        Controls['FreePrm3'] = 'Applied load (MN)'
2083    if 'FreePrm1' not in data:
2084        data['FreePrm1'] = 0.
2085    if 'FreePrm2' not in data:
2086        data['FreePrm2'] = 0.
2087    if 'FreePrm3' not in data:
2088        data['FreePrm3'] = 0.
2089    if 'SurfRoughA' not in data and 'PWDR' in histName:
2090        data['SurfRoughA'] = [0.,False]
2091        data['SurfRoughB'] = [0.,False]
2092    if 'Trans' not in data and 'SASD' in histName:
2093        data['Trans'] = 1.0
2094    if 'SlitLen' not in data and 'SASD' in histName:
2095        data['SlitLen'] = 0.0
2096    if 'Shift' not in data:
2097        data['Shift'] = [0.0,False]
2098    if 'Transparency' not in data:
2099        data['Transparency'] = [0.0,False]
2100    data['InstrName'] = data.get('InstrName','')
2101#patch end
2102    labelLst,elemKeysLst,dspLst,refFlgElem = [],[],[],[]
2103    parms = SetupSampleLabels(histName,data.get('Type'),Inst['Type'][0])
2104    mainSizer = wx.BoxSizer(wx.VERTICAL)
2105    topSizer = wx.BoxSizer(wx.HORIZONTAL)
2106    topSizer.Add((-1,-1),1,wx.EXPAND,1)
2107    topSizer.Add(wx.StaticText(G2frame.dataDisplay,label='Sample and Experimental Parameters'))
2108    topSizer.Add((-1,-1),1,wx.EXPAND,1)
2109    mainSizer.Add(topSizer,0,wx.EXPAND,1)
2110    nameSizer = wx.BoxSizer(wx.HORIZONTAL)
2111    nameSizer.Add(wx.StaticText(G2frame.dataDisplay,wx.ID_ANY,' Instrument Name'),
2112                0,WACV)
2113    nameSizer.Add((-1,-1),1,wx.EXPAND,1)
2114    instNameVal = wx.TextCtrl(G2frame.dataDisplay,wx.ID_ANY,data['InstrName'],
2115                              size=(200,-1),style=wx.TE_PROCESS_ENTER)       
2116    nameSizer.Add(instNameVal)
2117    instNameVal.Bind(wx.EVT_CHAR,OnNameVal)
2118    mainSizer.Add(nameSizer,0,wx.EXPAND,1)
2119    mainSizer.Add((5,5),0)
2120    labelLst.append('Instrument Name')
2121    elemKeysLst.append(['InstrName'])
2122    dspLst.append(None)
2123    refFlgElem.append(None)
2124
2125    if 'PWDR' in histName:
2126        nameSizer = wx.BoxSizer(wx.HORIZONTAL)
2127        nameSizer.Add(wx.StaticText(G2frame.dataDisplay,wx.ID_ANY,' Diffractometer type: '),
2128                    0,WACV)
2129        if 'T' in Inst['Type'][0]:
2130            choices = ['Debye-Scherrer',]
2131        else:
2132            choices = ['Debye-Scherrer','Bragg-Brentano',]
2133        histoType = G2G.G2ChoiceButton(G2frame.dataDisplay,choices,
2134                    strLoc=data,strKey='Type',
2135                    onChoice=OnHistoChange)
2136        nameSizer.Add(histoType)
2137        mainSizer.Add(nameSizer,0,wx.EXPAND,1)
2138        mainSizer.Add((5,5),0)
2139
2140    parmSizer = wx.FlexGridSizer(0,2,5,0)
2141    for key,lbl,nDig in parms:
2142        labelLst.append(lbl.strip().strip(':').strip())
2143        dspLst.append(nDig)
2144        if 'list' in str(type(data[key])):
2145            parmRef = G2G.G2CheckBox(G2frame.dataDisplay,' '+lbl,data[key],1)
2146            parmSizer.Add(parmRef,0,WACV|wx.EXPAND)
2147            parmVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,data[key],0,
2148                nDig=nDig,typeHint=float,OnLeave=AfterChange)
2149            elemKeysLst.append([key,0])
2150            refFlgElem.append([key,1])
2151        else:
2152            parmSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' '+lbl),
2153                0,WACV|wx.EXPAND)
2154            parmVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,data,key,
2155                typeHint=float,OnLeave=AfterChange)
2156            elemKeysLst.append([key])
2157            refFlgElem.append(None)
2158        parmSizer.Add(parmVal,1,wx.EXPAND)
2159    Info = {}
2160       
2161    for key in ('FreePrm1','FreePrm2','FreePrm3'):
2162        parmVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,Controls,key,typeHint=str,
2163                                        notBlank=False)
2164        parmSizer.Add(parmVal,1,wx.EXPAND)
2165        parmVal = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,data,key,typeHint=float)
2166        parmSizer.Add(parmVal,1,wx.EXPAND)
2167        labelLst.append(Controls[key])
2168        dspLst.append(None)
2169        elemKeysLst.append([key])
2170        refFlgElem.append(None)
2171       
2172    mainSizer.Add(parmSizer,1,wx.EXPAND)
2173    mainSizer.Add((0,5),0)   
2174    if 'SASD' in histName:
2175        rho = [0.,0.]
2176        anomrho = [0.,0.]
2177        mu = 0.
2178        subSizer = wx.FlexGridSizer(0,4,5,5)
2179        Substances = G2frame.PatternTree.GetItemPyData(
2180            G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Substances'))
2181        for id,item in enumerate(data['Materials']):
2182            subSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Material: '),0,WACV)
2183            matsel = wx.ComboBox(G2frame.dataDisplay,value=item['Name'],choices=Substances['Substances'].keys(),
2184                style=wx.CB_READONLY|wx.CB_DROPDOWN)
2185            Info[matsel.GetId()] = [id,'Name']
2186            matsel.Bind(wx.EVT_COMBOBOX,OnMaterial)       
2187            subSizer.Add(matsel,0,WACV)
2188            subSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Volume fraction: '),0,WACV)
2189            volfrac = wx.TextCtrl(G2frame.dataDisplay,value=str('%.3f'%(item['VolFrac'])),style=wx.TE_PROCESS_ENTER)
2190            Info[volfrac.GetId()] = [id,'VolFrac']
2191            volfrac.Bind(wx.EVT_TEXT_ENTER,OnMaterial)
2192            volfrac.Bind(wx.EVT_KILL_FOCUS,OnMaterial)
2193            subSizer.Add(volfrac,0,WACV)
2194            material = Substances['Substances'][item['Name']]
2195            mu += item['VolFrac']*material.get('XAbsorption',0.)
2196            rho[id] = material['Scatt density']
2197            anomrho[id] = material.get('XAnom density',0.)
2198        data['Contrast'] = [(rho[1]-rho[0])**2,(anomrho[1]-anomrho[0])**2]
2199        mainSizer.Add(subSizer,0)
2200        conSizer = wx.BoxSizer(wx.HORIZONTAL)
2201        conSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Contrast: %10.2f '%(data['Contrast'][0])),0,WACV)
2202        conSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Anom. Contrast: %10.2f '%(data['Contrast'][1])),0,WACV)
2203        mut =  mu*data['Thick']
2204        conSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Transmission (calc): %10.3f  '%(np.exp(-mut))),0,WACV)
2205        mainSizer.Add(conSizer,0)
2206   
2207    mainSizer.Layout()   
2208    G2frame.dataDisplay.SetSizer(mainSizer)
2209    Size = mainSizer.Fit(G2frame.dataFrame)
2210    G2frame.dataDisplay.SetSize(Size)
2211    G2frame.dataFrame.setSizePosLeft(Size)
2212               
2213################################################################################
2214#####  Indexing Peaks
2215################################################################################           
2216       
2217def UpdateIndexPeaksGrid(G2frame, data):
2218    '''respond to selection of PWDR Index Peak List data
2219    tree item.
2220    '''
2221    bravaisSymb = ['Fm3m','Im3m','Pm3m','R3-H','P6/mmm','I4/mmm',
2222        'P4/mmm','Fmmm','Immm','Cmmm','Pmmm','C2/m','P2/m','P1']
2223    IndexId = G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Index Peak List')
2224    Inst = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Instrument Parameters'))[0]
2225
2226    def RefreshIndexPeaksGrid(event):
2227        r,c =  event.GetRow(),event.GetCol()
2228        peaks = G2frame.IndexPeaksTable.GetData()
2229        if c == 2:
2230            if peaks[r][c]:
2231                peaks[r][c] = False
2232            else:
2233                peaks[r][c] = True
2234            G2frame.IndexPeaksTable.SetData(peaks)
2235            G2frame.PatternTree.SetItemPyData(IndexId,[peaks,data[1]])
2236            G2frame.dataDisplay.ForceRefresh()
2237            if 'PKS' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
2238                G2plt.PlotPowderLines(G2frame)
2239            else:
2240                G2plt.PlotPatterns(G2frame,plotType='PWDR')
2241           
2242    def OnReload(event):
2243        peaks = []
2244        sigs = []
2245        Peaks = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Peak List'))
2246        for ip,peak in enumerate(Peaks['peaks']):
2247            dsp = G2lat.Pos2dsp(Inst,peak[0])
2248            peaks.append([peak[0],peak[2],True,False,0,0,0,dsp,0.0])    #SS?
2249            try:
2250                sig = Peaks['sigDict']['pos'+str(ip)]
2251            except KeyError:
2252                sig = 0.
2253            sigs.append(sig)
2254        data = [peaks,sigs]
2255        G2frame.PatternTree.SetItemPyData(IndexId,data)
2256        UpdateIndexPeaksGrid(G2frame,data)
2257       
2258    def KeyEditPickGrid(event):
2259        colList = G2frame.dataDisplay.GetSelectedCols()
2260        rowList = G2frame.dataDisplay.GetSelectedRows()
2261        data = G2frame.PatternTree.GetItemPyData(IndexId)
2262        if event.GetKeyCode() == wx.WXK_RETURN:
2263            event.Skip(True)
2264        elif event.GetKeyCode() == wx.WXK_CONTROL:
2265            event.Skip(True)
2266        elif event.GetKeyCode() == wx.WXK_SHIFT:
2267            event.Skip(True)
2268        elif colList:
2269            G2frame.dataDisplay.ClearSelection()
2270            key = event.GetKeyCode()
2271            for col in colList:
2272                if G2frame.IndexPeaksTable.GetColLabelValue(col) in ['use',]:
2273                    if key == 89: #'Y'
2274                        for row in range(G2frame.IndexPeaksTable.GetNumberRows()): data[0][row][col]=True
2275                    elif key == 78:  #'N'
2276                        for row in range(G2frame.IndexPeaksTable.GetNumberRows()): data[0][row][col]=False
2277           
2278    if G2frame.dataDisplay:
2279        G2frame.dataFrame.Clear()
2280    if not G2frame.dataFrame.GetStatusBar():
2281        Status = G2frame.dataFrame.CreateStatusBar()
2282    if 'PWD' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
2283        G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.IndPeaksMenu)
2284        G2frame.Bind(wx.EVT_MENU, OnReload, id=G2gd.wxID_INDXRELOAD)
2285    G2frame.dataFrame.IndexPeaks.Enable(False)
2286    G2frame.IndexPeaksTable = []
2287    if len(data[0]):
2288        G2frame.dataFrame.IndexPeaks.Enable(True)
2289        Unit = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Unit Cells List'))
2290        if Unit:
2291            if len(Unit) == 4:  #patch
2292                Unit.append({})
2293            controls,bravais,cellist,dmin,ssopt = Unit
2294            G2frame.HKL = []
2295            if ssopt.get('Use',False):
2296                cell = controls[6:12]
2297                A = G2lat.cell2A(cell)
2298                ibrav = bravaisSymb.index(controls[5])
2299                spc = controls[13]
2300                SGData = G2spc.SpcGroup(spc)[1]
2301                SSGData = G2spc.SSpcGroup(SGData,ssopt['ssSymb'])[1]
2302                Vec = ssopt['ModVec']
2303                maxH = ssopt['maxH']
2304                G2frame.HKL = G2pwd.getHKLMpeak(dmin,Inst,SGData,SSGData,Vec,maxH,A)
2305                G2frame.HKL = np.array(G2frame.HKL)
2306                data[0] = G2indx.IndexSSPeaks(data[0],G2frame.HKL)[1]
2307            else:        #select cell from table - no SS
2308                for i,cell in enumerate(cellist):
2309                    if cell[-2]:
2310                        ibrav = cell[2]
2311                        A = G2lat.cell2A(cell[3:9])
2312                        G2frame.HKL = G2lat.GenHBravais(dmin,ibrav,A)
2313                        for hkl in G2frame.HKL:
2314                            hkl.insert(4,G2lat.Dsp2pos(Inst,hkl[3]))
2315                        G2frame.HKL = np.array(G2frame.HKL)
2316                        data[0] = G2indx.IndexPeaks(data[0],G2frame.HKL)[1]
2317                        break
2318    rowLabels = []
2319    for i in range(len(data[0])): rowLabels.append(str(i+1))
2320    colLabels = ['position','intensity','use','indexed','h','k','l','d-obs','d-calc']
2321    Types = [wg.GRID_VALUE_FLOAT+':10,4',wg.GRID_VALUE_FLOAT+':10,1',]+2*[wg.GRID_VALUE_BOOL,]+ \
2322        3*[wg.GRID_VALUE_LONG,]+2*[wg.GRID_VALUE_FLOAT+':10,5',]
2323    if len(data[0]) and len(data[0][0]) > 9:
2324        colLabels = ['position','intensity','use','indexed','h','k','l','m','d-obs','d-calc']
2325        Types = [wg.GRID_VALUE_FLOAT+':10,4',wg.GRID_VALUE_FLOAT+':10,1',]+2*[wg.GRID_VALUE_BOOL,]+ \
2326            4*[wg.GRID_VALUE_LONG,]+2*[wg.GRID_VALUE_FLOAT+':10,5',]
2327    G2frame.PatternTree.SetItemPyData(IndexId,data)
2328    G2frame.IndexPeaksTable = G2G.Table(data[0],rowLabels=rowLabels,colLabels=colLabels,types=Types)
2329    G2frame.dataFrame.SetLabel('Index Peak List')
2330    G2frame.dataDisplay = G2G.GSGrid(parent=G2frame.dataFrame)               
2331    G2frame.dataDisplay.SetTable(G2frame.IndexPeaksTable, True)
2332    XY = []
2333    Sigs = []
2334    for r in range(G2frame.dataDisplay.GetNumberRows()):
2335        for c in range(G2frame.dataDisplay.GetNumberCols()):
2336            if c == 2:
2337                G2frame.dataDisplay.SetReadOnly(r,c,isReadOnly=False)
2338            else:
2339                G2frame.dataDisplay.SetReadOnly(r,c,isReadOnly=True)
2340        if data[0][r][2] and data[0][r][3]:
2341            XY.append([data[0][r][-1],data[0][r][0]])
2342            try:
2343                sig = data[1][r]
2344            except IndexError:
2345                sig = 0.
2346            Sigs.append(sig)
2347    G2frame.dataDisplay.Bind(wg.EVT_GRID_CELL_LEFT_CLICK, RefreshIndexPeaksGrid)
2348    G2frame.dataDisplay.Bind(wx.EVT_KEY_DOWN, KeyEditPickGrid)                 
2349    G2frame.dataDisplay.SetMargins(0,0)
2350    G2frame.dataDisplay.AutoSizeColumns(False)
2351    G2frame.dataFrame.setSizePosLeft([490,300])
2352    if len(XY):
2353        XY = np.array(XY)
2354        G2plt.PlotCalib(G2frame,Inst,XY,Sigs,newPlot=True)
2355    G2frame.dataFrame.SendSizeEvent()
2356     
2357################################################################################
2358#####  Unit cells
2359################################################################################           
2360       
2361def UpdateUnitCellsGrid(G2frame, data):
2362    '''respond to selection of PWDR Unit Cells data tree item.
2363    '''
2364    UnitCellsId = G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Unit Cells List')
2365    SPGlist = G2spc.spglist
2366    bravaisSymb = ['Fm3m','Im3m','Pm3m','R3-H','P6/mmm','I4/mmm',
2367        'P4/mmm','Fmmm','Immm','Cmmm','Pmmm','C2/m','P2/m','P1']
2368    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',
2369        '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']
2370    Inst = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Instrument Parameters'))[0]
2371    if 'C' in Inst['Type'][0] or 'PKS' in Inst['Type'][0]:
2372        wave = G2mth.getWave(Inst)
2373    else:
2374        difC = Inst['difC'][1]
2375   
2376    def SetLattice(controls):
2377        ibrav = bravaisSymb.index(controls[5])
2378        if ibrav in [0,1,2]:
2379            controls[7] = controls[8] = controls[6]
2380            controls[9] = controls[10] = controls[11] = 90.
2381        elif ibrav in [3,4,5,6]:
2382            controls[7] = controls[6]
2383            controls[9] = controls[10] = controls[11] = 90.
2384            if ibrav in [3,4]:
2385                controls[11] = 120.
2386        elif ibrav in [7,8,9,10]:
2387            controls[9] = controls[10] = controls[11] = 90.
2388        elif ibrav in [11,12]:
2389            controls[9] = controls[11] = 90.  # b unique
2390        if len(controls) < 13: controls.append(0)
2391        controls[12] = G2lat.calc_V(G2lat.cell2A(controls[6:12]))
2392        return ibrav
2393       
2394    def OnNcNo(event):
2395        controls[2] = NcNo.GetValue()
2396       
2397    def OnIfX20(event):
2398        G2frame.ifX20 = x20.GetValue()
2399       
2400    def OnStartVol(event):
2401        try:
2402            stVol = int(float(startVol.GetValue()))
2403            if stVol < 25:
2404                raise ValueError
2405        except ValueError:
2406            stVol = 25
2407        controls[3] = stVol
2408        startVol.SetValue("%d"%(stVol))
2409       
2410    def OnBravais(event):
2411        Obj = event.GetEventObject()
2412        bravais[bravList.index(Obj.GetId())] = Obj.GetValue()
2413       
2414    def OnZero(event):
2415        try:
2416            Zero = min(5.0,max(-5.0,float(zero.GetValue())))
2417        except ValueError:
2418            Zero = 0.0
2419        controls[1] = Zero
2420        zero.SetValue("%.4f"%(Zero))
2421       
2422    def OnZeroVar(event):
2423        controls[0] = zeroVar.GetValue()
2424       
2425    def OnSSopt(event):
2426        if controls[5] in ['Fm3m','Im3m','Pm3m']:
2427            SSopt.SetValue(False)
2428            G2frame.ErrorDialog('Cubic lattice', 'Superlattice not allowed for a cubic lattice')
2429            return
2430        ssopt['Use'] = SSopt.GetValue()
2431        if 'ssSymb' not in ssopt:
2432            ssopt.update({'ssSymb':'(abg)','ModVec':[0.1,0.1,0.1],'maxH':1})
2433        wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)
2434       
2435    def OnSelMG(event):
2436        ssopt['ssSymb'] = selMG.GetValue()
2437        Vec = ssopt['ModVec']
2438        modS = G2spc.splitSSsym(ssopt['ssSymb'])[0]
2439        ssopt['ModVec'] = G2spc.SSGModCheck(Vec,modS)[0]
2440        print ' Selecting: ',controls[13],ssopt['ssSymb'], 'maxH:',ssopt['maxH']
2441        OnHklShow(event)
2442        wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)
2443       
2444    def OnModVal(event):
2445        Obj = event.GetEventObject()
2446        ObjId = Obj.GetId()
2447        Id = Indx[ObjId]
2448        try:
2449            value = min(1.0,max(0.,float(Obj.GetValue())))
2450        except ValueError:
2451            value = ssopt['ModVec'][Id]
2452        Obj.SetValue('%.4f'%(value))
2453        ssopt['ModVec'][Id] = value
2454        OnHklShow(event)
2455       
2456    def OnMoveMod(event):
2457        Obj = event.GetEventObject()
2458        ObjId = Obj.GetId()
2459        Id,valObj = Indx[ObjId]
2460        move = Obj.GetValue()*0.0005
2461        Obj.SetValue(0)
2462        value = min(1.0,max(.0,float(valObj.GetValue())+move))
2463        valObj.SetValue('%.4f'%(value)) 
2464        ssopt['ModVec'][Id] = value
2465        OnHklShow(event)
2466       
2467    def OnMaxMH(event):
2468        ssopt['maxH'] = int(maxMH.GetValue())
2469        print ' Selecting: ',controls[13],ssopt['ssSymb'], 'maxH:',ssopt['maxH']
2470        OnHklShow(event)
2471       
2472    def OnFindMV(event):
2473        Peaks = np.copy(peaks[0])
2474        print ' Trying: ',controls[13],ssopt['ssSymb'], 'maxH:',ssopt['maxH']
2475        dlg = wx.ProgressDialog('Elapsed time','Modulation vector search',
2476            style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE)
2477        try:
2478            ssopt['ModVec'] = G2indx.findMV(Peaks,controls,ssopt,Inst,dlg)
2479        finally:
2480            dlg.Destroy()
2481        OnHklShow(event)
2482        wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)
2483       
2484    def OnBravSel(event):
2485        brav = bravSel.GetString(bravSel.GetSelection())
2486        controls[5] = brav
2487        controls[13] = SPGlist[brav][0]       
2488        wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)
2489       
2490    def OnSpcSel(event):
2491        controls[13] = spcSel.GetString(spcSel.GetSelection())
2492        G2frame.dataFrame.RefineCell.Enable(True)
2493        OnHklShow(event)
2494       
2495    def SetCellValue(Obj,ObjId,value):
2496        ibrav = bravaisSymb.index(controls[5])
2497        if ibrav in [0,1,2]:
2498            controls[6] = controls[7] = controls[8] = value
2499            controls[9] = controls[10] = controls[11] = 90.0
2500            Obj.SetValue("%.5f"%(controls[6]))
2501        elif ibrav in [3,4,5,6]:
2502            if ObjId == 0:
2503                controls[6] = controls[7] = value
2504                Obj.SetValue("%.5f"%(controls[6]))
2505            else:
2506                controls[8] = value
2507                Obj.SetValue("%.5f"%(controls[8]))
2508            controls[9] = controls[10] = controls[11] = 90.0
2509            if ibrav in [3,4]:
2510                controls[11] = 120.
2511        elif ibrav in [7,8,9,10]:
2512            controls[6+ObjId] = value
2513            Obj.SetValue("%.5f"%(controls[6+ObjId]))
2514            controls[9] = controls[10] = controls[11] = 90.0
2515        elif ibrav in [11,12]:
2516            controls[9] = controls[11] = 90.0
2517            if ObjId != 3:
2518                controls[6+ObjId] = value
2519                Obj.SetValue("%.5f"%(controls[6+ObjId]))
2520            else:
2521                controls[10] = value
2522                Obj.SetValue("%.3f"%(controls[10]))
2523        else:
2524            controls[6+ObjId] = value
2525            if ObjId < 3:
2526                Obj.SetValue("%.5f"%(controls[6+ObjId]))
2527            else:
2528                Obj.SetValue("%.3f"%(controls[6+ObjId]))
2529        controls[12] = G2lat.calc_V(G2lat.cell2A(controls[6:12]))
2530        volVal.SetValue("%.3f"%(controls[12]))
2531       
2532    def OnMoveCell(event):
2533        Obj = event.GetEventObject()
2534        ObjId = cellList.index(Obj.GetId())
2535        valObj = valDict[Obj.GetId()]
2536        if ObjId/2 < 3:
2537            move = Obj.GetValue()*0.01
2538        else:
2539            move = Obj.GetValue()*0.1
2540        Obj.SetValue(0)
2541        value = float(valObj.GetValue())+move 
2542        SetCellValue(valObj,ObjId/2,value)
2543        OnHklShow(event)
2544       
2545    def OnExportCells(event):
2546        dlg = wx.FileDialog(G2frame, 'Choose Indexing Result csv file', '.', '', 
2547            'indexing result file (*.csv)|*.csv',wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT|wx.CHANGE_DIR)
2548        try:
2549            if dlg.ShowModal() == wx.ID_OK:
2550                filename = dlg.GetPath()
2551                filename = os.path.splitext(filename)[0]+'.csv'
2552                File = open(filename,'w')
2553                names = 'M20,X20,Bravais,a,b,c,alpha,beta,gamma,volume\n'
2554                File.write(names)
2555                fmt = '%.2f,%d,%s,%.4f,%.4f,%.4f,%.2f,%.2f,%.2f,%.3f\n'
2556                for cell in cells:
2557                    File.write(fmt%(cell[0],cell[1],bravaisSymb[cell[2]], cell[3],cell[4],cell[5], cell[6],cell[7],cell[8],cell[9]))
2558                File.close()
2559        finally:
2560            dlg.Destroy()
2561       
2562    def OnCellChange(event):
2563        Obj = event.GetEventObject()
2564        ObjId = cellList.index(Obj.GetId())
2565        try:
2566            value = max(1.0,float(Obj.GetValue()))
2567        except ValueError:
2568            if ObjId/2 < 3:               #bad cell edge - reset
2569                value = controls[6+ObjId/2]
2570            else:                       #bad angle
2571                value = 90.
2572        SetCellValue(Obj,ObjId/2,value)
2573       
2574    def OnHklShow(event):
2575        PatternId = G2frame.PatternId
2576        PickId = G2frame.PickId   
2577        peaks = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Index Peak List'))
2578        limits = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Limits'))[1]
2579        controls,bravais,cells,dmin,ssopt = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Unit Cells List'))
2580        cell = controls[6:12]
2581        A = G2lat.cell2A(cell)
2582        ibrav = bravaisSymb.index(controls[5])
2583        spc = controls[13]
2584        SGData = G2spc.SpcGroup(spc)[1]
2585        if 'C' in Inst['Type'][0]:
2586            dmin = G2lat.Pos2dsp(Inst,limits[1])
2587        else:   #TOF - use other limit!
2588            dmin = G2lat.Pos2dsp(Inst,limits[0])
2589        if ssopt.get('Use',False):
2590            dmin = peaks[0][-1][8]
2591            SSGData = G2spc.SSpcGroup(SGData,ssopt['ssSymb'])[1]
2592            Vec = ssopt['ModVec']
2593            maxH = ssopt['maxH']
2594            G2frame.HKL = G2pwd.getHKLMpeak(dmin,Inst,SGData,SSGData,Vec,maxH,A)
2595            peaks = [G2indx.IndexSSPeaks(peaks[0],G2frame.HKL)[1],peaks[1]]   #keep esds from peak fit
2596            M20,X20 = G2indx.calc_M20SS(peaks[0],G2frame.HKL)
2597        else:
2598            if len(peaks[0]):
2599                dmin = peaks[0][-1][7]
2600                G2frame.HKL = G2pwd.getHKLpeak(dmin,SGData,A,Inst)
2601                peaks = [G2indx.IndexPeaks(peaks[0],G2frame.HKL)[1],peaks[1]]   #keep esds from peak fit
2602                M20,X20 = G2indx.calc_M20(peaks[0],G2frame.HKL)
2603            else:
2604                M20 = X20 = 0.
2605                G2frame.HKL = G2pwd.getHKLpeak(dmin,SGData,A,Inst)
2606        G2frame.HKL = np.array(G2frame.HKL)
2607        if len(G2frame.HKL):
2608            print ' new M20,X20: %.2f %d fraction found: %.3f'%(M20,X20,float(len(peaks[0]))/len(G2frame.HKL))
2609        G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Index Peak List'),peaks)
2610        if 'PKS' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
2611            G2plt.PlotPowderLines(G2frame)
2612        else:
2613            G2plt.PlotPatterns(G2frame)
2614           
2615    def OnSortCells(event):
2616        controls,bravais,cells,dmin,ssopt = G2frame.PatternTree.GetItemPyData(UnitCellsId)
2617        c =  event.GetCol()
2618        if colLabels[c] == 'M20':
2619            cells = G2indx.sortM20(cells)
2620        elif colLabels[c] in ['X20','Bravais','a','b','c','alpha','beta','gamma','Volume']:
2621            if c == 1:
2622                c += 1  #X20 before Use
2623            cells = G2indx.sortCells(cells,c-1)     #an extra column (Use) not in cells
2624        else:
2625            return
2626        data = [controls,bravais,cells,dmin,ssopt]
2627        G2frame.PatternTree.SetItemPyData(UnitCellsId,data)
2628        wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)
2629       
2630    def CopyUnitCell(event):
2631        controls,bravais,cells,dmin,ssopt = G2frame.PatternTree.GetItemPyData(UnitCellsId)
2632        for Cell in cells:
2633            if Cell[-2]:
2634                break
2635        cell = Cell[2:9]
2636        controls[4] = 1
2637        controls[5] = bravaisSymb[cell[0]]
2638        controls[6:12] = cell[1:8]
2639        controls[12] = G2lat.calc_V(G2lat.cell2A(controls[6:12]))
2640        controls[13] = spaceGroups[bravaisSymb.index(controls[5])]
2641        G2frame.PatternTree.SetItemPyData(UnitCellsId,[controls,bravais,cells,dmin,ssopt])
2642        G2frame.dataFrame.RefineCell.Enable(True)
2643        wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)       
2644               
2645    def RefineCell(event):
2646       
2647        def cellPrint(ibrav,A):
2648            cell = G2lat.A2cell(A)
2649            Vol = G2lat.calc_V(A)
2650            if ibrav in [0,1,2]:
2651                print " %s%10.6f" % ('a =',cell[0])
2652            elif ibrav in [3,4,5,6]:
2653                print " %s%10.6f %s%10.6f %s%12.3f" % ('a =',cell[0],' c =',cell[2],' volume =',Vol)
2654            elif ibrav in [7,8,9,10]:
2655                print " %s%10.6f %s%10.6f %s%10.6f %s%12.3f" % ('a =',cell[0],'b =',cell[1],'c =',cell[2],' volume =',Vol)
2656            elif ibrav in [11,12]:
2657                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)
2658            else:
2659                print " %s%10.6f %s%10.6f %s%10.6f" % ('a =',cell[0],'b =',cell[1],'c =',cell[2])
2660                print " %s%8.3f %s%8.3f %s%8.3f %s%12.3f" % ('alpha =',cell[3],'beta =',cell[4],'gamma =',cell[5],' volume =',Vol)
2661               
2662        def vecPrint(Vec):
2663            print ' %s %10.5f %10.5f %10.5f'%('Modulation vector:',Vec[0],Vec[1],Vec[2])
2664             
2665        PatternId = G2frame.PatternId
2666        PickId = G2frame.PickId   
2667        peaks = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Index Peak List'))
2668        if not len(peaks[0]):
2669            G2frame.ErrorDialog('No peaks!', 'Nothing to refine!')
2670            return       
2671        print ' Refine cell'
2672        controls,bravais,cells,dmin,ssopt = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Unit Cells List'))
2673        cell = controls[6:12]
2674        A = G2lat.cell2A(cell)
2675        ibrav = bravaisSymb.index(controls[5])
2676        SGData = G2spc.SpcGroup(controls[13])[1]
2677        dmin = G2indx.getDmin(peaks[0])-0.005
2678        if 'C' in Inst['Type'][0]:
2679            if ssopt.get('Use',False):
2680                vecFlags = [True if x in ssopt['ssSymb'] else False for x in ['a','b','g']]
2681                SSGData = G2spc.SSpcGroup(SGData,ssopt['ssSymb'])[1]
2682                G2frame.HKL = G2pwd.getHKLMpeak(dmin,Inst,SGData,SSGData,ssopt['ModVec'],ssopt['maxH'],A)
2683                peaks = [G2indx.IndexSSPeaks(peaks[0],G2frame.HKL)[1],peaks[1]]   #put peak fit esds back in peaks
2684                Lhkl,M20,X20,Aref,Vec,Zero = \
2685                    G2indx.refinePeaksZSS(peaks[0],wave,Inst,SGData,SSGData,ssopt['maxH'],ibrav,A,ssopt['ModVec'],vecFlags,controls[1],controls[0])
2686            else:
2687                G2frame.HKL = G2pwd.getHKLpeak(dmin,SGData,A,Inst)
2688                peaks = [G2indx.IndexPeaks(peaks[0],G2frame.HKL)[1],peaks[1]]   #put peak fit esds back in peaks
2689                Lhkl,M20,X20,Aref,Zero = G2indx.refinePeaksZ(peaks[0],wave,ibrav,A,controls[1],controls[0])
2690        else:   #'T'OF - doesn't seem to work
2691            G2frame.HKL = G2pwd.getHKLpeak(dmin,SGData,A,Inst)
2692            peaks = [G2indx.IndexPeaks(peaks[0],G2frame.HKL)[1],peaks[1]]   #put peak fit esds back in peaks
2693            Lhkl,M20,X20,Aref,Zero = G2indx.refinePeaksT(peaks[0],difC,ibrav,A,controls[1],controls[0])           
2694        G2frame.HKL = np.array(G2frame.HKL)
2695        controls[1] = Zero
2696        controls[6:12] = G2lat.A2cell(Aref)
2697        controls[12] = G2lat.calc_V(Aref)
2698        cells = G2frame.PatternTree.GetItemPyData(UnitCellsId)[2]
2699        for cell in cells:
2700            cell[-2] = False
2701        cells.insert(0,[M20,X20,ibrav]+controls[6:13]+[True,False])
2702        if ssopt.get('Use',False):
2703            ssopt['ModVec'] = Vec
2704            G2frame.HKL = G2pwd.getHKLMpeak(dmin,Inst,SGData,SSGData,ssopt['ModVec'],ssopt['maxH'],A)
2705        else:
2706            G2frame.HKL = G2pwd.getHKLpeak(dmin,SGData,A,Inst)
2707        data = [controls,bravais,cells,dmin,ssopt]
2708        G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Unit Cells List'),data)
2709        print " %s%10.3f" % ('refinement M20 = ',M20)
2710        print ' unindexed lines = ',X20
2711        cellPrint(ibrav,Aref)
2712        ip = 4
2713        if ssopt.get('Use',False):
2714            vecPrint(Vec)
2715            ip = 5
2716        for hkl in G2frame.HKL:
2717            hkl[ip] = G2lat.Dsp2pos(Inst,hkl[ip-1])+controls[1]
2718        G2frame.HKL = np.array(G2frame.HKL)
2719        if 'PKS' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
2720            G2plt.PlotPowderLines(G2frame)
2721        else:
2722            G2plt.PlotPatterns(G2frame)
2723        wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)
2724       
2725    def IndexPeaks(event):
2726        PatternId = G2frame.PatternId   
2727        print 'Peak Indexing'
2728        keepcells = []
2729        try:
2730            controls,bravais,cells,dmin,ssopt = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Unit Cells List'))
2731            for cell in cells:
2732                if cell[11]:
2733                    cell[10] = False    #clear selection flag on keepers
2734                    keepcells.append(cell)
2735        except IndexError:
2736            pass
2737        except ValueError:
2738            G2frame.ErrorDialog('Error','Need to set controls in Unit Cell List first')
2739            return
2740        if ssopt.get('Use',False):
2741            G2frame.ErrorDialog('Super lattice error','Indexing not available for super lattices')
2742            return
2743        if True not in bravais:
2744            G2frame.ErrorDialog('Error','No Bravais lattices selected')
2745            return
2746        if not len(peaks[0]):
2747            G2frame.ErrorDialog('Error','Index Peak List is empty')
2748            return
2749        if len(peaks[0][0]) > 9:
2750            G2frame.ErrorDialog('Error','You need to reload Index Peaks List first')
2751            return
2752        G2frame.dataFrame.CopyCell.Enable(False)
2753        G2frame.dataFrame.RefineCell.Enable(False)
2754        OK,dmin,newcells = G2indx.DoIndexPeaks(peaks[0],controls,bravais,G2frame.ifX20)
2755        cells = keepcells+newcells
2756        cells = G2indx.sortM20(cells)
2757        if OK:
2758            cells[0][10] = True         #select best M20
2759            data = [controls,bravais,cells,dmin,ssopt]
2760            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Unit Cells List'),data)
2761            bestCell = cells[0]
2762            if bestCell[0] > 10.:
2763                G2frame.HKL = G2lat.GenHBravais(dmin,bestCell[2],G2lat.cell2A(bestCell[3:9]))
2764                for hkl in G2frame.HKL:
2765                    hkl.insert(4,G2lat.Dsp2pos(Inst,hkl[3])+controls[1])
2766                G2frame.HKL = np.array(G2frame.HKL)
2767                if 'PKS' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
2768                    G2plt.PlotPowderLines(G2frame)
2769                else:
2770                    G2plt.PlotPatterns(G2frame)
2771            G2frame.dataFrame.CopyCell.Enable(True)
2772            G2frame.dataFrame.IndexPeaks.Enable(True)
2773            G2frame.dataFrame.MakeNewPhase.Enable(True)
2774            G2frame.ifX20 = True
2775            wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)
2776               
2777    def RefreshUnitCellsGrid(event):
2778        data = G2frame.PatternTree.GetItemPyData(UnitCellsId)
2779        cells,dmin = data[2:4]
2780        r,c =  event.GetRow(),event.GetCol()
2781        if cells:
2782            if c == 2:
2783                for i in range(len(cells)):
2784                    cells[i][-2] = False
2785                    UnitCellsTable.SetValue(i,c,False)
2786                UnitCellsTable.SetValue(r,c,True)
2787                gridDisplay.Refresh()
2788                cells[r][-2] = True
2789                ibrav = cells[r][2]
2790                A = G2lat.cell2A(cells[r][3:9])
2791                G2frame.HKL = G2lat.GenHBravais(dmin,ibrav,A)
2792                for hkl in G2frame.HKL:
2793                    hkl.insert(4,G2lat.Dsp2pos(Inst,hkl[3])+controls[1])
2794                G2frame.HKL = np.array(G2frame.HKL)
2795                if 'PKS' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
2796                    G2plt.PlotPowderLines(G2frame)
2797                else:
2798                    G2plt.PlotPatterns(G2frame)
2799            elif c == 11:
2800                if UnitCellsTable.GetValue(r,c):
2801                    UnitCellsTable.SetValue(r,c,False)
2802                    cells[r][c] = False
2803                else:
2804                    cells[r][c] = True
2805                    UnitCellsTable.SetValue(r,c,True)
2806                gridDisplay.ForceRefresh()
2807            G2frame.PatternTree.SetItemPyData(UnitCellsId,data)
2808       
2809    def MakeNewPhase(event):
2810        if not G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Phases'):
2811            sub = G2frame.PatternTree.AppendItem(parent=G2frame.root,text='Phases')
2812        else:
2813            sub = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Phases')
2814        PhaseName = ''
2815        dlg = wx.TextEntryDialog(None,'Enter a name for this phase','Phase Name Entry','New phase',
2816            style=wx.OK)
2817        try:
2818            if dlg.ShowModal() == wx.ID_OK:
2819                PhaseName = dlg.GetValue()
2820                cells = G2frame.PatternTree.GetItemPyData(UnitCellsId)[2]
2821                for Cell in cells:
2822                    if Cell[-2]:
2823                        break
2824                cell = Cell[2:10]       
2825                sub = G2frame.PatternTree.AppendItem(parent=sub,text=PhaseName)
2826                E,SGData = G2spc.SpcGroup(controls[13])
2827                G2frame.PatternTree.SetItemPyData(sub, \
2828                    G2IO.SetNewPhase(Name=PhaseName,SGData=SGData,cell=cell[1:],Super=ssopt))
2829                Status.SetStatusText('Change space group from '+str(controls[13])+' if needed')
2830        finally:
2831            dlg.Destroy()
2832           
2833    if G2frame.dataDisplay:
2834        G2frame.dataFrame.DestroyChildren()
2835    G2frame.dataDisplay = wxscroll.ScrolledPanel(G2frame.dataFrame)
2836    G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.IndexMenu)
2837    if not G2frame.dataFrame.GetStatusBar():
2838        Status = G2frame.dataFrame.CreateStatusBar()
2839    G2frame.Bind(wx.EVT_MENU, IndexPeaks, id=G2gd.wxID_INDEXPEAKS)
2840    G2frame.Bind(wx.EVT_MENU, CopyUnitCell, id=G2gd.wxID_COPYCELL)
2841    G2frame.Bind(wx.EVT_MENU, RefineCell, id=G2gd.wxID_REFINECELL)
2842    G2frame.Bind(wx.EVT_MENU, MakeNewPhase, id=G2gd.wxID_MAKENEWPHASE)
2843    G2frame.Bind(wx.EVT_MENU, OnExportCells, id=G2gd.wxID_EXPORTCELLS)
2844       
2845    controls,bravais,cells,dmin,ssopt = data
2846    if len(controls) < 13:              #add cell volume if missing
2847        controls.append(G2lat.calc_V(G2lat.cell2A(controls[6:12])))
2848    if len(controls) < 14:              #add space gropu used in indexing
2849        controls.append(spaceGroups[bravaisSymb.index(controls[5])])
2850    G2frame.PatternTree.SetItemPyData(UnitCellsId,data)            #update with volume
2851    bravaisNames = ['Cubic-F','Cubic-I','Cubic-P','Trigonal-R','Trigonal/Hexagonal-P',
2852        'Tetragonal-I','Tetragonal-P','Orthorhombic-F','Orthorhombic-I','Orthorhombic-C',
2853        'Orthorhombic-P','Monoclinic-C','Monoclinic-P','Triclinic']
2854    cellGUIlist = [[[0,1,2],4,zip([" Unit cell: a = "," Vol = "],["%.5f","%.3f"],[True,False],[0,0])],
2855    [[3,4,5,6],6,zip([" Unit cell: a = "," c = "," Vol = "],["%.5f","%.5f","%.3f"],[True,True,False],[0,2,0])],
2856    [[7,8,9,10],8,zip([" Unit cell: a = "," b = "," c = "," Vol = "],["%.5f","%.5f","%.5f","%.3f"],
2857        [True,True,True,False],[0,1,2,0])],
2858    [[11,12],10,zip([" Unit cell: a = "," b = "," c = "," beta = "," Vol = "],
2859        ["%.5f","%.5f","%.5f","%.3f","%.3f"],[True,True,True,True,False],[0,1,2,4,0])],
2860    [[13,],8,zip([" Unit cell: a = "," b = "," c = "," Vol = "," alpha = "," beta = "," gamma = "],
2861        ["%.5f","%.5f","%.5f","%.3f","%.3f","%.3f","%.3f"],
2862        [True,True,True,False,True,True,True],[0,1,2,0,3,4,5])]]
2863   
2864    G2frame.dataFrame.SetLabel('Unit Cells List')
2865    G2frame.dataFrame.IndexPeaks.Enable(False)
2866    peaks = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Index Peak List'))
2867    if peaks:
2868        G2frame.dataFrame.IndexPeaks.Enable(True)
2869    G2frame.dataFrame.RefineCell.Enable(False)
2870    if controls[12] > 1.0:                               #if a "real" volume (i.e. not default)
2871        G2frame.dataFrame.RefineCell.Enable(True)   
2872    G2frame.dataFrame.CopyCell.Enable(False)
2873    G2frame.dataFrame.MakeNewPhase.Enable(False)       
2874    G2frame.dataFrame.ExportCells.Enable(False)
2875    if cells:
2876        G2frame.dataFrame.CopyCell.Enable(True)
2877        G2frame.dataFrame.MakeNewPhase.Enable(True)
2878        G2frame.dataFrame.ExportCells.Enable(True)
2879    mainSizer = wx.BoxSizer(wx.VERTICAL)
2880    mainSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Indexing controls: '),0,WACV)
2881    mainSizer.Add((5,5),0)
2882    littleSizer = wx.FlexGridSizer(0,5,5,5)
2883    littleSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Max Nc/Nobs '),0,WACV)
2884    NcNo = wx.SpinCtrl(G2frame.dataDisplay)
2885    NcNo.SetRange(2,6)
2886    NcNo.SetValue(controls[2])
2887    NcNo.Bind(wx.EVT_SPINCTRL,OnNcNo)
2888    littleSizer.Add(NcNo,0,WACV)
2889    littleSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Start Volume '),0,WACV)
2890    startVol = wx.TextCtrl(G2frame.dataDisplay,value=str('%d'%(controls[3])),style=wx.TE_PROCESS_ENTER)
2891    startVol.Bind(wx.EVT_TEXT_ENTER,OnStartVol)
2892    startVol.Bind(wx.EVT_KILL_FOCUS,OnStartVol)
2893    littleSizer.Add(startVol,0,WACV)
2894    x20 = wx.CheckBox(G2frame.dataDisplay,label='Use M20/(X20+1)?')
2895    x20.SetValue(G2frame.ifX20)
2896    x20.Bind(wx.EVT_CHECKBOX,OnIfX20)
2897    littleSizer.Add(x20,0,WACV)
2898    mainSizer.Add(littleSizer,0)
2899    mainSizer.Add((5,5),0)
2900    mainSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Select Bravais Lattices for indexing: '),
2901        0,WACV)
2902    mainSizer.Add((5,5),0)
2903    littleSizer = wx.FlexGridSizer(0,7,5,5)
2904    bravList = []
2905    bravs = zip(bravais,bravaisNames)
2906    for brav,bravName in bravs:
2907        bravCk = wx.CheckBox(G2frame.dataDisplay,label=bravName)
2908        bravList.append(bravCk.GetId())
2909        bravCk.SetValue(brav)
2910        bravCk.Bind(wx.EVT_CHECKBOX,OnBravais)
2911        littleSizer.Add(bravCk,0,WACV)
2912    mainSizer.Add(littleSizer,0)
2913    mainSizer.Add((5,5),0)
2914   
2915    mainSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Cell Refinement: '),0,WACV)
2916    mainSizer.Add((5,5),0)
2917    littleSizer = wx.BoxSizer(wx.HORIZONTAL)
2918    littleSizer.Add(wx.StaticText(G2frame.dataDisplay,label=" Bravais lattice "),0,WACV)
2919    bravSel = wx.Choice(G2frame.dataDisplay,choices=bravaisSymb)
2920    bravSel.SetSelection(bravaisSymb.index(controls[5]))
2921    bravSel.Bind(wx.EVT_CHOICE,OnBravSel)
2922    littleSizer.Add(bravSel,0,WACV)
2923    littleSizer.Add(wx.StaticText(G2frame.dataDisplay,label=" Space group "),0,WACV)
2924    spcSel = wx.Choice(G2frame.dataDisplay,choices=SPGlist[controls[5]])
2925    spcSel.SetSelection(SPGlist[controls[5]].index(controls[13]))
2926    spcSel.Bind(wx.EVT_CHOICE,OnSpcSel)
2927    littleSizer.Add(spcSel,0,WACV)
2928    if ssopt.get('Use',False):        #zero for super lattice doesn't work!
2929        controls[0] = False
2930    else:
2931        littleSizer.Add(wx.StaticText(G2frame.dataDisplay,label=" Zero offset"),0,WACV)
2932        zero = wx.TextCtrl(G2frame.dataDisplay,value="%.4f"%(controls[1]),style=wx.TE_PROCESS_ENTER)
2933        zero.Bind(wx.EVT_TEXT_ENTER,OnZero)
2934        zero.Bind(wx.EVT_KILL_FOCUS,OnZero)
2935        littleSizer.Add(zero,0,WACV)
2936        zeroVar = wx.CheckBox(G2frame.dataDisplay,label="Refine?")
2937        zeroVar.SetValue(controls[0])
2938        zeroVar.Bind(wx.EVT_CHECKBOX,OnZeroVar)
2939        littleSizer.Add(zeroVar,0,WACV)
2940    SSopt = wx.CheckBox(G2frame.dataDisplay,label="Super lattice?")
2941    SSopt.SetValue(ssopt.get('Use',False))
2942    SSopt.Bind(wx.EVT_CHECKBOX,OnSSopt)
2943    littleSizer.Add(SSopt,0,WACV)
2944    hklShow = wx.Button(G2frame.dataDisplay,label="Show hkl positions")
2945    hklShow.Bind(wx.EVT_BUTTON,OnHklShow)
2946    littleSizer.Add(hklShow,0,WACV)
2947    mainSizer.Add(littleSizer,0)
2948   
2949    mainSizer.Add((5,5),0)
2950    ibrav = SetLattice(controls)
2951    for cellGUI in cellGUIlist:
2952        if ibrav in cellGUI[0]:
2953            useGUI = cellGUI
2954    cellList = []
2955    valDict = {}
2956    littleSizer = wx.FlexGridSizer(0,useGUI[1],5,5)
2957    for txt,fmt,ifEdit,Id in useGUI[2]:
2958        littleSizer.Add(wx.StaticText(G2frame.dataDisplay,label=txt),0,WACV)
2959        if ifEdit:          #a,b,c,etc.
2960            cellVal = wx.TextCtrl(G2frame.dataDisplay,value=(fmt%(controls[6+Id])),style=wx.TE_PROCESS_ENTER)
2961            cellVal.Bind(wx.EVT_TEXT_ENTER,OnCellChange)       
2962            cellVal.Bind(wx.EVT_KILL_FOCUS,OnCellChange)
2963            valSizer = wx.BoxSizer(wx.HORIZONTAL)
2964            valSizer.Add(cellVal,0,WACV)
2965            cellSpin = wx.SpinButton(G2frame.dataDisplay,style=wx.SP_VERTICAL,size=wx.Size(20,20))
2966            cellSpin.SetValue(0)
2967            cellSpin.SetRange(-1,1)
2968            cellSpin.Bind(wx.EVT_SPIN, OnMoveCell)
2969            valSizer.Add(cellSpin,0,WACV)
2970            littleSizer.Add(valSizer,0,WACV)
2971            cellList.append(cellVal.GetId())
2972            cellList.append(cellSpin.GetId())
2973            valDict[cellSpin.GetId()] = cellVal
2974        else:               #volume
2975            volVal = wx.TextCtrl(G2frame.dataDisplay,value=(fmt%(controls[12])),style=wx.TE_READONLY)
2976            volVal.SetBackgroundColour(VERY_LIGHT_GREY)
2977            littleSizer.Add(volVal,0,WACV)
2978    mainSizer.Add(littleSizer,0)
2979    if ssopt.get('Use',False):        #super lattice display
2980        indChoice = ['1','2','3','4',]
2981        SpSg = controls[13]
2982        ssChoice = G2spc.ssdict[SpSg]
2983        if ssopt['ssSymb'] not in ssChoice:
2984            ssopt['ssSymb'] = ssChoice[0]
2985        ssSizer = wx.BoxSizer(wx.HORIZONTAL)
2986        ssSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Supersymmetry space group: '+SpSg+' '),0,WACV)
2987        selMG = wx.ComboBox(G2frame.dataDisplay,value=ssopt['ssSymb'],
2988                choices=ssChoice,style=wx.CB_READONLY|wx.CB_DROPDOWN)
2989        selMG.Bind(wx.EVT_COMBOBOX, OnSelMG)
2990        ssSizer.Add(selMG,0,WACV)
2991        ssSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Mod. vector: '),0,WACV)
2992        modS = G2spc.splitSSsym(ssopt['ssSymb'])[0]
2993        ssopt['ModVec'],ifShow = G2spc.SSGModCheck(ssopt['ModVec'],modS)
2994        Indx = {}
2995        for i,[val,show] in enumerate(zip(ssopt['ModVec'],ifShow)):
2996            if show:
2997                valSizer = wx.BoxSizer(wx.HORIZONTAL)
2998                modVal = wx.TextCtrl(G2frame.dataDisplay,value=('%.4f'%(val)),
2999                    size=wx.Size(50,20),style=wx.TE_PROCESS_ENTER)
3000                modVal.Bind(wx.EVT_TEXT_ENTER,OnModVal)       
3001                modVal.Bind(wx.EVT_KILL_FOCUS,OnModVal)
3002                valSizer.Add(modVal,0,WACV)
3003                modSpin = wx.SpinButton(G2frame.dataDisplay,style=wx.SP_VERTICAL,size=wx.Size(20,20))
3004                modSpin.SetValue(0)
3005                modSpin.SetRange(-1,1)
3006                modSpin.Bind(wx.EVT_SPIN, OnMoveMod)
3007                valSizer.Add(modSpin,0,WACV)
3008                ssSizer.Add(valSizer,0,WACV)
3009                Indx[modVal.GetId()] = i
3010                Indx[modSpin.GetId()] = [i,modVal]
3011            else:
3012                modVal = wx.TextCtrl(G2frame.dataDisplay,value=('%.3f'%(val)),
3013                    size=wx.Size(50,20),style=wx.TE_READONLY)
3014                modVal.SetBackgroundColour(VERY_LIGHT_GREY)
3015                ssSizer.Add(modVal,0,WACV)
3016        ssSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Max. M: '),0,WACV)
3017        maxMH = wx.ComboBox(G2frame.dataDisplay,value=str(ssopt['maxH']),
3018            choices=indChoice,style=wx.CB_READONLY|wx.CB_DROPDOWN)
3019        maxMH.Bind(wx.EVT_COMBOBOX, OnMaxMH)
3020        ssSizer.Add(maxMH,0,WACV)
3021        findMV = wx.wx.Button(G2frame.dataDisplay,label="Find mod. vec.?")
3022        findMV.Bind(wx.EVT_BUTTON,OnFindMV)
3023        ssSizer.Add(findMV,0,WACV)
3024        mainSizer.Add(ssSizer,0)
3025
3026    if cells:
3027        mainSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label='\n Indexing Result:'),0,WACV)
3028        rowLabels = []
3029        colLabels = ['M20','X20','use','Bravais','a','b','c','alpha','beta','gamma','Volume','Keep']
3030        Types = [wg.GRID_VALUE_FLOAT+':10,2',wg.GRID_VALUE_NUMBER,wg.GRID_VALUE_BOOL,wg.GRID_VALUE_STRING,]+ \
3031            3*[wg.GRID_VALUE_FLOAT+':10,5',]+3*[wg.GRID_VALUE_FLOAT+':10,3',]+ \
3032            [wg.GRID_VALUE_FLOAT+':10,2',wg.GRID_VALUE_BOOL]
3033        numRows = len(cells)
3034        table = []
3035        for cell in cells:
3036            rowLabels.append('')
3037            row = cell[0:2]+[cell[-2]]+[bravaisSymb[cell[2]]]+cell[3:10]+[cell[11],]
3038            if cell[-2]:
3039                A = G2lat.cell2A(cell[3:9])
3040                G2frame.HKL = G2lat.GenHBravais(dmin,cell[2],A)
3041                for hkl in G2frame.HKL:
3042                    hkl.insert(4,G2lat.Dsp2pos(Inst,hkl[3])+controls[1])
3043                G2frame.HKL = np.array(G2frame.HKL)
3044            table.append(row)
3045        UnitCellsTable = G2G.Table(table,rowLabels=rowLabels,colLabels=colLabels,types=Types)
3046        gridDisplay = G2G.GSGrid(G2frame.dataDisplay)
3047        gridDisplay.SetTable(UnitCellsTable, True)
3048        G2frame.dataFrame.CopyCell.Enable(True)
3049        gridDisplay.Bind(wg.EVT_GRID_CELL_LEFT_CLICK,RefreshUnitCellsGrid)
3050        gridDisplay.Bind(wg.EVT_GRID_LABEL_LEFT_DCLICK,OnSortCells)
3051        gridDisplay.SetMargins(0,0)
3052        gridDisplay.SetRowLabelSize(0)
3053        gridDisplay.AutoSizeColumns(False)
3054        for r in range(gridDisplay.GetNumberRows()):
3055            for c in range(gridDisplay.GetNumberCols()):
3056                if c == 2:
3057                    gridDisplay.SetReadOnly(r,c,isReadOnly=False)
3058                else:
3059                    gridDisplay.SetReadOnly(r,c,isReadOnly=True)
3060        mainSizer.Add(gridDisplay,0,WACV)
3061    mainSizer.Layout()   
3062    G2frame.dataDisplay.SetSizer(mainSizer)
3063    G2frame.dataDisplay.SetAutoLayout(1)
3064    G2frame.dataDisplay.SetupScrolling()
3065    Size = mainSizer.Fit(G2frame.dataFrame)
3066    Size[0] += 25
3067    G2frame.dataDisplay.SetSize(Size)
3068    G2frame.dataFrame.setSizePosLeft(Size)   
3069   
3070################################################################################
3071#####  Reflection list
3072################################################################################           
3073       
3074def UpdateReflectionGrid(G2frame,data,HKLF=False,Name=''):
3075    '''respond to selection of PWDR Reflections data tree item by displaying
3076    a table of reflections in the data window.
3077    '''
3078    def OnPlotHKL(event):
3079        '''Plots a layer of reflections
3080        '''
3081        phaseName = G2frame.RefList
3082        if phaseName not in ['Unknown',]:
3083            pId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Phases')
3084            phaseId =  G2gd.GetPatternTreeItemId(G2frame,pId,phaseName)
3085            General = G2frame.PatternTree.GetItemPyData(phaseId)['General']
3086            Super = General.get('Super',0)
3087            SuperVec = General.get('SuperVec',[])
3088        else:
3089            Super = 0
3090            SuperVec = []       
3091        if 'list' in str(type(data)):   #single crystal data is 2 dict in list
3092            refList = data[1]['RefList']
3093        else:                           #powder data is a dict of dicts; each same structure as SC 2nd dict
3094            refList = np.array(data[phaseName]['RefList'])
3095        FoMax = np.max(refList.T[8+Super])
3096        Hmin = np.array([int(np.min(refList.T[0])),int(np.min(refList.T[1])),int(np.min(refList.T[2]))])
3097        Hmax = np.array([int(np.max(refList.T[0])),int(np.max(refList.T[1])),int(np.max(refList.T[2]))])
3098        controls = {'Type' : 'Fo','ifFc' : True,'HKLmax' : Hmax,'HKLmin' : Hmin,
3099            'FoMax' : FoMax,'Zone' : '001','Layer' : 0,'Scale' : 1.0,'Super':Super,'SuperVec':SuperVec}
3100        G2plt.PlotSngl(G2frame,newPlot=True,Data=controls,hklRef=refList,Title=phaseName)
3101       
3102    def OnPlot3DHKL(event):
3103        '''Plots the reflections in 3D
3104        '''
3105        phaseName = G2frame.RefList
3106        if phaseName not in ['Unknown',]:
3107            pId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Phases')
3108            phaseId =  G2gd.GetPatternTreeItemId(G2frame,pId,phaseName)
3109            General = G2frame.PatternTree.GetItemPyData(phaseId)['General']
3110            Super = General.get('Super',0)
3111            SuperVec = General.get('SuperVec',[])
3112        else:
3113            Super = 0
3114            SuperVec = []       
3115        if 'list' in str(type(data)):   #single crystal data is 2 dict in list
3116            refList = data[1]['RefList']
3117        else:                           #powder data is a dict of dicts; each same structure as SC 2nd dict
3118            refList = np.array(data[phaseName]['RefList'])
3119        FoMax = np.max(refList.T[8+Super])
3120        Hmin = np.array([int(np.min(refList.T[0])),int(np.min(refList.T[1])),int(np.min(refList.T[2]))])
3121        Hmax = np.array([int(np.max(refList.T[0])),int(np.max(refList.T[1])),int(np.max(refList.T[2]))])
3122        Vpoint = np.array([int(np.mean(refList.T[0])),int(np.mean(refList.T[1])),int(np.mean(refList.T[2]))])
3123        controls = {'Type':'Fosq','Iscale':False,'HKLmax':Hmax,'HKLmin':Hmin,'Zone':False,'viewKey':'L',
3124            'FoMax' : FoMax,'Scale' : 1.0,'Drawing':{'viewPoint':[Vpoint,[]],'default':Vpoint[:],
3125            'backColor':[0,0,0],'depthFog':False,'Zclip':10.0,'cameraPos':10.,'Zstep':0.05,'viewUp':[0,1,0],
3126            'Scale':1.0,'oldxy':[],'viewDir':[0,0,1]},'Super':Super,'SuperVec':SuperVec}
3127        G2plt.Plot3DSngl(G2frame,newPlot=True,Data=controls,hklRef=refList,Title=phaseName)
3128       
3129    def MakeReflectionTable(phaseName):
3130        '''Returns a wx.grid table (G2G.Table) containing a list of all reflections
3131        for a phase.       
3132        '''
3133        if phaseName not in ['Unknown',]:
3134            pId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Phases')
3135            phaseId =  G2gd.GetPatternTreeItemId(G2frame,pId,phaseName)
3136            General = G2frame.PatternTree.GetItemPyData(phaseId)['General']
3137            Super = General.get('Super',0)
3138            SuperVec = General.get('SuperVec',[])
3139        else:
3140            Super = 0
3141            SuperVec = []       
3142        rowLabels = []
3143        if HKLF:
3144            refList = data[1]['RefList']
3145            refs = refList
3146        else:
3147            if len(data) > 1:
3148                G2frame.dataFrame.SelectPhase.Enable(True)
3149            try:            #patch for old reflection lists
3150                if not len(data[phaseName]):
3151                    return None
3152                refList = np.array(data[phaseName]['RefList'])
3153                I100 = refList.T[8+Super]*refList.T[11+Super]
3154            except TypeError:
3155                refList = np.array([refl[:11+Super] for refl in data[phaseName]])
3156                I100 = refList.T[8+Super]*np.array([refl[11+Super] for refl in data[phaseName]])
3157            Imax = np.max(I100)
3158            if Imax:
3159                I100 *= 100.0/Imax
3160            if 'C' in Inst['Type'][0]:
3161                refs = np.vstack((refList.T[:15+Super],I100)).T
3162            elif 'T' in Inst['Type'][0]:
3163                refs = np.vstack((refList.T[:18+Super],I100)).T
3164            G2frame.HKL = np.vstack((refList.T[:6+Super])).T    #build for plots
3165        rowLabels = [str(i) for i in range(len(refs))]
3166        Types = (4+Super)*[wg.GRID_VALUE_LONG,]+4*[wg.GRID_VALUE_FLOAT+':10,4',]+ \
3167            2*[wg.GRID_VALUE_FLOAT+':10,2',]+[wg.GRID_VALUE_FLOAT+':10,3',]+ \
3168            [wg.GRID_VALUE_FLOAT+':10,3',]
3169        if HKLF:
3170            colLabels = ['H','K','L','twin','d','Fosq','sig','Fcsq','FoTsq','FcTsq','phase','ExtC',]
3171            if 'T' in Inst['Type'][0]:
3172                colLabels = ['H','K','L','twin','d','Fosq','sig','Fcsq','FoTsq','FcTsq','phase','ExtC','wave','tbar']
3173                Types += 2*[wg.GRID_VALUE_FLOAT+':10,3',]
3174            if Super:
3175                colLabels.insert(3,'M')
3176        else:
3177            if 'C' in Inst['Type'][0]:
3178                colLabels = ['H','K','L','mul','d','pos','sig','gam','Fosq','Fcsq','phase','Icorr','Prfo','Trans','ExtP','I100']
3179                Types += 4*[wg.GRID_VALUE_FLOAT+':10,3',]
3180            elif 'T' in Inst['Type'][0]:
3181                colLabels = ['H','K','L','mul','d','pos','sig','gam','Fosq','Fcsq','phase','Icorr','alp','bet','wave','Prfo','Abs','Ext','I100']
3182                Types += 7*[wg.GRID_VALUE_FLOAT+':10,3',]
3183            if Super:
3184                colLabels.insert(3,'M')
3185        return G2G.Table(refs,rowLabels=rowLabels,colLabels=colLabels,types=Types)
3186
3187    def ShowReflTable(phaseName):
3188        '''Posts a table of reflections for a phase, creating the table
3189        if needed using MakeReflectionTable
3190        '''
3191        def setBackgroundColors(im,it):
3192            for r in range(G2frame.refTable[phaseName].GetNumberRows()):
3193                if HKLF:
3194                    if float(G2frame.refTable[phaseName].GetCellValue(r,3+im)) <= 0.:
3195                        G2frame.refTable[phaseName].SetCellBackgroundColour(r,3+im,wx.RED)
3196                    Fosq = float(G2frame.refTable[phaseName].GetCellValue(r,5+im))
3197                    Fcsq = float(G2frame.refTable[phaseName].GetCellValue(r,7+im))
3198                    sig = float(G2frame.refTable[phaseName].GetCellValue(r,6+im))
3199                    rat = abs(Fosq-Fcsq)/sig
3200                    if  rat > 10.:
3201                        G2frame.refTable[phaseName].SetCellBackgroundColour(r,7+im,wx.RED)
3202                    elif rat > 3.0:
3203                        G2frame.refTable[phaseName].SetCellBackgroundColour(r,7+im,wx.Colour(255,255,0))
3204#                    else:
3205#                        G2frame.refTable[phaseName].SetCellBackgroundColour(r,7+im,wx.WHITE)
3206                else:   #PWDR
3207                    if float(G2frame.refTable[phaseName].GetCellValue(r,12+im+it)) < 0.:
3208                        G2frame.refTable[phaseName].SetCellBackgroundColour(r,12+im+it,wx.RED)
3209                                                 
3210        G2frame.RefList = phaseName
3211        G2frame.dataFrame.SetLabel('Reflection List for '+phaseName)
3212        if HKLF:
3213            Status.SetStatusText('abs(DF)/sig > 10 red; > 3 yellow; twin < 0 (user rejected) red; twin=0 (sp. gp. absent) red')
3214        else:
3215            Status.SetStatusText('Prfo < 0. in red')
3216        it = 0
3217        if HKLF:
3218            im = data[1].get('Super',0)
3219        else:
3220            if 'T' in data[phaseName].get('Type',''):
3221                it = 3
3222            im = data[phaseName].get('Super',0)
3223        # has this table already been displayed?
3224        if G2frame.refTable[phaseName].GetTable() is None:
3225            PeakTable = MakeReflectionTable(phaseName)
3226            G2frame.refTable[phaseName].SetTable(PeakTable, True)
3227            G2frame.refTable[phaseName].EnableEditing(False)
3228            G2frame.refTable[phaseName].SetMargins(0,0)
3229            G2frame.refTable[phaseName].AutoSizeColumns(False)
3230            setBackgroundColors(im,it)
3231        # raise the tab (needed for 1st use and from OnSelectPhase)
3232        for PageNum in range(G2frame.dataDisplay.GetPageCount()):
3233            if phaseName == G2frame.dataDisplay.GetPageText(PageNum):
3234                G2frame.dataDisplay.SetSelection(PageNum)
3235                break
3236        else:
3237            print phaseName
3238            print phases
3239            raise Exception("how did we not find a phase name?")
3240       
3241    def OnPageChanged(event):
3242        '''Respond to a press on a phase tab by displaying the reflections. This
3243        routine is needed because the reflection table may not have been created yet.
3244        '''
3245        page = event.GetSelection()
3246        phaseName = G2frame.dataDisplay.GetPageText(page)
3247        ShowReflTable(phaseName)
3248
3249    def OnSelectPhase(event):
3250        '''For PWDR, selects a phase with a selection box. Called from menu.
3251        '''
3252        if len(phases) < 2: return
3253        dlg = wx.SingleChoiceDialog(G2frame,'Select','Phase',phases)
3254        try:
3255            if dlg.ShowModal() == wx.ID_OK:
3256                sel = dlg.GetSelection()
3257                ShowReflTable(phases[sel])
3258        finally:
3259            dlg.Destroy()
3260           
3261    if not data:
3262        print 'No phases, no reflections'
3263        return
3264    if HKLF:
3265        G2frame.RefList = 1
3266        phaseName = IsHistogramInAnyPhase(G2frame,Name)
3267        if not phaseName:
3268            phaseName = 'Unknown'
3269        phases = [phaseName]
3270    else:
3271        phaseName = G2frame.RefList
3272        phases = data.keys()
3273    if G2frame.dataDisplay:
3274        G2frame.dataFrame.Clear()
3275    Inst = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Instrument Parameters'))[0]
3276    if HKLF:
3277        G2gd.SetDataMenuBar(G2frame)
3278        G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.ReflMenu)
3279        if not G2frame.dataFrame.GetStatusBar():
3280            Status = G2frame.dataFrame.CreateStatusBar()   
3281        G2frame.Bind(wx.EVT_MENU, OnPlotHKL, id=G2gd.wxID_PWDHKLPLOT)
3282        G2frame.Bind(wx.EVT_MENU, OnPlot3DHKL, id=G2gd.wxID_PWD3DHKLPLOT)
3283        G2frame.dataFrame.SelectPhase.Enable(False)
3284    else:
3285        G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.ReflMenu)
3286        if not G2frame.dataFrame.GetStatusBar():
3287            Status = G2frame.dataFrame.CreateStatusBar()   
3288        G2frame.Bind(wx.EVT_MENU, OnSelectPhase, id=G2gd.wxID_SELECTPHASE)
3289        G2frame.Bind(wx.EVT_MENU, OnPlotHKL, id=G2gd.wxID_PWDHKLPLOT)
3290        G2frame.Bind(wx.EVT_MENU, OnPlot3DHKL, id=G2gd.wxID_PWD3DHKLPLOT)
3291        G2frame.dataFrame.SelectPhase.Enable(False)
3292           
3293    G2frame.dataDisplay = G2G.GSNoteBook(parent=G2frame.dataFrame,size=G2frame.dataFrame.GetClientSize())
3294    G2frame.refTable = {}
3295    for tabnum,phase in enumerate(phases):
3296        G2frame.refTable[phase] = G2G.GSGrid(parent=G2frame.dataDisplay)
3297        G2frame.dataDisplay.AddPage(G2frame.refTable[phase],phase)
3298#    if phaseName not in G2frame.refTable:
3299#        print phaseName
3300#        print phases
3301#        raise Exception("how did we get a invalid phase name?")   
3302    ShowReflTable(phaseName)
3303    G2frame.refTable[phaseName].Fit()
3304    size = G2frame.refTable[phaseName].GetSize()
3305    G2frame.dataFrame.setSizePosLeft([size[0]+32,350])       
3306    G2frame.dataDisplay.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CHANGED, OnPageChanged)
3307   
3308################################################################################
3309#####  SASD Substances
3310################################################################################
3311           
3312def UpdateSubstanceGrid(G2frame,data):
3313    '''respond to selection of SASD Substance data tree item.
3314    '''
3315    import Substances as substFile
3316   
3317    def OnLoadSubstance(event):
3318        names = substFile.Substances.keys()
3319        names.sort()
3320        dlg = wx.SingleChoiceDialog(G2frame, 'Which substance?', 'Select substance', names, wx.CHOICEDLG_STYLE)
3321        try:
3322            if dlg.ShowModal() == wx.ID_OK:
3323                name = names[dlg.GetSelection()]
3324            else:
3325                return
3326        finally:
3327            dlg.Destroy()
3328        data['Substances'][name] = {'Elements':{},'Volume':1.0,'Density':1.0,
3329            'Scatt density':0.0,'XAnom density':0.0,'XAbsorption':0.0}
3330        subst = substFile.Substances[name]
3331        ElList = subst['Elements'].keys()
3332        for El in ElList:
3333            Info = G2elem.GetAtomInfo(El.strip().capitalize())
3334            Info.update(subst['Elements'][El])
3335            data['Substances'][name]['Elements'][El] = Info
3336            if 'Volume' in subst:
3337                data['Substances'][name]['Volume'] = subst['Volume']
3338                data['Substances'][name]['Density'] = \
3339                    G2mth.Vol2Den(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])
3340            elif 'Density' in subst:
3341                data['Substances'][name]['Density'] = subst['Density']
3342                data['Substances'][name]['Volume'] = \
3343                    G2mth.Den2Vol(data['Substances'][name]['Elements'],data['Substances'][name]['Density'])
3344            else:
3345                data['Substances'][name]['Volume'] = G2mth.El2EstVol(data['Substances'][name]['Elements'])
3346                data['Substances'][name]['Density'] = \
3347                    G2mth.Vol2Den(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])
3348            data['Substances'][name]['Scatt density'] = \
3349                G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])[0]
3350            contrst,absorb = G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'],wave)         
3351            data['Substances'][name]['XAnom density'] = contrst
3352            data['Substances'][name]['XAbsorption'] = absorb
3353                         
3354        UpdateSubstanceGrid(G2frame,data)
3355       
3356    def OnCopySubstance(event):
3357        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
3358        histList = GetHistsLikeSelected(G2frame)
3359        if not histList:
3360            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
3361            return
3362        copyList = []
3363        dlg = G2G.G2MultiChoiceDialog(
3364            G2frame.dataFrame, 
3365            'Copy substances from\n'+hst[5:]+' to...',
3366            'Copy substances', histList)
3367        try:
3368            if dlg.ShowModal() == wx.ID_OK:
3369                for i in dlg.GetSelections(): 
3370                    copyList.append(histList[i])
3371        finally:
3372            dlg.Destroy()       
3373        for item in copyList:
3374            Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
3375            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Substances'),
3376                copy.copy(data))
3377   
3378    def OnAddSubstance(event):
3379        dlg = wx.TextEntryDialog(None,'Enter a name for this substance','Substance Name Entry','New substance',
3380            style=wx.OK)
3381        if dlg.ShowModal() == wx.ID_OK:
3382            Name = dlg.GetValue()
3383            data['Substances'][Name] = {'Elements':{},'Volume':1.0,'Density':1.0,
3384                'Scatt density':0.0,'XAnom density':0.,'XAbsorption':0.}
3385        dlg.Destroy()
3386        AddElement(Name)
3387        UpdateSubstanceGrid(G2frame,data)
3388       
3389    def OnDeleteSubstance(event):
3390        TextList = []
3391        for name in data['Substances']:
3392            if name != 'vacuum':
3393                TextList += [name,]
3394        if not TextList:
3395            return
3396        dlg = wx.SingleChoiceDialog(G2frame, 'Which substance?', 'Select substance to delete', TextList, wx.CHOICEDLG_STYLE)
3397        try:
3398            if dlg.ShowModal() == wx.ID_OK:
3399                name = TextList[dlg.GetSelection()]
3400            else:
3401                return
3402        finally:
3403            dlg.Destroy()
3404        del(data['Substances'][name])
3405        UpdateSubstanceGrid(G2frame,data)       
3406               
3407    def OnAddElement(event):       
3408        TextList = []
3409        for name in data['Substances']:
3410            if name != 'vacuum':
3411                TextList += [name,]
3412        if not TextList:
3413            return
3414        dlg = wx.SingleChoiceDialog(G2frame, 'Which substance?', 'Select substance', TextList, wx.CHOICEDLG_STYLE)
3415        try:
3416            if dlg.ShowModal() == wx.ID_OK:
3417                name = TextList[dlg.GetSelection()]
3418            else:
3419                return
3420        finally:
3421            dlg.Destroy()
3422        AddElement(name)
3423        UpdateSubstanceGrid(G2frame,data)
3424       
3425    def AddElement(name):
3426        ElList = data['Substances'][name]['Elements'].keys()
3427        dlg = G2elemGUI.PickElements(G2frame,ElList)
3428        if dlg.ShowModal() == wx.ID_OK:
3429            for El in dlg.Elem:
3430                El = El.strip().capitalize()
3431                Info = G2elem.GetAtomInfo(El)
3432                Info.update({'Num':1})
3433                data['Substances'][name]['Elements'][El] = Info
3434                data['Substances'][name]['Volume'] = G2mth.El2EstVol(data['Substances'][name]['Elements'])
3435                data['Substances'][name]['Density'] = \
3436                    G2mth.Vol2Den(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])
3437                data['Substances'][name]['Scatt density'] = \
3438                    G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])[0]
3439                contrst,absorb = G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'],wave)         
3440                data['Substances'][name]['XAnom density'] = contrst
3441                data['Substances'][name]['XAbsorption'] = absorb
3442        dlg.Destroy()
3443       
3444    def OnDeleteElement(event):
3445        TextList = []
3446        for name in data['Substances']:
3447            if name != 'vacuum':
3448                TextList += [name,]
3449        if not TextList:
3450            return
3451        dlg = wx.SingleChoiceDialog(G2frame, 'Which substance?', 'Select substance', TextList, wx.CHOICEDLG_STYLE)
3452        try:
3453            if dlg.ShowModal() == wx.ID_OK:
3454                name = TextList[dlg.GetSelection()]
3455            else:
3456                return
3457        finally:
3458            dlg.Destroy()
3459        ElList = data['Substances'][name]['Elements'].keys()
3460        if len(ElList):
3461            DE = G2elemGUI.DeleteElement(G2frame,ElList)
3462            if DE.ShowModal() == wx.ID_OK:
3463                El = DE.GetDeleteElement().strip().upper()
3464                del(data['Substances'][name]['Elements'][El])
3465                data['Substances'][name]['Volume'] = G2mth.El2EstVol(data['Substances'][name]['Elements'])
3466                data['Substances'][name]['Density'] = \
3467                    G2mth.Vol2Den(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])
3468                data['Substances'][name]['Scatt density'] = \
3469                    G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])[0]
3470                contrst,absorb = G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'],wave)         
3471                data['Substances'][name]['XAnom density'] = contrst
3472                data['Substances'][name]['XAbsorption'] = absorb
3473        UpdateSubstanceGrid(G2frame,data)
3474               
3475    def SubstSizer():
3476       
3477        def OnValueChange(event):
3478            Obj = event.GetEventObject()
3479            if len(Indx[Obj.GetId()]) == 3:
3480                name,El,keyId = Indx[Obj.GetId()]
3481                try:
3482                    value = max(0,float(Obj.GetValue()))
3483                except ValueError:
3484                    value = 0
3485                    Obj.SetValue('%.2f'%(value))
3486                data['Substances'][name]['Elements'][El][keyId] = value
3487                data['Substances'][name]['Volume'] = G2mth.El2EstVol(data['Substances'][name]['Elements'])
3488                data['Substances'][name]['Density'] = \
3489                    G2mth.Vol2Den(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])
3490            else:
3491                name,keyId = Indx[Obj.GetId()]
3492                try:
3493                    value = max(0,float(Obj.GetValue()))
3494                except ValueError:
3495                    value = 1.0
3496                data['Substances'][name][keyId] = value
3497                if keyId in 'Volume':
3498                    data['Substances'][name]['Density'] = \
3499                        G2mth.Vol2Den(data['Substances'][name]['Elements'],value)
3500                elif keyId in 'Density':
3501                    data['Substances'][name]['Volume'] = \
3502                        G2mth.Den2Vol(data['Substances'][name]['Elements'],value)
3503            data['Substances'][name]['Scatt density'] = \
3504                G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])[0]
3505            contrst,absorb = G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'],wave)         
3506            data['Substances'][name]['XAnom density'] = contrst
3507            data['Substances'][name]['XAbsorption'] = absorb
3508            wx.CallAfter(UpdateSubstanceGrid,G2frame,data)
3509       
3510        Indx = {}
3511        substSizer = wx.BoxSizer(wx.VERTICAL)
3512        substSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Substance list: wavelength: %.5fA'%(wave)),
3513            0,WACV)
3514        for name in data['Substances']:
3515            G2G.HorizontalLine(substSizer,G2frame.dataDisplay)   
3516            substSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Data for '+name+':'),
3517                0,WACV)
3518            if name == 'vacuum':
3519                substSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label='        Not applicable'),
3520                    0,WACV)
3521            else:   
3522                elSizer = wx.FlexGridSizer(0,6,5,5)
3523                Substance = data['Substances'][name]
3524                Elems = Substance['Elements']
3525                for El in Elems:    #do elements as pull downs for isotopes for neutrons
3526                    elSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' '+El+': '),
3527                        0,WACV)
3528                    num = wx.TextCtrl(G2frame.dataDisplay,value='%.2f'%(Elems[El]['Num']),style=wx.TE_PROCESS_ENTER)
3529                    Indx[num.GetId()] = [name,El,'Num']
3530                    num.Bind(wx.EVT_TEXT_ENTER,OnValueChange)       
3531                    num.Bind(wx.EVT_KILL_FOCUS,OnValueChange)
3532                    elSizer.Add(num,0,WACV)
3533                substSizer.Add(elSizer,0)
3534                vdsSizer = wx.FlexGridSizer(0,4,5,5)
3535                vdsSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Volume: '),
3536                    0,WACV)
3537                vol = wx.TextCtrl(G2frame.dataDisplay,value='%.3f'%(Substance['Volume']),style=wx.TE_PROCESS_ENTER)
3538                Indx[vol.GetId()] = [name,'Volume']
3539                vol.Bind(wx.EVT_TEXT_ENTER,OnValueChange)       
3540                vol.Bind(wx.EVT_KILL_FOCUS,OnValueChange)
3541                vdsSizer.Add(vol,0,WACV)               
3542                vdsSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Density: '),
3543                    0,WACV)
3544                den = wx.TextCtrl(G2frame.dataDisplay,value='%.3f'%(Substance['Density']),style=wx.TE_PROCESS_ENTER)
3545                Indx[den.GetId()] = [name,'Density']
3546                den.Bind(wx.EVT_TEXT_ENTER,OnValueChange)       
3547                den.Bind(wx.EVT_KILL_FOCUS,OnValueChange)
3548                vdsSizer.Add(den,0,WACV)
3549                substSizer.Add(vdsSizer,0)
3550                substSizer.Add(wx.StaticText(G2frame.dataDisplay,
3551                    label=' Scattering density  : %.2f *10%scm%s'%(Substance['Scatt density'],Pwr10,Pwrm2)),
3552                    0,WACV)               
3553                substSizer.Add(wx.StaticText(G2frame.dataDisplay,       #allow neutrons here into NAnom density & NAbsorption
3554                    label=' Anomalous density : %.2f *10%scm%s'%(Substance['XAnom density'],Pwr10,Pwrm2)),
3555                    0,WACV)               
3556                substSizer.Add(wx.StaticText(G2frame.dataDisplay,
3557                    label=' X-ray absorption   : %.2f cm%s'%(Substance['XAbsorption'],Pwrm1)),
3558                    0,WACV)               
3559        return substSizer
3560           
3561    Inst = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Instrument Parameters'))[0]
3562    wave = G2mth.getWave(Inst)
3563    if G2frame.dataDisplay:
3564        G2frame.dataFrame.DestroyChildren()  # is this a ScrolledWindow? If so, bad!
3565    G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.SubstanceMenu)
3566    if not G2frame.dataFrame.GetStatusBar():
3567        Status = G2frame.dataFrame.CreateStatusBar()
3568    G2frame.dataDisplay = wxscroll.ScrolledPanel(G2frame.dataFrame)
3569    G2frame.dataFrame.SetLabel('Substances')
3570    G2frame.dataFrame.Bind(wx.EVT_MENU, OnLoadSubstance, id=G2gd.wxID_LOADSUBSTANCE)   
3571    G2frame.dataFrame.Bind(wx.EVT_MENU, OnAddSubstance, id=G2gd.wxID_ADDSUBSTANCE)
3572    G2frame.dataFrame.Bind(wx.EVT_MENU, OnCopySubstance, id=G2gd.wxID_COPYSUBSTANCE)
3573    G2frame.dataFrame.Bind(wx.EVT_MENU, OnDeleteSubstance, id=G2gd.wxID_DELETESUBSTANCE)   
3574    G2frame.dataFrame.Bind(wx.EVT_MENU, OnAddElement, id=G2gd.wxID_ELEMENTADD)
3575    G2frame.dataFrame.Bind(wx.EVT_MENU, OnDeleteElement, id=G2gd.wxID_ELEMENTDELETE)
3576    mainSizer = wx.BoxSizer(wx.VERTICAL)
3577    mainSizer.Add(SubstSizer(),0)
3578
3579    mainSizer.Layout()   
3580    G2frame.dataDisplay.SetSizer(mainSizer)
3581    G2frame.dataDisplay.SetAutoLayout(1)
3582    G2frame.dataDisplay.SetupScrolling()
3583    Size = mainSizer.Fit(G2frame.dataFrame)
3584    Size[0] += 25
3585    G2frame.dataDisplay.SetSize(Size)
3586    G2frame.dataFrame.setSizePosLeft(Size)   
3587       
3588################################################################################
3589#####  SASD Models
3590################################################################################           
3591       
3592def UpdateModelsGrid(G2frame,data):
3593    '''respond to selection of SASD Models data tree item.
3594    '''
3595    #patches
3596    if 'Current' not in data:
3597        data['Current'] = 'Size dist.'
3598    if 'logBins' not in data['Size']:
3599        data['Size']['logBins'] = True
3600    if 'MinMaxDiam' in data['Size']:
3601        data['Size']['MinDiam'] = 50.
3602        data['Size']['MaxDiam'] = 10000.
3603        del data['Size']['MinMaxDiam']
3604    if isinstance(data['Size']['MaxEnt']['Sky'],float):
3605        data['Size']['MaxEnt']['Sky'] = -3
3606    if 'Power' not in data['Size']['IPG']:
3607        data['Size']['IPG']['Power'] = -1
3608    if 'Matrix' not in data['Particle']:
3609        data['Particle']['Matrix'] = {'Name':'vacuum','VolFrac':[0.0,False]}
3610    if 'BackFile' not in data:
3611        data['BackFile'] = ''
3612    #end patches
3613   
3614    def RefreshPlots(newPlot=False):
3615        PlotText = G2frame.G2plotNB.nb.GetPageText(G2frame.G2plotNB.nb.GetSelection())
3616        if 'Powder' in PlotText:
3617            G2plt.PlotPatterns(G2frame,plotType='SASD',newPlot=newPlot)
3618        elif 'Size' in PlotText:
3619            G2plt.PlotSASDSizeDist(G2frame)
3620               
3621    def OnAddModel(event):
3622        if data['Current'] == 'Particle fit':
3623            material = 'vacuum'
3624            if len(data['Particle']['Levels']):
3625                material = data['Particle']['Levels'][-1]['Controls']['Material']
3626            data['Particle']['Levels'].append({
3627                'Controls':{'FormFact':'Sphere','DistType':'LogNormal','Material':material,
3628                    'FFargs':{},'SFargs':{},'NumPoints':50,'Cutoff':0.01,'Contrast':0.0,
3629                    'SlitSmear':[0.0,False],'StrFact':'Dilute'},    #last 2 not used - future?
3630                'LogNormal':{'Volume':[0.05,False],'Mean':[1000.,False],'StdDev':[0.5,False],'MinSize':[10.,False],},
3631                'Gaussian':{'Volume':[0.05,False],'Mean':[1000.,False],'StdDev':[300.,False],},
3632                'LSW':{'Volume':[0.05,False],'Mean':[1000.0,False],},
3633                'Schulz-Zimm':{'Volume':[0.05,False],'Mean':[1000.,False],'StdDev':[300.,False],},
3634                'Unified':{'G':[1.e3,False],'Rg':[100,False],'B':[1.e-5,False],'P':[4,False],'Cutoff':[1e-5,False],},
3635                'Porod':{'B':[1.e-4,False],'P':[4,False],'Cutoff':[1e-5,False],},
3636                'Monodisperse':{'Volume':[0.05,False],'Radius':[100,False],},   #OK for spheres
3637                'Bragg':{'PkInt':[100,False],'PkPos':[0.2,False],
3638                    'PkSig':[10,False],'PkGam':[10,False],},        #reasonable 31A peak
3639                })
3640            G2sasd.ModelFxn(Profile,ProfDict,Limits,Sample,data)
3641            RefreshPlots(True)
3642                   
3643        wx.CallAfter(UpdateModelsGrid,G2frame,data)
3644       
3645    def OnCopyModel(event):
3646        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
3647        histList = GetHistsLikeSelected(G2frame)
3648        if not histList:
3649            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
3650            return
3651        copyList = []
3652        dlg = G2G.G2MultiChoiceDialog(
3653            G2frame.dataFrame, 
3654            'Copy models from\n'+hst[5:]+' to...',
3655            'Copy models', histList)
3656        try:
3657            if dlg.ShowModal() == wx.ID_OK:
3658                for i in dlg.GetSelections(): 
3659                    copyList.append(histList[i])
3660        finally:
3661            dlg.Destroy()       
3662        for item in copyList:
3663            Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
3664            newdata = copy.deepcopy(data)
3665            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Models'),newdata)
3666            if newdata['BackFile']:
3667                Profile = G2frame.PatternTree.GetItemPyData(Id)[1]
3668                BackId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,newdata['BackFile'])
3669                BackSample = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,BackId, 'Sample Parameters'))
3670                Profile[5] = BackSample['Scale'][0]*G2frame.PatternTree.GetItemPyData(BackId)[1][1]
3671        RefreshPlots(True)
3672               
3673    def OnCopyFlags(event):
3674        thisModel = copy.deepcopy(data)
3675        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
3676        histList = GetHistsLikeSelected(G2frame)
3677        if not histList:
3678            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
3679            return
3680        dlg = G2G.G2MultiChoiceDialog(
3681            G2frame.dataFrame, 
3682            'Copy sample ref. flags from\n'+str(hst[5:])+' to...',
3683            'Copy sample flags', histList)
3684        distChoice = ['LogNormal','Gaussian','LSW','Schulz-Zimm','Bragg','Unified',
3685            'Porod','Monodisperse',]
3686        parmOrder = ['Volume','Radius','Mean','StdDev','G','Rg','B','P',
3687            'Cutoff','PkInt','PkPos','PkSig','PkGam','VolFr','Dist',]
3688        try:
3689            if dlg.ShowModal() == wx.ID_OK:
3690                result = dlg.GetSelections()
3691                for i in result: 
3692                    item = histList[i]
3693                    Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
3694                    newModel = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Models'))
3695                    newModel['Back'][1] = copy.copy(thisModel['Back'][1])
3696                    for ilev,level in enumerate(newModel['Particle']['Levels']):
3697                        for form in level:
3698                            if form in distChoice:
3699                                thisForm = thisModel['Particle']['Levels'][ilev][form]                               
3700                                for item in parmOrder:
3701                                    if item in thisForm:
3702                                       level[form][item][1] = copy.copy(thisForm[item][1])
3703                            elif form == 'Controls':
3704                                thisForm = thisModel['Particle']['Levels'][ilev][form]['SFargs']
3705                                for item in parmOrder:
3706                                    if item in thisForm:
3707                                        level[form]['SFargs'][item][1] = copy.copy(thisForm[item][1])
3708        finally:
3709            dlg.Destroy()
3710               
3711    def OnFitModelAll(event):
3712        choices = G2gd.GetPatternTreeDataNames(G2frame,['SASD',])
3713        sel = []
3714        dlg = G2G.G2MultiChoiceDialog(G2frame.dataFrame, 'Sequential SASD refinement',
3715             'Select dataset to include',choices)
3716        dlg.SetSelections(sel)
3717        names = []
3718        if dlg.ShowModal() == wx.ID_OK:
3719            for sel in dlg.GetSelections():
3720                names.append(choices[sel])
3721        dlg.Destroy()
3722        SeqResult = {'histNames':names}
3723        Reverse = False
3724        CopyForward = False
3725        choice = ['Reverse sequence','Copy from prev.']
3726        dlg = wx.MultiChoiceDialog(G2frame.dataFrame,'Sequential controls','Select controls',choice)
3727        if dlg.ShowModal() == wx.ID_OK:
3728            for sel in dlg.GetSelections():
3729                if sel:
3730                    CopyForward = True
3731                else:
3732                    Reverse = True
3733        dlg.Destroy()
3734        dlg = wx.ProgressDialog('SASD Sequential fit','Data set name = '+names[0],len(names), 
3735            style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE|wx.PD_REMAINING_TIME|wx.PD_CAN_ABORT)
3736        wx.BeginBusyCursor()
3737        if Reverse:
3738            names.reverse()
3739        try:
3740            for i,name in enumerate(names):
3741                print ' Sequential fit for ',name
3742                GoOn = dlg.Update(i,newmsg='Data set name = '+name)[0]
3743                if not GoOn:
3744                    break
3745                Id =  G2gd.GetPatternTreeItemId(G2frame,G2frame.root,name)
3746                if i and CopyForward:
3747                    G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Models'),JModel)
3748                IProfDict,IProfile = G2frame.PatternTree.GetItemPyData(Id)[:2]
3749                IModel = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Models'))
3750                ISample = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Sample Parameters'))
3751                ILimits = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Limits'))
3752                IfOK,result,varyList,sig,Rvals,covMatrix,parmDict,Msg = G2sasd.ModelFit(IProfile,IProfDict,ILimits,ISample,IModel)
3753                JModel = copy.deepcopy(IModel)
3754                if not IfOK:
3755                    G2frame.ErrorDialog('Failed sequential refinement for data '+name,
3756                        ' Msg: '+Msg+'\nYou need to rethink your selection of parameters\n'+    \
3757                        ' Model restored to previous version for'+name)
3758                    SeqResult['histNames'] = names[:i]
3759                    dlg.Destroy()
3760                    break
3761                else:
3762                    G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Models'),copy.deepcopy(IModel))
3763               
3764                G2sasd.ModelFxn(IProfile,IProfDict,ILimits,ISample,IModel)
3765                SeqResult[name] = {'variables':result[0],'varyList':varyList,'sig':sig,'Rvals':Rvals,
3766                    'covMatrix':covMatrix,'title':name,'parmDict':parmDict}
3767            else:
3768                dlg.Destroy()
3769                print ' ***** Small angle sequential refinement successful *****'
3770        finally:
3771            wx.EndBusyCursor()   
3772        Id =  G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Sequential results')
3773        if Id:
3774            G2frame.PatternTree.SetItemPyData(Id,SeqResult)
3775        else:
3776            Id = G2frame.PatternTree.AppendItem(parent=G2frame.root,text='Sequential results')
3777            G2frame.PatternTree.SetItemPyData(Id,SeqResult)
3778        G2frame.PatternTree.SelectItem(Id)
3779       
3780    def OnFitModel(event):
3781        if data['Current'] == 'Size dist.':
3782            if not any(Sample['Contrast']):
3783                G2frame.ErrorDialog('No contrast; your sample is a vacuum!',
3784                    'You need to define a scattering substance!\n'+    \
3785                    ' Do Substances and then Sample parameters')
3786                return
3787            G2sasd.SizeDistribution(Profile,ProfDict,Limits,Sample,data)
3788            G2plt.PlotSASDSizeDist(G2frame)
3789            RefreshPlots(True)
3790           
3791        elif data['Current'] == 'Particle fit':
3792            SaveState()
3793            Results = G2sasd.ModelFit(Profile,ProfDict,Limits,Sample,data)
3794            if not Results[0]:
3795                    G2frame.ErrorDialog('Failed refinement',
3796                        ' Msg: '+Results[-1]+'\nYou need to rethink your selection of parameters\n'+    \
3797                        ' Model restored to previous version')
3798            G2sasd.ModelFxn(Profile,ProfDict,Limits,Sample,data)
3799            RefreshPlots(True)
3800            wx.CallAfter(UpdateModelsGrid,G2frame,data)
3801           
3802    def OnUnDo(event):
3803        DoUnDo()
3804        data = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,
3805            G2frame.PatternId,'Models'))
3806        G2frame.dataFrame.SasdUndo.Enable(False)
3807        UpdateModelsGrid(G2frame,data)
3808        G2sasd.ModelFxn(Profile,ProfDict,Limits,Sample,data)
3809        RefreshPlots(True)
3810
3811    def DoUnDo():
3812        print 'Undo last refinement'
3813        file = open(G2frame.undosasd,'rb')
3814        PatternId = G2frame.PatternId
3815        G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Models'),cPickle.load(file))
3816        print ' Models recovered'
3817        file.close()
3818       
3819    def SaveState():
3820        G2frame.undosasd = os.path.join(G2frame.dirname,'GSASIIsasd.save')
3821        file = open(G2frame.undosasd,'wb')
3822        PatternId = G2frame.PatternId
3823        for item in ['Models']:
3824            cPickle.dump(G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId,item)),file,1)
3825        file.close()
3826        G2frame.dataFrame.SasdUndo.Enable(True)
3827       
3828    def OnSelectFit(event):
3829        data['Current'] = fitSel.GetValue()
3830        wx.CallAfter(UpdateModelsGrid,G2frame,data)
3831       
3832    def OnCheckBox(event):
3833        Obj = event.GetEventObject()
3834        item,ind = Indx[Obj.GetId()]
3835        item[ind] = Obj.GetValue()
3836       
3837    def OnIntVal(event):
3838        Obj = event.GetEventObject()
3839        item,ind,minVal = Indx[Obj.GetId()]
3840        try:
3841            value = int(Obj.GetValue())
3842            if value <= minVal:
3843                raise ValueError
3844        except ValueError:
3845            value = item[ind]
3846        Obj.SetValue(str(value))
3847        item[ind] = value
3848
3849    def SizeSizer():
3850       
3851        def OnShape(event):
3852            data['Size']['Shape'][0] = partsh.GetValue()
3853            wx.CallAfter(UpdateModelsGrid,G2frame,data)
3854           
3855        def OnMethod(event):
3856            data['Size']['Method'] = method.GetValue()
3857            wx.CallAfter(UpdateModelsGrid,G2frame,data)
3858           
3859        def OnPartVal(event):
3860            try:
3861                val = max(0.0,float(partprm.GetValue()))
3862            except ValueError:
3863                val = 1
3864            data['Size']['Shape'][1] = val
3865            partprm.SetValue('%.3f'%(val))
3866           
3867        sizeSizer = wx.BoxSizer(wx.VERTICAL)
3868        sizeSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Size distribution parameters: '),0,WACV)
3869        binSizer = wx.FlexGridSizer(0,7,5,5)
3870        binSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' No. size bins: '),0,WACV)
3871        bins = ['50','100','150','200']
3872        nbins = wx.ComboBox(G2frame.dataDisplay,value=str(data['Size']['Nbins']),choices=bins,
3873            style=wx.CB_READONLY|wx.CB_DROPDOWN)
3874        Indx[nbins.GetId()] = [data['Size'],'Nbins',0]
3875        nbins.Bind(wx.EVT_COMBOBOX,OnIntVal)       
3876        binSizer.Add(nbins,0,WACV)
3877        binSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Min diam.: '),0,WACV)
3878        minDias = ['10','25','50','100','150','200']
3879        mindiam = wx.ComboBox(G2frame.dataDisplay,value=str(data['Size']['MinDiam']),choices=minDias,
3880            style=wx.CB_DROPDOWN)
3881        mindiam.Bind(wx.EVT_LEAVE_WINDOW,OnIntVal)
3882        mindiam.Bind(wx.EVT_TEXT_ENTER,OnIntVal)       
3883        mindiam.Bind(wx.EVT_KILL_FOCUS,OnIntVal)
3884        Indx[mindiam.GetId()] = [data['Size'],'MinDiam',0]
3885        binSizer.Add(mindiam,0,WACV)
3886        binSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Max diam.: '),0,WACV)
3887        maxDias = [str(1000*(i+1)) for i in range(10)]
3888        maxdiam = wx.ComboBox(G2frame.dataDisplay,value=str(data['Size']['MaxDiam']),choices=maxDias,
3889            style=wx.CB_DROPDOWN)
3890        maxdiam.Bind(wx.EVT_LEAVE_WINDOW,OnIntVal)
3891        maxdiam.Bind(wx.EVT_TEXT_ENTER,OnIntVal)       
3892        maxdiam.Bind(wx.EVT_KILL_FOCUS,OnIntVal)
3893        Indx[maxdiam.GetId()] = [data['Size'],'MaxDiam',0]
3894        binSizer.Add(maxdiam,0,WACV)
3895        logbins = wx.CheckBox(G2frame.dataDisplay,label='Log bins?')
3896        Indx[logbins.GetId()] = [data['Size'],'logBins']
3897        logbins.SetValue(data['Size']['logBins'])
3898        logbins.Bind(wx.EVT_CHECKBOX, OnCheckBox)
3899        binSizer.Add(logbins,0,WACV)
3900        sizeSizer.Add(binSizer,0)
3901        sizeSizer.Add((5,5),0)
3902        partSizer = wx.BoxSizer(wx.HORIZONTAL)
3903        partSizer.Add(wx.StaticText(G2frame.dataDisplay,label='Particle description: '),0,WACV)
3904        shapes = {'Spheroid':' Aspect ratio: ','Cylinder':' Diameter ','Cylinder AR':' Aspect ratio: ',
3905            'Unified sphere':'','Unified rod':' Diameter: ','Unified rod AR':' Aspect ratio: ',
3906            'Unified disk':' Thickness: '}
3907        partsh = wx.ComboBox(G2frame.dataDisplay,value=str(data['Size']['Shape'][0]),choices=shapes.keys(),
3908            style=wx.CB_READONLY|wx.CB_DROPDOWN)
3909        partsh.Bind(wx.EVT_COMBOBOX,OnShape)       
3910        partSizer.Add(partsh,0,WACV)
3911        if data['Size']['Shape'][0] not in ['Unified sphere',]:
3912            partSizer.Add(wx.StaticText(G2frame.dataDisplay,label=shapes[data['Size']['Shape'][0]]),0,WACV)
3913            partprm = wx.TextCtrl(G2frame.dataDisplay,value='%.3f'%(data['Size']['Shape'][1]),
3914                style=wx.TE_PROCESS_ENTER)
3915            partprm.Bind(wx.EVT_TEXT_ENTER,OnPartVal)       
3916            partprm.Bind(wx.EVT_KILL_FOCUS,OnPartVal)
3917            partSizer.Add(partprm,0,WACV)
3918        sizeSizer.Add(partSizer,0)
3919        sizeSizer.Add((5,5),0)
3920        fitSizer = wx.BoxSizer(wx.HORIZONTAL)
3921        methods = ['MaxEnt','IPG',]
3922        fitSizer.Add(wx.StaticText(G2frame.dataDisplay,label='Fitting method: '),0,WACV)
3923        method = wx.ComboBox(G2frame.dataDisplay,value=data['Size']['Method'],choices=methods,
3924            style=wx.CB_READONLY|wx.CB_DROPDOWN)
3925        method.Bind(wx.EVT_COMBOBOX,OnMethod)
3926        fitSizer.Add(method,0,WACV)
3927        iters = ['10','25','50','100','150','200']       
3928        fitSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' No. iterations: '),0,WACV)
3929        Method = data['Size']['Method']
3930        iter = wx.ComboBox(G2frame.dataDisplay,value=str(data['Size'][Method]['Niter']),choices=iters,
3931            style=wx.CB_READONLY|wx.CB_DROPDOWN)
3932        Indx[iter.GetId()] = [data['Size'][Method],'Niter',0]
3933        iter.Bind(wx.EVT_COMBOBOX,OnIntVal)
3934        fitSizer.Add(iter,0,WACV)
3935        if 'MaxEnt' in data['Size']['Method']:
3936            fitSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Log floor factor: '),0,WACV)
3937            floors = [str(-i) for i in range(9)]
3938            floor = wx.ComboBox(G2frame.dataDisplay,value=str(data['Size']['MaxEnt']['Sky']),choices=floors,
3939                style=wx.CB_READONLY|wx.CB_DROPDOWN)
3940            Indx[floor.GetId()] = [data['Size']['MaxEnt'],'Sky',-10]
3941            floor.Bind(wx.EVT_COMBOBOX,OnIntVal)
3942            fitSizer.Add(floor,0,WACV)
3943        elif 'IPG' in data['Size']['Method']:
3944            fitSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Q power weight (-1 for sigma): '),0,WACV)
3945            choices = ['-1','0','1','2','3','4']
3946            power = wx.ComboBox(G2frame.dataDisplay,value=str(data['Size']['IPG']['Power']),choices=choices,
3947                style=wx.CB_READONLY|wx.CB_DROPDOWN)
3948            Indx[power.GetId()] = [data['Size']['IPG'],'Power',-2]
3949            power.Bind(wx.EVT_COMBOBOX,OnIntVal)
3950            fitSizer.Add(power,0,WACV)
3951        sizeSizer.Add(fitSizer,0)
3952
3953        return sizeSizer
3954       
3955    def PartSizer():
3956       
3957        FormFactors = {'Sphere':{},'Spheroid':{'Aspect ratio':[1.0,False]},
3958            'Cylinder':{'Length':[100.,False]},'Cylinder diam':{'Diameter':[100.,False]},
3959            'Cylinder AR':{'Aspect ratio':[1.0,False]},'Unified sphere':{},
3960            'Unified rod':{'Length':[100.,False]},'Unified rod AR':{'Aspect ratio':[1.0,False]},
3961            'Unified disk':{'Thickness':[100.,False]},
3962            'Unified tube':{'Length':[100.,False],'Thickness':[10.,False]},}
3963               
3964        StructureFactors = {'Dilute':{},'Hard sphere':{'VolFr':[0.1,False],'Dist':[100.,False]},
3965            'Sticky hard sphere':{'VolFr':[0.1,False],'Dist':[100.,False],'epis':[0.05,False],'Sticky':[0.2,False]},
3966            'Square well':{'VolFr':[0.1,False],'Dist':[100.,False],'Depth':[0.1,False],'Width':[1.,False]},
3967            'InterPrecipitate':{'VolFr':[0.1,False],'Dist':[100.,False]},}
3968               
3969        ffDistChoices =  ['Sphere','Spheroid','Cylinder','Cylinder diam',
3970            'Cylinder AR','Unified sphere','Unified rod','Unified rod AR',
3971            'Unified disk','Unified tube',]
3972               
3973        ffMonoChoices = ['Sphere','Spheroid','Cylinder','Cylinder AR',]
3974       
3975        sfChoices = ['Dilute','Hard sphere','Sticky hard sphere','Square well','InterPrecipitate',]
3976           
3977        slMult = 1000.
3978                 
3979        def OnValue(event):
3980            Obj = event.GetEventObject()
3981            item,key,sldrObj = Indx[Obj.GetId()]
3982            try:
3983                value = float(Obj.GetValue())
3984                if value <= 0.:
3985                    raise ValueError
3986            except ValueError:
3987                value = item[key][0]
3988            item[key][0] = value
3989            Obj.SetValue('%.3g'%(value))
3990            if key in ['P','epis','Sticky','Depth','Width','VolFr','Dist']:
3991                sldrObj.SetValue(slMult*value)
3992            else:
3993                logv = np.log10(value)
3994                valMinMax = [logv-1,logv+1]
3995                sldrObj.SetRange(slMult*valMinMax[0],slMult*valMinMax[1])
3996                sldrObj.SetValue(slMult*logv)
3997            G2sasd.ModelFxn(Profile,ProfDict,Limits,Sample,data)
3998            RefreshPlots()
3999           
4000        def OnSelect(event):
4001            Obj = event.GetEventObject()
4002            item,key = Indx[Obj.GetId()]
4003            item[key] = Obj.GetValue()
4004            if 'Refine' not in Obj.GetLabel():
4005                if 'FormFact' in key :
4006                    item['FFargs'] = FormFactors[Obj.GetValue()]
4007                elif 'StrFact' in key:
4008                    item['SFargs'] = StructureFactors[Obj.GetValue()]
4009                wx.CallAfter(UpdateModelsGrid,G2frame,data)
4010                G2sasd.ModelFxn(Profile,ProfDict,Limits,Sample,data)
4011                RefreshPlots()
4012               
4013        def OnDelLevel(event):
4014            Obj = event.GetEventObject()
4015            item = Indx[Obj.GetId()]
4016            del data['Particle']['Levels'][item]
4017            wx.CallAfter(UpdateModelsGrid,G2frame,data)
4018            G2sasd.ModelFxn(Profile,ProfDict,Limits,Sample,data)
4019            RefreshPlots()
4020           
4021        def OnParmSlider(event):
4022            Obj = event.GetEventObject()
4023            item,key,pvObj = Indx[Obj.GetId()]
4024            slide = Obj.GetValue()
4025            if key in ['P','epis','Sticky','Depth','Width','VolFr','Dist']:
4026                value = float(slide/slMult)
4027            else:
4028                value = 10.**float(slide/slMult)
4029            item[key][0] = value
4030            pvObj.SetValue('%.3g'%(item[key][0]))
4031            G2sasd.ModelFxn(Profile,ProfDict,Limits,Sample,data)
4032            RefreshPlots()
4033           
4034        def SizeSizer():
4035            sizeSizer = wx.FlexGridSizer(0,4,5,5)
4036            sizeSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Distribution: '),0,WACV)
4037            Distchoice = ['LogNormal','Gaussian','LSW','Schulz-Zimm','Bragg','Unified','Porod','Monodisperse',]
4038            distChoice = wx.ComboBox(G2frame.dataDisplay,value=level['Controls']['DistType'],choices=Distchoice,
4039                style=wx.CB_READONLY|wx.CB_DROPDOWN)
4040            Indx[distChoice.GetId()] = [level['Controls'],'DistType']
4041            distChoice.Bind(wx.EVT_COMBOBOX,OnSelect)
4042            sizeSizer.Add(distChoice,0,WACV)    #put structure factor choices here
4043            if level['Controls']['DistType'] not in ['Bragg','Unified','Porod',]:
4044                sizeSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Form Factor: '),0,WACV)
4045                if 'Mono' in level['Controls']['DistType']:
4046                    ffChoice = wx.ComboBox(G2frame.dataDisplay,value=level['Controls']['FormFact'],choices=ffMonoChoices,
4047                        style=wx.CB_READONLY|wx.CB_DROPDOWN)
4048                else:
4049                    ffChoice = wx.ComboBox(G2frame.dataDisplay,value=level['Controls']['FormFact'],choices=ffDistChoices,
4050                        style=wx.CB_READONLY|wx.CB_DROPDOWN)
4051                Indx[ffChoice.GetId()] = [level['Controls'],'FormFact']
4052                ffChoice.Bind(wx.EVT_COMBOBOX,OnSelect)
4053                sizeSizer.Add(ffChoice,0,WACV)
4054               
4055                sizeSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Material: '),0,WACV)
4056                matSel = wx.ComboBox(G2frame.dataDisplay,value=level['Controls']['Material'],
4057                    choices=Substances['Substances'].keys(),style=wx.CB_READONLY|wx.CB_DROPDOWN)
4058                Indx[matSel.GetId()] = [level['Controls'],'Material']
4059                matSel.Bind(wx.EVT_COMBOBOX,OnSelect)       
4060                sizeSizer.Add(matSel,0,WACV) #do neutron test here?
4061                rho = Substances['Substances'][level['Controls']['Material']].get('XAnom density',0.0)
4062                level['Controls']['Contrast'] = contrast = (rho-rhoMat)**2                 
4063                sizeSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Resonant X-ray contrast: '),0,WACV)
4064                sizeSizer.Add(wx.StaticText(G2frame.dataDisplay,label=%.2f 10%scm%s'%(contrast,Pwr20,Pwrm4)),0,WACV)
4065                if 'Mono' not in level['Controls']['DistType']:
4066                    sizeSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Num. radii: '),0,WACV)
4067                    radii = ['25','50','75','100','200']
4068                    nRadii = wx.ComboBox(G2frame.dataDisplay,value=str(level['Controls']['NumPoints']),choices=radii,
4069                        style=wx.CB_READONLY|wx.CB_DROPDOWN)
4070                    Indx[nRadii.GetId()] = [level['Controls'],'NumPoints']
4071                    nRadii.Bind(wx.EVT_COMBOBOX,OnSelect)
4072                    sizeSizer.Add(nRadii,0,WACV)
4073                    sizeSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' R dist. cutoff: '),0,WACV)
4074                    rCutoff = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,level['Controls'],'Cutoff',
4075                        min=0.001,max=0.1,typeHint=float)
4076                    sizeSizer.Add(rCutoff,0,WACV)
4077            elif level['Controls']['DistType']  in ['Unified',]:
4078                Parms = level['Unified']
4079                Best = G2sasd.Bestimate(Parms['G'][0],Parms['Rg'][0],Parms['P'][0])
4080                sizeSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Estimated Dist B: %12.4g'%(Best)),0,WACV)
4081            return sizeSizer
4082           
4083        def ParmSizer():
4084            parmSizer = wx.FlexGridSizer(0,3,5,5)
4085            parmSizer.AddGrowableCol(2,1)
4086            parmSizer.SetFlexibleDirection(wx.HORIZONTAL)
4087            Parms = level[level['Controls']['DistType']]
4088            FFargs = level['Controls']['FFargs']
4089            SFargs = level['Controls'].get('SFargs',{})
4090            parmOrder = ['Volume','Radius','Mean','StdDev','MinSize','G','Rg','B','P','Cutoff',
4091                'PkInt','PkPos','PkSig','PkGam',]
4092            for parm in parmOrder:
4093                if parm in Parms:
4094                    if parm == 'MinSize':
4095                        parmSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Dist '+parm),0,wx.ALIGN_CENTER)
4096                    else:
4097                        parmVar = wx.CheckBox(G2frame.dataDisplay,label='Refine? Dist '+parm) 
4098                        parmVar.SetValue(Parms[parm][1])
4099                        parmVar.Bind(wx.EVT_CHECKBOX, OnSelect)
4100                        parmSizer.Add(parmVar,0,WACV)
4101                        Indx[parmVar.GetId()] = [Parms[parm],1]
4102                    parmValue = wx.TextCtrl(G2frame.dataDisplay,value='%.3g'%(Parms[parm][0]),
4103                        style=wx.TE_PROCESS_ENTER)
4104                    parmValue.Bind(wx.EVT_TEXT_ENTER,OnValue)       
4105                    parmValue.Bind(wx.EVT_KILL_FOCUS,OnValue)
4106                    parmSizer.Add(parmValue,0,WACV)
4107                    if parm == 'P':
4108                        value = Parms[parm][0]
4109                        valMinMax = [0.1,4.2]
4110                    else:
4111                        value = np.log10(Parms[parm][0])
4112                        valMinMax = [value-1,value+1]
4113                    parmSldr = wx.Slider(G2frame.dataDisplay,minValue=slMult*valMinMax[0],
4114                        maxValue=slMult*valMinMax[1],value=slMult*value)
4115                    Indx[parmValue.GetId()] = [Parms,parm,parmSldr]
4116                    Indx[parmSldr.GetId()] = [Parms,parm,parmValue]
4117                    parmSldr.Bind(wx.EVT_SLIDER,OnParmSlider)
4118                    parmSizer.Add(parmSldr,1,wx.EXPAND)
4119            if level['Controls']['DistType'] not in ['Bragg']:
4120                parmOrder = ['A