source: trunk/GSASIIpwdGUI.py @ 2117

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

refactor powder indexing to remove wx from G2index
change indexing progress bar to allow Skip of current Bravais search
Also only makes one Progress Bar Dialog

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