source: trunk/GSASIIpwdGUI.py @ 1894

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

Twins & Flack parameter can't exist together - make each exclusive
rename TwinFr?;n as TwinFr:n so constraint will work
Add a "Clear" option for fixed background points
Prevent Add, Move, Del ops. for fixed points when toolbar active

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