source: trunk/GSASIIpwdGUI.py @ 1778

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

allow Refine texture menu item to appear; use DestroyChildren? to clear the Texture tab before filling
fix azimuth calculations after image integration
put Azimuth in Sample parms.
add 3 prints to debug option in G2mapvars
add Omega, Chi, Phi & Azimuth to sequential results table if they vary

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