source: trunk/GSASIIpwdGUI.py @ 2147

Last change on this file since 2147 was 2147, checked in by vondreele, 6 years ago

handle TOF profile type=2 iparm files (e.g. for GEM)
implement multibank instprm files - add Save all profiles to Instrument parameters MenuBinding?
Do the Load profile to handle these - modifications to OnLoad?
add common transformation matrices to MergeDialog?
add bank no. to ReadPowderInstprm? call for matching it - in progress

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