source: trunk/GSASIIpwdGUI.py @ 1955

Last change on this file since 1955 was 1955, checked in by vondreele, 8 years ago

Add error message for TOF calibration if peak positions weren't fitted
fix a bug in SS structure factor calc.
put debug prints back in GetSSfxuinel; now only if debug=True

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