source: trunk/GSASIIpwdGUI.py @ 2109

Last change on this file since 2109 was 2109, checked in by toby, 6 years ago

Andrey's enhancement: keep track of last GPX, import & export directories; optionally save the 1st two

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 228.4 KB
Line 
1# -*- coding: utf-8 -*-
2#GSASIIpwdGUI - powder data display routines
3########### SVN repository information ###################
4# $Date: 2015-12-27 04:22:09 +0000 (Sun, 27 Dec 2015) $
5# $Author: toby $
6# $Revision: 2109 $
7# $URL: trunk/GSASIIpwdGUI.py $
8# $Id: GSASIIpwdGUI.py 2109 2015-12-27 04:22:09Z toby $
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: 2109 $")
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(1.0,max(-1.0,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.001
2484        Obj.SetValue(0)
2485        value = min(1.0,max(-1.0,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        OK,dmin,newcells = G2indx.DoIndexPeaks(peaks[0],controls,bravais,G2frame.ifX20)
2773        cells = keepcells+newcells
2774        cells = G2indx.sortM20(cells)
2775        if OK:
2776            cells[0][10] = True         #select best M20
2777            data = [controls,bravais,cells,dmin,ssopt]
2778            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Unit Cells List'),data)
2779            bestCell = cells[0]
2780            if bestCell[0] > 10.:
2781                G2frame.HKL = G2lat.GenHBravais(dmin,bestCell[2],G2lat.cell2A(bestCell[3:9]))
2782                for hkl in G2frame.HKL:
2783                    hkl.insert(4,G2lat.Dsp2pos(Inst,hkl[3])+controls[1])
2784                G2frame.HKL = np.array(G2frame.HKL)
2785                if 'PKS' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
2786                    G2plt.PlotPowderLines(G2frame)
2787                else:
2788                    G2plt.PlotPatterns(G2frame)
2789            G2frame.dataFrame.CopyCell.Enable(True)
2790            G2frame.dataFrame.IndexPeaks.Enable(True)
2791            G2frame.dataFrame.MakeNewPhase.Enable(True)
2792            G2frame.ifX20 = True
2793            wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)
2794               
2795    def RefreshUnitCellsGrid(event):
2796        data = G2frame.PatternTree.GetItemPyData(UnitCellsId)
2797        cells,dminx = data[2:4]
2798        r,c =  event.GetRow(),event.GetCol()
2799        if cells:
2800            if c == 2:
2801                for i in range(len(cells)):
2802                    cells[i][-2] = False
2803                    UnitCellsTable.SetValue(i,c,False)
2804                UnitCellsTable.SetValue(r,c,True)
2805                gridDisplay.ForceRefresh()
2806                cells[r][-2] = True
2807                ibrav = cells[r][2]
2808                A = G2lat.cell2A(cells[r][3:9])
2809                G2frame.HKL = G2lat.GenHBravais(dmin,ibrav,A)
2810                for hkl in G2frame.HKL:
2811                    hkl.insert(4,G2lat.Dsp2pos(Inst,hkl[3])+controls[1])
2812                G2frame.HKL = np.array(G2frame.HKL)
2813                if 'PKS' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
2814                    G2plt.PlotPowderLines(G2frame)
2815                else:
2816                    G2plt.PlotPatterns(G2frame)
2817            elif c == 11:
2818                if UnitCellsTable.GetValue(r,c):
2819                    UnitCellsTable.SetValue(r,c,False)
2820                    cells[r][c] = False
2821                else:
2822                    cells[r][c] = True
2823                    UnitCellsTable.SetValue(r,c,True)
2824                gridDisplay.ForceRefresh()
2825            G2frame.PatternTree.SetItemPyData(UnitCellsId,data)
2826       
2827    def MakeNewPhase(event):
2828        if not G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Phases'):
2829            sub = G2frame.PatternTree.AppendItem(parent=G2frame.root,text='Phases')
2830        else:
2831            sub = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Phases')
2832        PhaseName = ''
2833        dlg = wx.TextEntryDialog(None,'Enter a name for this phase','Phase Name Entry','New phase',
2834            style=wx.OK)
2835        try:
2836            if dlg.ShowModal() == wx.ID_OK:
2837                PhaseName = dlg.GetValue()
2838                cells = G2frame.PatternTree.GetItemPyData(UnitCellsId)[2]
2839                for Cell in cells:
2840                    if Cell[-2]:
2841                        break
2842                cell = Cell[2:10]       
2843                sub = G2frame.PatternTree.AppendItem(parent=sub,text=PhaseName)
2844                E,SGData = G2spc.SpcGroup(controls[13])
2845                G2frame.PatternTree.SetItemPyData(sub, \
2846                    G2IO.SetNewPhase(Name=PhaseName,SGData=SGData,cell=cell[1:],Super=ssopt))
2847                Status.SetStatusText('Change space group from '+str(controls[13])+' if needed')
2848        finally:
2849            dlg.Destroy()
2850           
2851    if G2frame.dataDisplay:
2852        G2frame.dataFrame.DestroyChildren()
2853    G2frame.dataDisplay = wxscroll.ScrolledPanel(G2frame.dataFrame)
2854    G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.IndexMenu)
2855    if not G2frame.dataFrame.GetStatusBar():
2856        Status = G2frame.dataFrame.CreateStatusBar()
2857    G2frame.Bind(wx.EVT_MENU, IndexPeaks, id=G2gd.wxID_INDEXPEAKS)
2858    G2frame.Bind(wx.EVT_MENU, CopyUnitCell, id=G2gd.wxID_COPYCELL)
2859    G2frame.Bind(wx.EVT_MENU, RefineCell, id=G2gd.wxID_REFINECELL)
2860    G2frame.Bind(wx.EVT_MENU, MakeNewPhase, id=G2gd.wxID_MAKENEWPHASE)
2861    G2frame.Bind(wx.EVT_MENU, OnExportCells, id=G2gd.wxID_EXPORTCELLS)
2862       
2863    controls,bravais,cells,dminx,ssopt = data
2864    if len(controls) < 13:              #add cell volume if missing
2865        controls.append(G2lat.calc_V(G2lat.cell2A(controls[6:12])))
2866    if len(controls) < 14:              #add space group used in indexing
2867        controls.append(spaceGroups[bravaisSymb.index(controls[5])])
2868    G2frame.PatternTree.SetItemPyData(UnitCellsId,data)            #update with volume
2869    bravaisNames = ['Cubic-F','Cubic-I','Cubic-P','Trigonal-R','Trigonal/Hexagonal-P',
2870        'Tetragonal-I','Tetragonal-P','Orthorhombic-F','Orthorhombic-I','Orthorhombic-C',
2871        'Orthorhombic-P','Monoclinic-C','Monoclinic-P','Triclinic']
2872    cellGUIlist = [[[0,1,2],4,zip([" Unit cell: a = "," Vol = "],["%.5f","%.3f"],[True,False],[0,0])],
2873    [[3,4,5,6],6,zip([" Unit cell: a = "," c = "," Vol = "],["%.5f","%.5f","%.3f"],[True,True,False],[0,2,0])],
2874    [[7,8,9,10],8,zip([" Unit cell: a = "," b = "," c = "," Vol = "],["%.5f","%.5f","%.5f","%.3f"],
2875        [True,True,True,False],[0,1,2,0])],
2876    [[11,12],10,zip([" Unit cell: a = "," b = "," c = "," beta = "," Vol = "],
2877        ["%.5f","%.5f","%.5f","%.3f","%.3f"],[True,True,True,True,False],[0,1,2,4,0])],
2878    [[13,],8,zip([" Unit cell: a = "," b = "," c = "," Vol = "," alpha = "," beta = "," gamma = "],
2879        ["%.5f","%.5f","%.5f","%.3f","%.3f","%.3f","%.3f"],
2880        [True,True,True,False,True,True,True],[0,1,2,0,3,4,5])]]
2881   
2882    G2frame.dataFrame.SetLabel('Unit Cells List')
2883    G2frame.dataFrame.IndexPeaks.Enable(False)
2884    peaks = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Index Peak List'))
2885    if peaks:
2886        G2frame.dataFrame.IndexPeaks.Enable(True)
2887    G2frame.dataFrame.RefineCell.Enable(False)
2888    if controls[12] > 1.0:                               #if a "real" volume (i.e. not default)
2889        G2frame.dataFrame.RefineCell.Enable(True)   
2890    G2frame.dataFrame.CopyCell.Enable(False)
2891    G2frame.dataFrame.MakeNewPhase.Enable(False)       
2892    G2frame.dataFrame.ExportCells.Enable(False)
2893    if cells:
2894        G2frame.dataFrame.CopyCell.Enable(True)
2895        G2frame.dataFrame.MakeNewPhase.Enable(True)
2896        G2frame.dataFrame.ExportCells.Enable(True)
2897    mainSizer = wx.BoxSizer(wx.VERTICAL)
2898    mainSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Indexing controls: '),0,WACV)
2899    mainSizer.Add((5,5),0)
2900    littleSizer = wx.FlexGridSizer(0,5,5,5)
2901    littleSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Max Nc/Nobs '),0,WACV)
2902    NcNo = wx.SpinCtrl(G2frame.dataDisplay)
2903    NcNo.SetRange(2,8)
2904    NcNo.SetValue(controls[2])
2905    NcNo.Bind(wx.EVT_SPINCTRL,OnNcNo)
2906    littleSizer.Add(NcNo,0,WACV)
2907    littleSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Start Volume '),0,WACV)
2908    startVol = wx.TextCtrl(G2frame.dataDisplay,value=str('%d'%(controls[3])),style=wx.TE_PROCESS_ENTER)
2909    startVol.Bind(wx.EVT_TEXT_ENTER,OnStartVol)
2910    startVol.Bind(wx.EVT_KILL_FOCUS,OnStartVol)
2911    littleSizer.Add(startVol,0,WACV)
2912    x20 = wx.CheckBox(G2frame.dataDisplay,label='Use M20/(X20+1)?')
2913    x20.SetValue(G2frame.ifX20)
2914    x20.Bind(wx.EVT_CHECKBOX,OnIfX20)
2915    littleSizer.Add(x20,0,WACV)
2916    mainSizer.Add(littleSizer,0)
2917    mainSizer.Add((5,5),0)
2918    mainSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Select Bravais Lattices for indexing: '),
2919        0,WACV)
2920    mainSizer.Add((5,5),0)
2921    littleSizer = wx.FlexGridSizer(0,7,5,5)
2922    bravList = []
2923    bravs = zip(bravais,bravaisNames)
2924    for brav,bravName in bravs:
2925        bravCk = wx.CheckBox(G2frame.dataDisplay,label=bravName)
2926        bravList.append(bravCk.GetId())
2927        bravCk.SetValue(brav)
2928        bravCk.Bind(wx.EVT_CHECKBOX,OnBravais)
2929        littleSizer.Add(bravCk,0,WACV)
2930    mainSizer.Add(littleSizer,0)
2931    mainSizer.Add((5,5),0)
2932   
2933    mainSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Cell Refinement: '),0,WACV)
2934    mainSizer.Add((5,5),0)
2935    littleSizer = wx.BoxSizer(wx.HORIZONTAL)
2936    littleSizer.Add(wx.StaticText(G2frame.dataDisplay,label=" Bravais lattice "),0,WACV)
2937    bravSel = wx.Choice(G2frame.dataDisplay,choices=bravaisSymb)
2938    bravSel.SetSelection(bravaisSymb.index(controls[5]))
2939    bravSel.Bind(wx.EVT_CHOICE,OnBravSel)
2940    littleSizer.Add(bravSel,0,WACV)
2941    littleSizer.Add(wx.StaticText(G2frame.dataDisplay,label=" Space group "),0,WACV)
2942    spcSel = wx.Choice(G2frame.dataDisplay,choices=SPGlist[controls[5]])
2943    spcSel.SetSelection(SPGlist[controls[5]].index(controls[13]))
2944    spcSel.Bind(wx.EVT_CHOICE,OnSpcSel)
2945    littleSizer.Add(spcSel,0,WACV)
2946    if ssopt.get('Use',False):        #zero for super lattice doesn't work!
2947        controls[0] = False
2948    else:
2949        littleSizer.Add(wx.StaticText(G2frame.dataDisplay,label=" Zero offset"),0,WACV)
2950        zero = wx.TextCtrl(G2frame.dataDisplay,value="%.4f"%(controls[1]),style=wx.TE_PROCESS_ENTER)
2951        zero.Bind(wx.EVT_TEXT_ENTER,OnZero)
2952        zero.Bind(wx.EVT_KILL_FOCUS,OnZero)
2953        littleSizer.Add(zero,0,WACV)
2954        zeroVar = wx.CheckBox(G2frame.dataDisplay,label="Refine?")
2955        zeroVar.SetValue(controls[0])
2956        zeroVar.Bind(wx.EVT_CHECKBOX,OnZeroVar)
2957        littleSizer.Add(zeroVar,0,WACV)
2958    SSopt = wx.CheckBox(G2frame.dataDisplay,label="Super lattice?")
2959    SSopt.SetValue(ssopt.get('Use',False))
2960    SSopt.Bind(wx.EVT_CHECKBOX,OnSSopt)
2961    littleSizer.Add(SSopt,0,WACV)
2962    hklShow = wx.Button(G2frame.dataDisplay,label="Show hkl positions")
2963    hklShow.Bind(wx.EVT_BUTTON,OnHklShow)
2964    littleSizer.Add(hklShow,0,WACV)
2965    mainSizer.Add(littleSizer,0)
2966   
2967    mainSizer.Add((5,5),0)
2968    ibrav = SetLattice(controls)
2969    for cellGUI in cellGUIlist:
2970        if ibrav in cellGUI[0]:
2971            useGUI = cellGUI
2972    cellList = []
2973    valDict = {}
2974    littleSizer = wx.FlexGridSizer(0,useGUI[1],5,5)
2975    for txt,fmt,ifEdit,Id in useGUI[2]:
2976        littleSizer.Add(wx.StaticText(G2frame.dataDisplay,label=txt),0,WACV)
2977        if ifEdit:          #a,b,c,etc.
2978            cellVal = wx.TextCtrl(G2frame.dataDisplay,value=(fmt%(controls[6+Id])),style=wx.TE_PROCESS_ENTER)
2979            cellVal.Bind(wx.EVT_TEXT_ENTER,OnCellChange)       
2980            cellVal.Bind(wx.EVT_KILL_FOCUS,OnCellChange)
2981            valSizer = wx.BoxSizer(wx.HORIZONTAL)
2982            valSizer.Add(cellVal,0,WACV)
2983            cellSpin = wx.SpinButton(G2frame.dataDisplay,style=wx.SP_VERTICAL,size=wx.Size(20,20))
2984            cellSpin.SetValue(0)
2985            cellSpin.SetRange(-1,1)
2986            cellSpin.Bind(wx.EVT_SPIN, OnMoveCell)
2987            valSizer.Add(cellSpin,0,WACV)
2988            littleSizer.Add(valSizer,0,WACV)
2989            cellList.append(cellVal.GetId())
2990            cellList.append(cellSpin.GetId())
2991            valDict[cellSpin.GetId()] = cellVal
2992        else:               #volume
2993            volVal = wx.TextCtrl(G2frame.dataDisplay,value=(fmt%(controls[12])),style=wx.TE_READONLY)
2994            volVal.SetBackgroundColour(VERY_LIGHT_GREY)
2995            littleSizer.Add(volVal,0,WACV)
2996    mainSizer.Add(littleSizer,0)
2997    if ssopt.get('Use',False):        #super lattice display
2998        indChoice = ['1','2','3','4',]
2999        SpSg = controls[13]
3000        ssChoice = G2spc.ssdict[SpSg]
3001        if ssopt['ssSymb'] not in ssChoice:
3002            ssopt['ssSymb'] = ssChoice[0]
3003        ssSizer = wx.BoxSizer(wx.HORIZONTAL)
3004        ssSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Supersymmetry space group: '+SpSg+' '),0,WACV)
3005        selMG = wx.ComboBox(G2frame.dataDisplay,value=ssopt['ssSymb'],
3006                choices=ssChoice,style=wx.CB_READONLY|wx.CB_DROPDOWN)
3007        selMG.Bind(wx.EVT_COMBOBOX, OnSelMG)
3008        ssSizer.Add(selMG,0,WACV)
3009        ssSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Mod. vector: '),0,WACV)
3010        modS = G2spc.splitSSsym(ssopt['ssSymb'])[0]
3011        ssopt['ModVec'],ifShow = G2spc.SSGModCheck(ssopt['ModVec'],modS)
3012        Indx = {}
3013        for i,[val,show] in enumerate(zip(ssopt['ModVec'],ifShow)):
3014            if show:
3015                valSizer = wx.BoxSizer(wx.HORIZONTAL)
3016                modVal = wx.TextCtrl(G2frame.dataDisplay,value=('%.4f'%(val)),
3017                    size=wx.Size(50,20),style=wx.TE_PROCESS_ENTER)
3018                modVal.Bind(wx.EVT_TEXT_ENTER,OnModVal)       
3019                modVal.Bind(wx.EVT_KILL_FOCUS,OnModVal)
3020                valSizer.Add(modVal,0,WACV)
3021                modSpin = wx.SpinButton(G2frame.dataDisplay,style=wx.SP_VERTICAL,size=wx.Size(20,20))
3022                modSpin.SetValue(0)
3023                modSpin.SetRange(-1,1)
3024                modSpin.Bind(wx.EVT_SPIN, OnMoveMod)
3025                valSizer.Add(modSpin,0,WACV)
3026                ssSizer.Add(valSizer,0,WACV)
3027                Indx[modVal.GetId()] = i
3028                Indx[modSpin.GetId()] = [i,modVal]
3029            else:
3030                modVal = wx.TextCtrl(G2frame.dataDisplay,value=('%.3f'%(val)),
3031                    size=wx.Size(50,20),style=wx.TE_READONLY)
3032                modVal.SetBackgroundColour(VERY_LIGHT_GREY)
3033                ssSizer.Add(modVal,0,WACV)
3034        ssSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Max. M: '),0,WACV)
3035        maxMH = wx.ComboBox(G2frame.dataDisplay,value=str(ssopt['maxH']),
3036            choices=indChoice,style=wx.CB_READONLY|wx.CB_DROPDOWN)
3037        maxMH.Bind(wx.EVT_COMBOBOX, OnMaxMH)
3038        ssSizer.Add(maxMH,0,WACV)
3039        findMV = wx.wx.Button(G2frame.dataDisplay,label="Find mod. vec.?")
3040        findMV.Bind(wx.EVT_BUTTON,OnFindMV)
3041        ssSizer.Add(findMV,0,WACV)
3042        mainSizer.Add(ssSizer,0)
3043
3044    if cells:
3045        mainSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label='\n Indexing Result:'),0,WACV)
3046        rowLabels = []
3047        colLabels = ['M20','X20','use','Bravais','a','b','c','alpha','beta','gamma','Volume','Keep']
3048        Types = [wg.GRID_VALUE_FLOAT+':10,2',wg.GRID_VALUE_NUMBER,wg.GRID_VALUE_BOOL,wg.GRID_VALUE_STRING,]+ \
3049            3*[wg.GRID_VALUE_FLOAT+':10,5',]+3*[wg.GRID_VALUE_FLOAT+':10,3',]+ \
3050            [wg.GRID_VALUE_FLOAT+':10,2',wg.GRID_VALUE_BOOL]
3051        numRows = len(cells)
3052        table = []
3053        for cell in cells:
3054            rowLabels.append('')
3055            row = cell[0:2]+[cell[-2]]+[bravaisSymb[cell[2]]]+cell[3:10]+[cell[11],]
3056            if cell[-2]:
3057                A = G2lat.cell2A(cell[3:9])
3058                G2frame.HKL = G2lat.GenHBravais(dmin,cell[2],A)
3059                for hkl in G2frame.HKL:
3060                    hkl.insert(4,G2lat.Dsp2pos(Inst,hkl[3])+controls[1])
3061                G2frame.HKL = np.array(G2frame.HKL)
3062            table.append(row)
3063        UnitCellsTable = G2G.Table(table,rowLabels=rowLabels,colLabels=colLabels,types=Types)
3064        gridDisplay = G2G.GSGrid(G2frame.dataDisplay)
3065        gridDisplay.SetTable(UnitCellsTable, True)
3066        G2frame.dataFrame.CopyCell.Enable(True)
3067        gridDisplay.Bind(wg.EVT_GRID_CELL_LEFT_CLICK,RefreshUnitCellsGrid)
3068        gridDisplay.Bind(wg.EVT_GRID_LABEL_LEFT_DCLICK,OnSortCells)
3069        gridDisplay.SetMargins(0,0)
3070        gridDisplay.SetRowLabelSize(0)
3071        gridDisplay.AutoSizeColumns(False)
3072        for r in range(gridDisplay.GetNumberRows()):
3073            for c in range(gridDisplay.GetNumberCols()):
3074                if c == 2:
3075                    gridDisplay.SetReadOnly(r,c,isReadOnly=False)
3076                else:
3077                    gridDisplay.SetReadOnly(r,c,isReadOnly=True)
3078        mainSizer.Add(gridDisplay,0,WACV)
3079    mainSizer.Layout()   
3080    G2frame.dataDisplay.SetSizer(mainSizer)
3081    G2frame.dataDisplay.SetAutoLayout(1)
3082    G2frame.dataDisplay.SetupScrolling()
3083    Size = mainSizer.Fit(G2frame.dataFrame)
3084    Size[0] += 25
3085    G2frame.dataDisplay.SetSize(Size)
3086    G2frame.dataFrame.setSizePosLeft(Size)   
3087   
3088################################################################################
3089#####  Reflection list
3090################################################################################           
3091       
3092def UpdateReflectionGrid(G2frame,data,HKLF=False,Name=''):
3093    '''respond to selection of PWDR Reflections data tree item by displaying
3094    a table of reflections in the data window.
3095    '''
3096    def OnPlotHKL(event):
3097        '''Plots a layer of reflections
3098        '''
3099        phaseName = G2frame.RefList
3100        if phaseName not in ['Unknown',]:
3101            pId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Phases')
3102            phaseId =  G2gd.GetPatternTreeItemId(G2frame,pId,phaseName)
3103            General = G2frame.PatternTree.GetItemPyData(phaseId)['General']
3104            Super = General.get('Super',0)
3105            SuperVec = General.get('SuperVec',[])
3106        else:
3107            Super = 0
3108            SuperVec = []       
3109        if 'list' in str(type(data)):   #single crystal data is 2 dict in list
3110            refList = data[1]['RefList']
3111        else:                           #powder data is a dict of dicts; each same structure as SC 2nd dict
3112            refList = np.array(data[phaseName]['RefList'])
3113        FoMax = np.max(refList.T[8+Super])
3114        Hmin = np.array([int(np.min(refList.T[0])),int(np.min(refList.T[1])),int(np.min(refList.T[2]))])
3115        Hmax = np.array([int(np.max(refList.T[0])),int(np.max(refList.T[1])),int(np.max(refList.T[2]))])
3116        controls = {'Type' : 'Fo','ifFc' : True,'HKLmax' : Hmax,'HKLmin' : Hmin,
3117            'FoMax' : FoMax,'Zone' : '001','Layer' : 0,'Scale' : 1.0,'Super':Super,'SuperVec':SuperVec}
3118        G2plt.PlotSngl(G2frame,newPlot=True,Data=controls,hklRef=refList,Title=phaseName)
3119       
3120    def OnPlot3DHKL(event):
3121        '''Plots the reflections in 3D
3122        '''
3123        phaseName = G2frame.RefList
3124        if phaseName not in ['Unknown',]:
3125            pId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Phases')
3126            phaseId =  G2gd.GetPatternTreeItemId(G2frame,pId,phaseName)
3127            General = G2frame.PatternTree.GetItemPyData(phaseId)['General']
3128            Super = General.get('Super',0)
3129            SuperVec = General.get('SuperVec',[])
3130        else:
3131            Super = 0
3132            SuperVec = []       
3133        if 'list' in str(type(data)):   #single crystal data is 2 dict in list
3134            refList = data[1]['RefList']
3135        else:                           #powder data is a dict of dicts; each same structure as SC 2nd dict
3136            refList = np.array(data[phaseName]['RefList'])
3137        FoMax = np.max(refList.T[8+Super])
3138        Hmin = np.array([int(np.min(refList.T[0])),int(np.min(refList.T[1])),int(np.min(refList.T[2]))])
3139        Hmax = np.array([int(np.max(refList.T[0])),int(np.max(refList.T[1])),int(np.max(refList.T[2]))])
3140        Vpoint = np.array([int(np.mean(refList.T[0])),int(np.mean(refList.T[1])),int(np.mean(refList.T[2]))])
3141        controls = {'Type':'Fosq','Iscale':False,'HKLmax':Hmax,'HKLmin':Hmin,'Zone':False,'viewKey':'L',
3142            'FoMax' : FoMax,'Scale' : 1.0,'Drawing':{'viewPoint':[Vpoint,[]],'default':Vpoint[:],
3143            'backColor':[0,0,0],'depthFog':False,'Zclip':10.0,'cameraPos':10.,'Zstep':0.05,'viewUp':[0,1,0],
3144            'Scale':1.0,'oldxy':[],'viewDir':[0,0,1]},'Super':Super,'SuperVec':SuperVec}
3145        G2plt.Plot3DSngl(G2frame,newPlot=True,Data=controls,hklRef=refList,Title=phaseName)
3146       
3147    def MakeReflectionTable(phaseName):
3148        '''Returns a wx.grid table (G2G.Table) containing a list of all reflections
3149        for a phase.       
3150        '''
3151        if phaseName not in ['Unknown',]:
3152            pId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Phases')
3153            phaseId =  G2gd.GetPatternTreeItemId(G2frame,pId,phaseName)
3154            General = G2frame.PatternTree.GetItemPyData(phaseId)['General']
3155            Super = General.get('Super',0)
3156            SuperVec = General.get('SuperVec',[])
3157        else:
3158            Super = 0
3159            SuperVec = []       
3160        rowLabels = []
3161        if HKLF:
3162            refList = data[1]['RefList']
3163            refs = refList
3164        else:
3165            if len(data) > 1:
3166                G2frame.dataFrame.SelectPhase.Enable(True)
3167            try:            #patch for old reflection lists
3168                if not len(data[phaseName]):
3169                    return None
3170                refList = np.array(data[phaseName]['RefList'])
3171                I100 = refList.T[8+Super]*refList.T[11+Super]
3172            except TypeError:
3173                refList = np.array([refl[:11+Super] for refl in data[phaseName]])
3174                I100 = refList.T[8+Super]*np.array([refl[11+Super] for refl in data[phaseName]])
3175            Imax = np.max(I100)
3176            if Imax:
3177                I100 *= 100.0/Imax
3178            if 'C' in Inst['Type'][0]:
3179                refs = np.vstack((refList.T[:15+Super],I100)).T
3180            elif 'T' in Inst['Type'][0]:
3181                refs = np.vstack((refList.T[:18+Super],I100)).T
3182            G2frame.HKL = np.vstack((refList.T[:6+Super])).T    #build for plots
3183        rowLabels = [str(i) for i in range(len(refs))]
3184        Types = (4+Super)*[wg.GRID_VALUE_LONG,]+4*[wg.GRID_VALUE_FLOAT+':10,4',]+ \
3185            2*[wg.GRID_VALUE_FLOAT+':10,2',]+[wg.GRID_VALUE_FLOAT+':10,3',]+ \
3186            [wg.GRID_VALUE_FLOAT+':10,3',]
3187        if HKLF:
3188            colLabels = ['H','K','L','twin','d','Fosq','sig','Fcsq','FoTsq','FcTsq','phase','ExtC',]
3189            if 'T' in Inst['Type'][0]:
3190                colLabels = ['H','K','L','twin','d','Fosq','sig','Fcsq','FoTsq','FcTsq','phase','ExtC','wave','tbar']
3191                Types += 2*[wg.GRID_VALUE_FLOAT+':10,3',]
3192            if Super:
3193                colLabels.insert(3,'M')
3194        else:
3195            if 'C' in Inst['Type'][0]:
3196                colLabels = ['H','K','L','mul','d','pos','sig','gam','Fosq','Fcsq','phase','Icorr','Prfo','Trans','ExtP','I100']
3197                Types += 4*[wg.GRID_VALUE_FLOAT+':10,3',]
3198            elif 'T' in Inst['Type'][0]:
3199                colLabels = ['H','K','L','mul','d','pos','sig','gam','Fosq','Fcsq','phase','Icorr','alp','bet','wave','Prfo','Abs','Ext','I100']
3200                Types += 7*[wg.GRID_VALUE_FLOAT+':10,3',]
3201            if Super:
3202                colLabels.insert(3,'M')
3203        return G2G.Table(refs,rowLabels=rowLabels,colLabels=colLabels,types=Types)
3204
3205    def ShowReflTable(phaseName):
3206        '''Posts a table of reflections for a phase, creating the table
3207        if needed using MakeReflectionTable
3208        '''
3209        def setBackgroundColors(im,it):
3210            for r in range(G2frame.refTable[phaseName].GetNumberRows()):
3211                if HKLF:
3212                    if float(G2frame.refTable[phaseName].GetCellValue(r,3+im)) <= 0.:
3213                        G2frame.refTable[phaseName].SetCellBackgroundColour(r,3+im,wx.RED)
3214                    Fosq = float(G2frame.refTable[phaseName].GetCellValue(r,5+im))
3215                    Fcsq = float(G2frame.refTable[phaseName].GetCellValue(r,7+im))
3216                    sig = float(G2frame.refTable[phaseName].GetCellValue(r,6+im))
3217                    rat = abs(Fosq-Fcsq)/sig
3218                    if  rat > 10.:
3219                        G2frame.refTable[phaseName].SetCellBackgroundColour(r,7+im,wx.RED)
3220                    elif rat > 3.0:
3221                        G2frame.refTable[phaseName].SetCellBackgroundColour(r,7+im,wx.Colour(255,255,0))
3222#                    else:
3223#                        G2frame.refTable[phaseName].SetCellBackgroundColour(r,7+im,wx.WHITE)
3224                else:   #PWDR
3225                    if float(G2frame.refTable[phaseName].GetCellValue(r,12+im+it)) < 0.:
3226                        G2frame.refTable[phaseName].SetCellBackgroundColour(r,12+im+it,wx.RED)
3227                                                 
3228        G2frame.RefList = phaseName
3229        G2frame.dataFrame.SetLabel('Reflection List for '+phaseName)
3230        if HKLF:
3231            Status.SetStatusText('abs(DF)/sig > 10 red; > 3 yellow; twin < 0 (user rejected) red; twin=0 (sp. gp. absent) red')
3232        else:
3233            Status.SetStatusText('Prfo < 0. in red')
3234        it = 0
3235        if HKLF:
3236            im = data[1].get('Super',0)
3237        else:
3238            if 'T' in data[phaseName].get('Type',''):
3239                it = 3
3240            im = data[phaseName].get('Super',0)
3241        # has this table already been displayed?
3242        if G2frame.refTable[phaseName].GetTable() is None:
3243            PeakTable = MakeReflectionTable(phaseName)
3244            G2frame.refTable[phaseName].SetTable(PeakTable, True)
3245            G2frame.refTable[phaseName].EnableEditing(False)
3246            G2frame.refTable[phaseName].SetMargins(0,0)
3247            G2frame.refTable[phaseName].AutoSizeColumns(False)
3248            setBackgroundColors(im,it)
3249        # raise the tab (needed for 1st use and from OnSelectPhase)
3250        for PageNum in range(G2frame.dataDisplay.GetPageCount()):
3251            if phaseName == G2frame.dataDisplay.GetPageText(PageNum):
3252                G2frame.dataDisplay.SetSelection(PageNum)
3253                break
3254        else:
3255            print phaseName
3256            print phases
3257            raise Exception("how did we not find a phase name?")
3258       
3259    def OnPageChanged(event):
3260        '''Respond to a press on a phase tab by displaying the reflections. This
3261        routine is needed because the reflection table may not have been created yet.
3262        '''
3263        page = event.GetSelection()
3264        phaseName = G2frame.dataDisplay.GetPageText(page)
3265        ShowReflTable(phaseName)
3266
3267    def OnSelectPhase(event):
3268        '''For PWDR, selects a phase with a selection box. Called from menu.
3269        '''
3270        if len(phases) < 2: return
3271        dlg = wx.SingleChoiceDialog(G2frame,'Select','Phase',phases)
3272        try:
3273            if dlg.ShowModal() == wx.ID_OK:
3274                sel = dlg.GetSelection()
3275                ShowReflTable(phases[sel])
3276        finally:
3277            dlg.Destroy()
3278           
3279    if not data:
3280        print 'No phases, no reflections'
3281        return
3282    if HKLF:
3283        G2frame.RefList = 1
3284        phaseName = IsHistogramInAnyPhase(G2frame,Name)
3285        if not phaseName:
3286            phaseName = 'Unknown'
3287        phases = [phaseName]
3288    else:
3289        phaseName = G2frame.RefList
3290        phases = data.keys()
3291    if G2frame.dataDisplay:
3292        G2frame.dataFrame.Clear()
3293    Inst = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Instrument Parameters'))[0]
3294    if HKLF:
3295        G2gd.SetDataMenuBar(G2frame)
3296        G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.ReflMenu)
3297        if not G2frame.dataFrame.GetStatusBar():
3298            Status = G2frame.dataFrame.CreateStatusBar()   
3299        G2frame.Bind(wx.EVT_MENU, OnPlotHKL, id=G2gd.wxID_PWDHKLPLOT)
3300        G2frame.Bind(wx.EVT_MENU, OnPlot3DHKL, id=G2gd.wxID_PWD3DHKLPLOT)
3301        G2frame.dataFrame.SelectPhase.Enable(False)
3302    else:
3303        G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.ReflMenu)
3304        if not G2frame.dataFrame.GetStatusBar():
3305            Status = G2frame.dataFrame.CreateStatusBar()   
3306        G2frame.Bind(wx.EVT_MENU, OnSelectPhase, id=G2gd.wxID_SELECTPHASE)
3307        G2frame.Bind(wx.EVT_MENU, OnPlotHKL, id=G2gd.wxID_PWDHKLPLOT)
3308        G2frame.Bind(wx.EVT_MENU, OnPlot3DHKL, id=G2gd.wxID_PWD3DHKLPLOT)
3309        G2frame.dataFrame.SelectPhase.Enable(False)
3310           
3311    G2frame.dataDisplay = G2G.GSNoteBook(parent=G2frame.dataFrame,size=G2frame.dataFrame.GetClientSize())
3312    G2frame.refTable = {}
3313    for tabnum,phase in enumerate(phases):
3314        G2frame.refTable[phase] = G2G.GSGrid(parent=G2frame.dataDisplay)
3315        G2frame.dataDisplay.AddPage(G2frame.refTable[phase],phase)
3316#    if phaseName not in G2frame.refTable:
3317#        print phaseName
3318#        print phases
3319#        raise Exception("how did we get a invalid phase name?")   
3320    ShowReflTable(phaseName)
3321    G2frame.refTable[phaseName].Fit()
3322    size = G2frame.refTable[phaseName].GetSize()
3323    G2frame.dataFrame.setSizePosLeft([size[0]+32,350])       
3324    G2frame.dataDisplay.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CHANGED, OnPageChanged)
3325   
3326################################################################################
3327#####  SASD Substances
3328################################################################################
3329           
3330def UpdateSubstanceGrid(G2frame,data):
3331    '''respond to selection of SASD Substance data tree item.
3332    '''
3333    import Substances as substFile
3334   
3335    def OnLoadSubstance(event):
3336        names = substFile.Substances.keys()
3337        names.sort()
3338        dlg = wx.SingleChoiceDialog(G2frame, 'Which substance?', 'Select substance', names, wx.CHOICEDLG_STYLE)
3339        try:
3340            if dlg.ShowModal() == wx.ID_OK:
3341                name = names[dlg.GetSelection()]
3342            else:
3343                return
3344        finally:
3345            dlg.Destroy()
3346        data['Substances'][name] = {'Elements':{},'Volume':1.0,'Density':1.0,
3347            'Scatt density':0.0,'XAnom density':0.0,'XAbsorption':0.0}
3348        subst = substFile.Substances[name]
3349        ElList = subst['Elements'].keys()
3350        for El in ElList:
3351            Info = G2elem.GetAtomInfo(El.strip().capitalize())
3352            Info.update(subst['Elements'][El])
3353            data['Substances'][name]['Elements'][El] = Info
3354            if 'Volume' in subst:
3355                data['Substances'][name]['Volume'] = subst['Volume']
3356                data['Substances'][name]['Density'] = \
3357                    G2mth.Vol2Den(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])
3358            elif 'Density' in subst:
3359                data['Substances'][name]['Density'] = subst['Density']
3360                data['Substances'][name]['Volume'] = \
3361                    G2mth.Den2Vol(data['Substances'][name]['Elements'],data['Substances'][name]['Density'])
3362            else:
3363                data['Substances'][name]['Volume'] = G2mth.El2EstVol(data['Substances'][name]['Elements'])
3364                data['Substances'][name]['Density'] = \
3365                    G2mth.Vol2Den(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])
3366            data['Substances'][name]['Scatt density'] = \
3367                G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])[0]
3368            contrst,absorb = G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'],wave)         
3369            data['Substances'][name]['XAnom density'] = contrst
3370            data['Substances'][name]['XAbsorption'] = absorb
3371                         
3372        UpdateSubstanceGrid(G2frame,data)
3373       
3374    def OnCopySubstance(event):
3375        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
3376        histList = GetHistsLikeSelected(G2frame)
3377        if not histList:
3378            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
3379            return
3380        copyList = []
3381        dlg = G2G.G2MultiChoiceDialog(
3382            G2frame.dataFrame, 
3383            'Copy substances from\n'+hst[5:]+' to...',
3384            'Copy substances', histList)
3385        try:
3386            if dlg.ShowModal() == wx.ID_OK:
3387                for i in dlg.GetSelections(): 
3388                    copyList.append(histList[i])
3389        finally:
3390            dlg.Destroy()       
3391        for item in copyList:
3392            Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
3393            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Substances'),
3394                copy.copy(data))
3395   
3396    def OnAddSubstance(event):
3397        dlg = wx.TextEntryDialog(None,'Enter a name for this substance','Substance Name Entry','New substance',
3398            style=wx.OK)
3399        if dlg.ShowModal() == wx.ID_OK:
3400            Name = dlg.GetValue()
3401            data['Substances'][Name] = {'Elements':{},'Volume':1.0,'Density':1.0,
3402                'Scatt density':0.0,'XAnom density':0.,'XAbsorption':0.}
3403        dlg.Destroy()
3404        AddElement(Name)
3405        UpdateSubstanceGrid(G2frame,data)
3406       
3407    def OnDeleteSubstance(event):
3408        TextList = []
3409        for name in data['Substances']:
3410            if name != 'vacuum':
3411                TextList += [name,]
3412        if not TextList:
3413            return
3414        dlg = wx.SingleChoiceDialog(G2frame, 'Which substance?', 'Select substance to delete', TextList, wx.CHOICEDLG_STYLE)
3415        try:
3416            if dlg.ShowModal() == wx.ID_OK:
3417                name = TextList[dlg.GetSelection()]
3418            else:
3419                return
3420        finally:
3421            dlg.Destroy()
3422        del(data['Substances'][name])
3423        UpdateSubstanceGrid(G2frame,data)       
3424               
3425    def OnAddElement(event):       
3426        TextList = []
3427        for name in data['Substances']:
3428            if name != 'vacuum':
3429                TextList += [name,]
3430        if not TextList:
3431            return
3432        dlg = wx.SingleChoiceDialog(G2frame, 'Which substance?', 'Select substance', TextList, wx.CHOICEDLG_STYLE)
3433        try:
3434            if dlg.ShowModal() == wx.ID_OK:
3435                name = TextList[dlg.GetSelection()]
3436            else:
3437                return
3438        finally:
3439            dlg.Destroy()
3440        AddElement(name)
3441        UpdateSubstanceGrid(G2frame,data)
3442       
3443    def AddElement(name):
3444        ElList = data['Substances'][name]['Elements'].keys()
3445        dlg = G2elemGUI.PickElements(G2frame,ElList)
3446        if dlg.ShowModal() == wx.ID_OK:
3447            for El in dlg.Elem:
3448                El = El.strip().capitalize()
3449                Info = G2elem.GetAtomInfo(El)
3450                Info.update({'Num':1})
3451                data['Substances'][name]['Elements'][El] = Info
3452                data['Substances'][name]['Volume'] = G2mth.El2EstVol(data['Substances'][name]['Elements'])
3453                data['Substances'][name]['Density'] = \
3454                    G2mth.Vol2Den(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])
3455                data['Substances'][name]['Scatt density'] = \
3456                    G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])[0]
3457                contrst,absorb = G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'],wave)         
3458                data['Substances'][name]['XAnom density'] = contrst
3459                data['Substances'][name]['XAbsorption'] = absorb
3460        dlg.Destroy()
3461       
3462    def OnDeleteElement(event):
3463        TextList = []
3464        for name in data['Substances']:
3465            if name != 'vacuum':
3466                TextList += [name,]
3467        if not TextList:
3468            return
3469        dlg = wx.SingleChoiceDialog(G2frame, 'Which substance?', 'Select substance', TextList, wx.CHOICEDLG_STYLE)
3470        try:
3471            if dlg.ShowModal() == wx.ID_OK:
3472                name = TextList[dlg.GetSelection()]
3473            else:
3474                return
3475        finally:
3476            dlg.Destroy()
3477        ElList = data['Substances'][name]['Elements'].keys()
3478        if len(ElList):
3479            DE = G2elemGUI.DeleteElement(G2frame,ElList)
3480            if DE.ShowModal() == wx.ID_OK:
3481                El = DE.GetDeleteElement().strip().upper()
3482                del(data['Substances'][name]['Elements'][El])
3483                data['Substances'][name]['Volume'] = G2mth.El2EstVol(data['Substances'][name]['Elements'])
3484                data['Substances'][name]['Density'] = \
3485                    G2mth.Vol2Den(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])
3486                data['Substances'][name]['Scatt density'] = \
3487                    G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])[0]
3488                contrst,absorb = G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'],wave)         
3489                data['Substances'][name]['XAnom density'] = contrst
3490                data['Substances'][name]['XAbsorption'] = absorb
3491        UpdateSubstanceGrid(G2frame,data)
3492               
3493    def SubstSizer():
3494       
3495        def OnValueChange(event):
3496            Obj = event.GetEventObject()
3497            if len(Indx[Obj.GetId()]) == 3:
3498                name,El,keyId = Indx[Obj.GetId()]
3499                try:
3500                    value = max(0,float(Obj.GetValue()))
3501                except ValueError:
3502                    value = 0
3503                    Obj.SetValue('%.2f'%(value))
3504                data['Substances'][name]['Elements'][El][keyId] = value
3505                data['Substances'][name]['Volume'] = G2mth.El2EstVol(data['Substances'][name]['Elements'])
3506                data['Substances'][name]['Density'] = \
3507                    G2mth.Vol2Den(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])
3508            else:
3509                name,keyId = Indx[Obj.GetId()]
3510                try:
3511                    value = max(0,float(Obj.GetValue()))
3512                except ValueError:
3513                    value = 1.0
3514                data['Substances'][name][keyId] = value
3515                if keyId in 'Volume':
3516                    data['Substances'][name]['Density'] = \
3517                        G2mth.Vol2Den(data['Substances'][name]['Elements'],value)
3518                elif keyId in 'Density':
3519                    data['Substances'][name]['Volume'] = \
3520                        G2mth.Den2Vol(data['Substances'][name]['Elements'],value)
3521            data['Substances'][name]['Scatt density'] = \
3522                G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])[0]
3523            contrst,absorb = G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'],wave)         
3524            data['Substances'][name]['XAnom density'] = contrst
3525            data['Substances'][name]['XAbsorption'] = absorb
3526            wx.CallAfter(UpdateSubstanceGrid,G2frame,data)
3527       
3528        Indx = {}
3529        substSizer = wx.BoxSizer(wx.VERTICAL)
3530        substSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Substance list: wavelength: %.5fA'%(wave)),
3531            0,WACV)
3532        for name in data['Substances']:
3533            G2G.HorizontalLine(substSizer,G2frame.dataDisplay)   
3534            substSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Data for '+name+':'),
3535                0,WACV)
3536            if name == 'vacuum':
3537                substSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label='        Not applicable'),
3538                    0,WACV)
3539            else:   
3540                elSizer = wx.FlexGridSizer(0,6,5,5)
3541                Substance = data['Substances'][name]
3542                Elems = Substance['Elements']
3543                for El in Elems:    #do elements as pull downs for isotopes for neutrons
3544                    elSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' '+El+': '),
3545                        0,WACV)
3546                    num = wx.TextCtrl(G2frame.dataDisplay,value='%.2f'%(Elems[El]['Num']),style=wx.TE_PROCESS_ENTER)
3547                    Indx[num.GetId()] = [name,El,'Num']
3548                    num.Bind(wx.EVT_TEXT_ENTER,OnValueChange)       
3549                    num.Bind(wx.EVT_KILL_FOCUS,OnValueChange)
3550                    elSizer.Add(num,0,WACV)
3551                substSizer.Add(elSizer,0)
3552                vdsSizer = wx.FlexGridSizer(0,4,5,5)
3553                vdsSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Volume: '),
3554                    0,WACV)
3555                vol = wx.TextCtrl(G2frame.dataDisplay,value='%.3f'%(Substance['Volume']),style=wx.TE_PROCESS_ENTER)
3556                Indx[vol.GetId()] = [name,'Volume']
3557                vol.Bind(wx.EVT_TEXT_ENTER,OnValueChange)       
3558                vol.Bind(wx.EVT_KILL_FOCUS,OnValueChange)
3559                vdsSizer.Add(vol,0,WACV)               
3560                vdsSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Density: '),
3561                    0,WACV)
3562                den = wx.TextCtrl(G2frame.dataDisplay,value='%.3f'%(Substance['Density']),style=wx.TE_PROCESS_ENTER)
3563                Indx[den.GetId()] = [name,'Density']
3564                den.Bind(wx.EVT_TEXT_ENTER,OnValueChange)       
3565                den.Bind(wx.EVT_KILL_FOCUS,OnValueChange)
3566                vdsSizer.Add(den,0,WACV)
3567                substSizer.Add(vdsSizer,0)
3568                substSizer.Add(wx.StaticText(G2frame.dataDisplay,
3569                    label=' Scattering density  : %.2f *10%scm%s'%(Substance['Scatt density'],Pwr10,Pwrm2)),
3570                    0,WACV)               
3571                substSizer.Add(wx.StaticText(G2frame.dataDisplay,       #allow neutrons here into NAnom density & NAbsorption
3572                    label=' Anomalous density : %.2f *10%scm%s'%(Substance['XAnom density'],Pwr10,Pwrm2)),
3573                    0,WACV)               
3574                substSizer.Add(wx.StaticText(G2frame.dataDisplay,
3575                    label=' X-ray absorption   : %.2f cm%s'%(Substance['XAbsorption'],Pwrm1)),
3576                    0,WACV)               
3577        return substSizer
3578           
3579    Inst = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Instrument Parameters'))[0]
3580    wave = G2mth.getWave(Inst)
3581    if G2frame.dataDisplay:
3582        G2frame.dataFrame.DestroyChildren()  # is this a ScrolledWindow? If so, bad!
3583    G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.SubstanceMenu)
3584    if not G2frame.dataFrame.GetStatusBar():
3585        Status = G2frame.dataFrame.CreateStatusBar()
3586    G2frame.dataDisplay = wxscroll.ScrolledPanel(G2frame.dataFrame)
3587    G2frame.dataFrame.SetLabel('Substances')
3588    G2frame.dataFrame.Bind(wx.EVT_MENU, OnLoadSubstance, id=G2gd.wxID_LOADSUBSTANCE)   
3589    G2frame.dataFrame.Bind(wx.EVT_MENU, OnAddSubstance, id=G2gd.wxID_ADDSUBSTANCE)
3590    G2frame.dataFrame.Bind(wx.EVT_MENU, OnCopySubstance, id=G2gd.wxID_COPYSUBSTANCE)
3591    G2frame.dataFrame.Bind(wx.EVT_MENU, OnDeleteSubstance, id=G2gd.wxID_DELETESUBSTANCE)   
3592    G2frame.dataFrame.Bind(wx.EVT_MENU, OnAddElement, id=G2gd.wxID_ELEMENTADD)
3593    G2frame.dataFrame.Bind(wx.EVT_MENU, OnDeleteElement, id=G2gd.wxID_ELEMENTDELETE)
3594    mainSizer = wx.BoxSizer(wx.VERTICAL)
3595    mainSizer.Add(SubstSizer(),0)
3596
3597    mainSizer.Layout()   
3598    G2frame.dataDisplay.SetSizer(mainSizer)
3599    G2frame.dataDisplay.SetAutoLayout(1)
3600    G2frame.dataDisplay.SetupScrolling()
3601    Size = mainSizer.Fit(G2frame.dataFrame)
3602    Size[0] += 25
3603    G2frame.dataDisplay.SetSize(Size)
3604    G2frame.dataFrame.setSizePosLeft(Size)   
3605       
3606################################################################################
3607#####  SASD Models
3608################################################################################           
3609       
3610def UpdateModelsGrid(G2frame,data):
3611    '''respond to selection of SASD Models data tree item.
3612    '''
3613    #patches
3614    if 'Current' not in data:
3615        data['Current'] = 'Size dist.'
3616    if 'logBins' not in data['Size']:
3617        data['Size']['logBins'] = True
3618    if 'MinMaxDiam' in data['Size']:
3619        data['Size']['MinDiam'] = 50.
3620        data['Size']['MaxDiam'] = 10000.
3621        del data['Size']['MinMaxDiam']
3622    if isinstance(data['Size']['MaxEnt']['Sky'],float):
3623        data['Size']['MaxEnt']['Sky'] = -3
3624    if 'Power' not in data['Size']['IPG']:
3625        data['Size']['IPG']['Power'] = -1
3626    if 'Matrix' not in data['Particle']:
3627        data['Particle']['Matrix'] = {'Name':'vacuum','VolFrac':[0.0,False]}
3628    if 'BackFile' not in data:
3629        data['BackFile'] = ''
3630    #end patches
3631   
3632    def RefreshPlots(newPlot=False):
3633        PlotText = G2frame.G2plotNB.nb.GetPageText(G2frame.G2plotNB.nb.GetSelection())
3634        if 'Powder' in PlotText:
3635            G2plt.PlotPatterns(G2frame,plotType='SASD',newPlot=newPlot)
3636        elif 'Size' in PlotText:
3637            G2plt.PlotSASDSizeDist(G2frame)
3638               
3639    def OnAddModel(event):
3640        if data['Current'] == 'Particle fit':
3641            material = 'vacuum'
3642            if len(data['Particle']['Levels']):
3643                material = data['Particle']['Levels'][-1]['Controls']['Material']
3644            data['Particle']['Levels'].append({
3645                'Controls':{'FormFact':'Sphere','DistType':'LogNormal','Material':material,
3646                    'FFargs':{},'SFargs':{},'NumPoints':50,'Cutoff':0.01,'Contrast':0.0,
3647                    'SlitSmear':[0.0,False],'StrFact':'Dilute'},    #last 2 not used - future?
3648                'LogNormal':{'Volume':[0.05,False],'Mean':[1000.,False],'StdDev':[0.5,False],'MinSize':[10.,False],},
3649                'Gaussian':{'Volume':[0.05,False],'Mean':[1000.,False],'StdDev':[300.,False],},
3650                'LSW':{'Volume':[0.05,False],'Mean':[1000.0,False],},
3651                'Schulz-Zimm':{'Volume':[0.05,False],'Mean':[1000.,False],'StdDev':[300.,False],},
3652                'Unified':{'G':[1.e3,False],'Rg':[100,False],'B':[1.e-5,False],'P':[4,False],'Cutoff':[1e-5,False],},
3653                'Porod':{'B':[1.e-4,False],'P':[4,False],'Cutoff':[1e-5,False],},
3654                'Monodisperse':{'Volume':[0.05,False],'Radius':[100,False],},   #OK for spheres
3655                'Bragg':{'PkInt':[100,False],'PkPos':[0.2,False],
3656                    'PkSig':[10,False],'PkGam':[10,False],},        #reasonable 31A peak
3657                })
3658            G2sasd.ModelFxn(Profile,ProfDict,Limits,Sample,data)
3659            RefreshPlots(True)
3660                   
3661        wx.CallAfter(UpdateModelsGrid,G2frame,data)
3662       
3663    def OnCopyModel(event):
3664        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
3665        histList = GetHistsLikeSelected(G2frame)
3666        if not histList:
3667            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
3668            return
3669        copyList = []
3670        dlg = G2G.G2MultiChoiceDialog(
3671            G2frame.dataFrame, 
3672            'Copy models from\n'+hst[5:]+' to...',
3673            'Copy models', histList)
3674        try:
3675            if dlg.ShowModal() == wx.ID_OK:
3676                for i in dlg.GetSelections(): 
3677                    copyList.append(histList[i])
3678        finally:
3679            dlg.Destroy()       
3680        for item in copyList:
3681            Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
3682            newdata = copy.deepcopy(data)
3683            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Models'),newdata)
3684            if newdata['BackFile']:
3685                Profile = G2frame.PatternTree.GetItemPyData(Id)[1]
3686                BackId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,newdata['BackFile'])
3687                BackSample = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,BackId, 'Sample Parameters'))
3688                Profile[5] = BackSample['Scale'][0]*G2frame.PatternTree.GetItemPyData(BackId)[1][1]
3689        RefreshPlots(True)
3690               
3691    def OnCopyFlags(event):
3692        thisModel = copy.deepcopy(data)
3693        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
3694        histList = GetHistsLikeSelected(G2frame)
3695        if not histList:
3696            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
3697            return
3698        dlg = G2G.G2MultiChoiceDialog(
3699            G2frame.dataFrame, 
3700            'Copy sample ref. flags from\n'+str(hst[5:])+' to...',
3701            'Copy sample flags', histList)
3702        distChoice = ['LogNormal','Gaussian','LSW','Schulz-Zimm','Bragg','Unified',
3703            'Porod','Monodisperse',]
3704        parmOrder = ['Volume','Radius','Mean','StdDev','G','Rg','B','P',
3705            'Cutoff','PkInt','PkPos','PkSig','PkGam','VolFr','Dist',]
3706        try:
3707            if dlg.ShowModal() == wx.ID_OK:
3708                result = dlg.GetSelections()
3709                for i in result: 
3710                    item = histList[i]
3711                    Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
3712                    newModel = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Models'))
3713                    newModel['Back'][1] = copy.copy(thisModel['Back'][1])
3714                    for ilev,level in enumerate(newModel['Particle']['Levels']):
3715                        for form in level:
3716                            if form in distChoice:
3717                                thisForm = thisModel['Particle']['Levels'][ilev][form]                               
3718                                for item in parmOrder:
3719                                    if item in thisForm:
3720                                       level[form][item][1] = copy.copy(thisForm[item][1])
3721                            elif form == 'Controls':
3722                                thisForm = thisModel['Particle']['Levels'][ilev][form]['SFargs']
3723                                for item in parmOrder:
3724                                    if item in thisForm:
3725                                        level[form]['SFargs'][item][1] = copy.copy(thisForm[item][1])
3726        finally:
3727            dlg.Destroy()
3728               
3729    def OnFitModelAll(event):
3730        choices = G2gd.GetPatternTreeDataNames(G2frame,['SASD',])
3731        sel = []
3732        dlg = G2G.G2MultiChoiceDialog(G2frame.dataFrame, 'Sequential SASD refinement',
3733             'Select dataset to include',choices)
3734        dlg.SetSelections(sel)
3735        names = []
3736        if dlg.ShowModal() == wx.ID_OK:
3737            for sel in dlg.GetSelections():
3738                names.append(choices[sel])
3739        dlg.Destroy()
3740        SeqResult = {'histNames':names}
3741        Reverse = False
3742        CopyForward = False
3743        choice = ['Reverse sequence','Copy from prev.']
3744        dlg = wx.MultiChoiceDialog(G2frame.dataFrame,'Sequential controls','Select controls',choice)
3745        if dlg.ShowModal() == wx.ID_OK:
3746            for sel in dlg.GetSelections():
3747                if sel:
3748                    CopyForward = True
3749                else:
3750                    Reverse = True
3751        dlg.Destroy()
3752        dlg = wx.ProgressDialog('SASD Sequential fit','Data set name = '+names[0],len(names), 
3753            style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE|wx.PD_REMAINING_TIME|wx.PD_CAN_ABORT)
3754        wx.BeginBusyCursor()
3755        if Reverse:
3756            names.reverse()
3757        try:
3758            for i,name in enumerate(names):
3759                print ' Sequential fit for ',name
3760                GoOn = dlg.Update(i,newmsg='Data set name = '+name)[0]
3761                if not GoOn:
3762                    break
3763                Id =  G2gd.GetPatternTreeItemId(G2frame,G2frame.root,name)
3764                if i and CopyForward:
3765                    G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Models'),JModel)
3766                IProfDict,IProfile = G2frame.PatternTree.GetItemPyData(Id)[:2]
3767                IModel = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Models'))
3768                ISample = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Sample Parameters'))
3769                ILimits = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Limits'))
3770                IfOK,result,varyList,sig,Rvals,covMatrix,parmDict,Msg = G2sasd.ModelFit(IProfile,IProfDict,ILimits,ISample,IModel)
3771                JModel = copy.deepcopy(IModel)
3772                if not IfOK:
3773                    G2frame.ErrorDialog('Failed sequential refinement for data '+name,
3774                        ' Msg: '+Msg+'\nYou need to rethink your selection of parameters\n'+    \
3775                        ' Model restored to previous version for'+name)
3776                    SeqResult['histNames'] = names[:i]
3777                    dlg.Destroy()
3778                    break
3779                else:
3780                    G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Models'),copy.deepcopy(IModel))
3781               
3782                G2sasd.ModelFxn(IProfile,IProfDict,ILimits,ISample,IModel)
3783                SeqResult[name] = {'variables':result[0],'varyList':varyList,'sig':sig,'Rvals':Rvals,
3784                    'covMatrix':covMatrix,'title':name,'parmDict':parmDict}
3785            else:
3786                dlg.Destroy()
3787                print ' ***** Small angle sequential refinement successful *****'
3788        finally:
3789            wx.EndBusyCursor()   
3790        Id =  G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Sequential results')
3791        if Id:
3792            G2frame.PatternTree.SetItemPyData(Id,SeqResult)
3793        else:
3794            Id = G2frame.PatternTree.AppendItem(parent=G2frame.root,text='Sequential results')
3795            G2frame.PatternTree.SetItemPyData(Id,SeqResult)
3796        G2frame.PatternTree.SelectItem(Id)
3797       
3798    def OnFitModel(event):
3799        if data['Current'] == 'Size dist.':
3800            if not any(Sample['Contrast']):
3801                G2frame.ErrorDialog('No contrast; your sample is a vacuum!',
3802                    'You need to define a scattering substance!\n'+    \
3803                    ' Do Substances and then Sample parameters')
3804                return
3805            G2sasd.SizeDistribution(Profile,ProfDict,Limits,Sample,data)
3806            G2plt.PlotSASDSizeDist(G2frame)
3807            RefreshPlots(True)
3808           
3809        elif data['Current'] == 'Particle fit':
3810            SaveState()
3811            Results = G2sasd.ModelFit(Profile,ProfDict,Limits,Sample,data)
3812            if not Results[0]:
3813                    G2frame.ErrorDialog('Failed refinement',
3814                        ' Msg: '+Results[-1]+'\nYou need to rethink your selection of parameters\n'+    \
3815                        ' Model restored to previous version')
3816            G2sasd.ModelFxn(Profile,ProfDict,Limits,Sample,data)
3817            RefreshPlots(True)
3818            wx.CallAfter(UpdateModelsGrid,G2frame,data)
3819           
3820    def OnUnDo(event):
3821        DoUnDo()
3822        data = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,
3823            G2frame.PatternId,'Models'))
3824        G2frame.dataFrame.SasdUndo.Enable(False)
3825        UpdateModelsGrid(G2frame,data)
3826        G2sasd.ModelFxn(Profile,ProfDict,Limits,Sample,data)
3827        RefreshPlots(True)
3828
3829    def DoUnDo():
3830        print 'Undo last refinement'
3831        file = open(G2frame.undosasd,'rb')
3832        PatternId = G2frame.PatternId
3833        G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Models'),cPickle.load(file))
3834        print ' Models recovered'
3835        file.close()
3836       
3837    def SaveState():
3838        G2frame.undosasd = os.path.join(G2frame.dirname,'GSASIIsasd.save')
3839        file = open(G2frame.undosasd,'wb')
3840        PatternId = G2frame.PatternId
3841        for item in ['Models']:
3842            cPickle.dump(G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId,item)),file,1)
3843        file.close()
3844        G2frame.dataFrame.SasdUndo.Enable(True)
3845       
3846    def OnSelectFit(event):
3847        data['Current'] = fitSel.GetValue()
3848        wx.CallAfter(UpdateModelsGrid,G2frame,data)
3849       
3850    def OnCheckBox(event):
3851        Obj = event.GetEventObject()
3852        item,ind = Indx[Obj.GetId()]
3853        item[ind] = Obj.GetValue()
3854       
3855    def OnIntVal(event):
3856        Obj = event.GetEventObject()
3857        item,ind,minVal = Indx[Obj.GetId()]
3858        try:
3859            value = int(Obj.GetValue())
3860            if value <= minVal:
3861                raise ValueError
3862        except ValueError:
3863            value = item[ind]
3864        Obj.SetValue(str(value))
3865        item[ind] = value
3866
3867    def SizeSizer():
3868       
3869        def OnShape(event):
3870            data['Size']['Shape'][0] = partsh.GetValue()
3871            wx.CallAfter(UpdateModelsGrid,G2frame,data)
3872           
3873        def OnMethod(event):
3874            data['Size']['Method'] = method.GetValue()
3875            wx.CallAfter(UpdateModelsGrid,G2frame,data)
3876           
3877        def OnPartVal(event):
3878            try:
3879                val = max(0.0,float(partprm.GetValue()))
3880            except ValueError:
3881                val = 1
3882            data['Size']['Shape'][1] = val
3883            partprm.SetValue('%.3f'%(val))
3884           
3885        sizeSizer = wx.BoxSizer(wx.VERTICAL)
3886        sizeSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Size distribution parameters: '),0,WACV)
3887        binSizer = wx.FlexGridSizer(0,7,5,5)
3888        binSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' No. size bins: '),0,WACV)
3889        bins = ['50','100','150','200']
3890        nbins = wx.ComboBox(G2frame.dataDisplay,value=str(data['Size']['Nbins']),choices=bins,
3891            style=wx.CB_READONLY|wx.CB_DROPDOWN)
3892        Indx[nbins.GetId()] = [data['Size'],'Nbins',0]
3893        nbins.Bind(wx.EVT_COMBOBOX,OnIntVal)       
3894        binSizer.Add(nbins,0,WACV)
3895        binSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Min diam.: '),0,WACV)
3896        minDias = ['10','25','50','100','150','200']
3897        mindiam = wx.ComboBox(G2frame.dataDisplay,value=str(data['Size']['MinDiam']),choices=minDias,
3898            style=wx.CB_DROPDOWN)
3899        mindiam.Bind(wx.EVT_LEAVE_WINDOW,OnIntVal)
3900        mindiam.Bind(wx.EVT_TEXT_ENTER,OnIntVal)       
3901        mindiam.Bind(wx.EVT_KILL_FOCUS,OnIntVal)
3902        Indx[mindiam.GetId()] = [data['Size'],'MinDiam',0]
3903        binSizer.Add(mindiam,0,WACV)
3904        binSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Max diam.: '),0,WACV)
3905        maxDias = [str(1000*(i+1)) for i in range(10)]
3906        maxdiam = wx.ComboBox(G2frame.dataDisplay,value=str(data['Size']['MaxDiam']),choices=maxDias,
3907            style=wx.CB_DROPDOWN)
3908        maxdiam.Bind(wx.EVT_LEAVE_WINDOW,OnIntVal)
3909        maxdiam.Bind(wx.EVT_TEXT_ENTER,OnIntVal)       
3910        maxdiam.Bind(wx.EVT_KILL_FOCUS,OnIntVal)
3911        Indx[maxdiam.GetId()] = [data['Size'],'MaxDiam',0]
3912        binSizer.Add(maxdiam,0,WACV)
3913        logbins = wx.CheckBox(G2frame.dataDisplay,label='Log bins?')
3914        Indx[logbins.GetId()] = [data['Size'],'logBins']
3915        logbins.SetValue(data['Size']['logBins'])
3916        logbins.Bind(wx.EVT_CHECKBOX, OnCheckBox)
3917        binSizer.Add(logbins,0,WACV)
3918        sizeSizer.Add(binSizer,0)
3919        sizeSizer.Add((5,5),0)
3920        partSizer = wx.BoxSizer(wx.HORIZONTAL)
3921        partSizer.Add(wx.StaticText(G2frame.dataDisplay,label='Particle description: '),0,WACV)
3922        shapes = {'Spheroid':' Aspect ratio: ','Cylinder':' Diameter ','Cylinder AR':' Aspect ratio: ',
3923            'Unified sphere':'','Unified rod':' Diameter: ','Unified rod AR':' Aspect ratio: ',
3924            'Unified disk':' Thickness: '}
3925        partsh = wx.ComboBox(G2frame.dataDisplay,value=str(data['Size']['Shape'][0]),choices=shapes.keys(),
3926            style=wx.CB_READONLY|wx.CB_DROPDOWN)
3927        partsh.Bind(wx.EVT_COMBOBOX,OnShape)       
3928        partSizer.Add(partsh,0,WACV)
3929        if data['Size']['Shape'][0] not in ['Unified sphere',]:
3930            partSizer.Add(wx.StaticText(G2frame.dataDisplay,label=shapes[data['Size']['Shape'][0]]),0,WACV)
3931            partprm = wx.TextCtrl(G2frame.dataDisplay,value='%.3f'%(data['Size']['Shape'][1]),
3932                style=wx.TE_PROCESS_ENTER)
3933            partprm.Bind(wx.EVT_TEXT_ENTER,OnPartVal)       
3934            partprm.Bind(wx.EVT_KILL_FOCUS,OnPartVal)
3935            partSizer.Add(partprm,0,WACV)
3936        sizeSizer.Add(partSizer,0)
3937        sizeSizer.Add((5,5),0)
3938        fitSizer = wx.BoxSizer(wx.HORIZONTAL)
3939        methods = ['MaxEnt','IPG',]
3940        fitSizer.Add(wx.StaticText(G2frame.dataDisplay,label='Fitting method: '),0,WACV)
3941        method = wx.ComboBox(G2frame.dataDisplay,value=data['Size']['Method'],choices=methods,
3942            style=wx.CB_READONLY|wx.CB_DROPDOWN)
3943        method.Bind(wx.EVT_COMBOBOX,OnMethod)
3944        fitSizer.Add(method,0,WACV)
3945        iters = ['10','25','50','100','150','200']       
3946        fitSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' No. iterations: '),0,WACV)
3947        Method = data['Size']['Method']
3948        iter = wx.ComboBox(G2frame.dataDisplay,value=str(data['Size'][Method]['Niter']),choices=iters,
3949            style=wx.CB_READONLY|wx.CB_DROPDOWN)
3950        Indx[iter.GetId()] = [data['Size'][Method],'Niter',0]
3951        iter.Bind(wx.EVT_COMBOBOX,OnIntVal)
3952        fitSizer.Add(iter,0,WACV)
3953        if 'MaxEnt' in data['Size']['Method']:
3954            fitSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Log floor factor: '),0,WACV)
3955            floors = [str(-i) for i in range(9)]
3956            floor = wx.ComboBox(G2frame.dataDisplay,value=str(data['Size']['MaxEnt']['Sky']),choices=floors,
3957                style=wx.CB_READONLY|wx.CB_DROPDOWN)
3958            Indx[floor.GetId()] = [data['Size']['MaxEnt'],'Sky',-10]
3959            floor.Bind(wx.EVT_COMBOBOX,OnIntVal)
3960            fitSizer.Add(floor,0,WACV)
3961        elif 'IPG' in data['Size']['Method']:
3962            fitSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Q power weight (-1 for sigma): '),0,WACV)
3963            choices = ['-1','0','1','2','3','4']
3964            power = wx.ComboBox(G2frame.dataDisplay,value=str(data['Size']['IPG']['Power']),choices=choices,
3965                style=wx.CB_READONLY|wx.CB_DROPDOWN)
3966            Indx[power.GetId()] = [data['Size']['IPG'],'Power',-2]
3967            power.Bind(wx.EVT_COMBOBOX,OnIntVal)
3968            fitSizer.Add(power,0,WACV)
3969        sizeSizer.Add(fitSizer,0)
3970
3971        return sizeSizer
3972       
3973    def PartSizer():
3974       
3975        FormFactors = {'Sphere':{},'Spheroid':{'Aspect ratio':[1.0,False]},
3976            'Cylinder':{'Length':[100.,False]},'Cylinder diam':{'Diameter':[100.,False]},
3977            'Cylinder AR':{'Aspect ratio':[1.0,False]},'Unified sphere':{},
3978            'Unified rod':{'Length':[100.,False]},'Unified rod AR':{'Aspect ratio':[1.0,False]},
3979            'Unified disk':{'Thickness':[100.,False]},
3980            'Unified tube':{'Length':[100.,False],'Thickness':[10.,False]},}
3981               
3982        StructureFactors = {'Dilute':{},'Hard sphere':{'VolFr':[0.1,False],'Dist':[100.,False]},
3983            'Sticky hard sphere':{'VolFr':[0.1,False],'Dist':[100.,False],'epis':[0.05,False],'Sticky':[0.2,False]},
3984            'Square well':{'VolFr':[0.1,False],'Dist':[100.,False],'Depth':[0.1,False],'Width':[1.,False]},
3985            'InterPrecipitate':{'VolFr':[0.1,False],'Dist':[100.,False]},}
3986               
3987        ffDistChoices =  ['Sphere','Spheroid','Cylinder','Cylinder diam',
3988            'Cylinder AR','Unified sphere','Unified rod','Unified rod AR',
3989            'Unified disk','Unified tube',]
3990               
3991        ffMonoChoices = ['Sphere','Spheroid','Cylinder','Cylinder AR',]
3992       
3993        sfChoices = ['Dilute','Hard sphere','Sticky hard sphere','Square well','InterPrecipitate',]
3994           
3995        slMult = 1000.
3996                 
3997        def OnValue(event):
3998            Obj = event.GetEventObject()
3999            item,key,sldrObj = Indx[Obj.GetId()]
4000            try:
4001                value = float(Obj.GetValue())
4002                if value <= 0.:
4003                    raise ValueError
4004            except ValueError:
4005                value = item[key][0]
4006            item[key][0] = value
4007            Obj.SetValue('%.3g'%(value))
4008            if key in ['P','epis','Sticky','Depth','Width','VolFr','Dist']:
4009                sldrObj.SetValue(slMult*value)
4010            else:
4011                logv = np.log10(value)
4012                valMinMax = [logv-1,logv+1]
4013                sldrObj.SetRange(slMult*valMinMax[0],slMult*valMinMax[1])
4014                sldrObj.SetValue(slMult*logv)
4015            G2sasd.ModelFxn(Profile,ProfDict,Limits,Sample,data)
4016            RefreshPlots()
4017           
4018        def OnSelect(event):
4019            Obj = event.GetEventObject()
4020            item,key = Indx[Obj.GetId()]
4021            item[key] = Obj.GetValue()
4022            if 'Refine' not in Obj.GetLabel():
4023                if 'FormFact' in key :
4024                    item['FFargs'] = FormFactors[Obj.GetValue()]
4025                elif 'StrFact' in key:
4026                    item['SFargs'] = StructureFactors[Obj.GetValue()]
4027                wx.CallAfter(UpdateModelsGrid,G2frame,data)
4028                G2sasd.ModelFxn(Profile,ProfDict,Limits,Sample,data)
4029                RefreshPlots()
4030               
4031        def OnDelLevel(event):
4032            Obj = event.GetEventObject()
4033            item = Indx[Obj.GetId()]
4034            del data['Particle']['Levels'][item]
4035            wx.CallAfter(UpdateModelsGrid,G2frame,data)
4036            G2sasd.ModelFxn(Profile,ProfDict,Limits,Sample,data)
4037            RefreshPlots()
4038           
4039        def OnParmSlider(event):
4040            Obj = event.GetEventObject()
4041            item,key,pvObj = Indx[Obj.GetId()]
4042            slide = Obj.GetValue()
4043            if key in ['P','epis','Sticky','Depth','Width','VolFr','Dist']:
4044                value = float(slide/slMult)
4045            else:
4046                value = 10.**float(slide/slMult)
4047            item[key][0] = value
4048            pvObj.SetValue('%.3g'%(item[key][0]))
4049            G2sasd.ModelFxn(Profile,ProfDict,Limits,Sample,data)
4050            RefreshPlots()
4051           
4052        def SizeSizer():
4053            sizeSizer = wx.FlexGridSizer(0,4,5,5)
4054            sizeSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Distribution: '),0,WACV)
4055            Distchoice = ['LogNormal','Gaussian','LSW','Schulz-Zimm','Bragg','Unified','Porod','Monodisperse',]
4056            distChoice = wx.ComboBox(G2frame.dataDisplay,value=level['Controls']['DistType'],choices=Distchoice,
4057                style=wx.CB_READONLY|wx.CB_DROPDOWN)
4058            Indx[distChoice.GetId()] = [level['Controls'],'DistType']
4059            distChoice.Bind(wx.EVT_COMBOBOX,OnSelect)
4060            sizeSizer.Add(distChoice,0,WACV)    #put structure factor choices here
4061            if level['Controls']['DistType'] not in ['Bragg','Unified','Porod',]:
4062                sizeSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Form Factor: '),0,WACV)
4063                if 'Mono' in level['Controls']['DistType']:
4064                    ffChoice = wx.ComboBox(G2frame.dataDisplay,value=level['Controls']['FormFact'],choices=ffMonoChoices,
4065                        style=wx.CB_READONLY|wx.CB_DROPDOWN)
4066                else:
4067                    ffChoice = wx.ComboBox(G2frame.dataDisplay,value=level['Controls']['FormFact'],choices=ffDistChoices,
4068                        style=wx.CB_READONLY|wx.CB_DROPDOWN)
4069                Indx[ffChoice.GetId()] = [level['Controls'],'FormFact']
4070                ffChoice.Bind(wx.EVT_COMBOBOX,OnSelect)
4071                sizeSizer.Add(ffChoice,0,WACV)
4072               
4073                sizeSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Material: '),0,WACV)
4074                matSel = wx.ComboBox(G2frame.dataDisplay,value=level['Controls']['Material'],
4075                    choices=Substances['Substances'].keys(),style=wx.CB_READONLY|wx.CB_DROPDOWN)
4076                Indx[matSel.GetId()] = [level['Controls'],'Material']
4077                matSel.Bind(wx.EVT_COMBOBOX,OnSelect)       
4078                sizeSizer.Add(matSel,0,WACV) #do neutron test here?
4079                rho = Substances['Substances'][level['Controls']['Material']].get('XAnom density',0.0)
4080                level['Controls']['Contrast'] = contrast = (rho-rhoMat)**2                 
4081                sizeSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Resonant X-ray contrast: '),0,WACV)
4082                sizeSizer.Add(wx.StaticText(G2frame.dataDisplay,label=%.2f 10%scm%s'%(contrast,Pwr20,Pwrm4)),0,WACV)
4083                if 'Mono' not in level['Controls']['DistType']:
4084                    sizeSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Num. radii: '),0,WACV)
4085                    radii = ['25','50','75','100','200']
4086                    nRadii = wx.ComboBox(G2frame.dataDisplay,value=str(level['Controls']['NumPoints']),choices=radii,
4087                        style=wx.CB_READONLY|wx.CB_DROPDOWN)
4088                    Indx[nRadii.GetId()] = [level['Controls'],'NumPoints']
4089                    nRadii.Bind(wx.EVT_COMBOBOX,OnSelect)
4090                    sizeSizer.Add(nRadii,0,WACV)
4091                    sizeSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' R dist. cutoff: '),0,WACV)
4092                    rCutoff = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,level['Controls'],'Cutoff',
4093                        min=0.001,max=0.1,typeHint=float)
4094                    sizeSizer.Add(rCutoff,0,WACV)
4095            elif level['Controls']['DistType']  in ['Unified',]:
4096                Parms = level['Unified']
4097                Best = G2sasd.Bestimate(Parms['G'][0],Parms['Rg'][0],Parms['P'][0])
4098                sizeSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Estimated Dist B: %12.4g'%(Best)),0,WACV)
4099            return sizeSizer
4100           
4101        def ParmSizer():
4102            parmSizer = wx.FlexGridSizer(0,3,5,5)
4103            parmSizer.AddGrowableCol(2,1)
4104            parmSizer.SetFlexibleDirection(wx.HORIZONTAL)
4105            Parms = level[level['Controls']['DistType']]
4106            FFargs = level['Controls']['FFargs']
4107            SFargs = level['Controls'].get('SFargs',{})
4108            parmOrder = ['Volume','Radius','Mean','StdDev','MinSize','G','Rg','B','P','Cutoff',
4109                'PkInt','PkPos','PkSig','PkGam',]
4110            for parm in parmOrder:
4111                if parm in Parms:
4112                    if parm == 'MinSize':
4113                        parmSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Dist '+parm),0,wx.ALIGN_CENTER)
4114                    else:
4115                        parmVar = wx.CheckBox(G2frame.dataDisplay,label='Refine? Dist '+parm) 
4116                        parmVar.SetValue(Parms[parm][1])
4117                        parmVar.Bind(wx.EVT_CHECKBOX, OnSelect)
4118                        parmSizer.Add(parmVar,0,WACV)
4119                        Indx[parmVar.GetId()] = [Parms[parm],1]
4120                    parmValue = wx.TextCtrl(G2frame.dataDisplay,value='%.3g'%(Parms[parm][0]),
4121                        style=wx.TE_PROCESS_ENTER)
4122                    parmValue.Bind(wx.EVT_TEXT_ENTER,OnValue)       
4123                    parmValue