source: trunk/GSASIIpwdGUI.py @ 1743

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

fix to data selection issue
formatting error for histogram scale
change ':' to ';' for SASD parameter names

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