source: trunk/GSASIIpwdGUI.py @ 2151

Last change on this file since 2151 was 2151, checked in by vondreele, 6 years ago

add Generic TOF to defaultIparms.py; forces user to set flight path & 2-theta
modify instparm reading to sort out multibank issues
add MultiFloatDialog? to solicit multi values from user

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