source: trunk/GSASIIpwdGUI.py @ 2186

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

fix Bravais lattice name issues in Unit Cells & fix problem of uneditable unit cell values after Show HKLs

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 234.6 KB
Line 
1# -*- coding: utf-8 -*-
2#GSASIIpwdGUI - powder data display routines
3########### SVN repository information ###################
4# $Date: 2016-03-31 14:50:12 +0000 (Thu, 31 Mar 2016) $
5# $Author: vondreele $
6# $Revision: 2186 $
7# $URL: trunk/GSASIIpwdGUI.py $
8# $Id: GSASIIpwdGUI.py 2186 2016-03-31 14:50:12Z 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: 2186 $")
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            if 'T' in histType:
104                parms += [['Absorption',u'Sample absorption (\xb5\xb7r/l): ',[10,4]],]
105            else:
106                parms += [['DisplaceX',u'Sample X displ. perp. to beam (\xb5m): ',[10,3]],
107                    ['DisplaceY',u'Sample Y displ. || to beam (\xb5m): ',[10,3]],
108                    ['Absorption',u'Sample absorption (\xb5\xb7r): ',[10,4]],]
109        elif dataType == 'Bragg-Brentano':
110            parms += [['Shift',u'Sample displacement(\xb5m): ',[10,4]],
111                ['Transparency',u'Sample transparency(1/\xb5eff, cm): ',[10,3]],
112                ['SurfRoughA','Surface roughness A: ',[10,4]],
113                ['SurfRoughB','Surface roughness B: ',[10,4]]]
114    elif 'SASD' in histName:
115        parms.append(['Thick','Sample thickness (mm)',[10,3]])
116        parms.append(['Trans','Transmission (meas)',[10,3]])
117        parms.append(['SlitLen',u'Slit length (Q,\xc5'+Pwrm1+')',[10,3]])
118    parms.append(['Omega','Goniometer omega:',[10,3]])
119    parms.append(['Chi','Goniometer chi:',[10,3]])
120    parms.append(['Phi','Goniometer phi:',[10,3]])
121    parms.append(['Azimuth','Detector azimuth:',[10,3]])
122    parms.append(['Time','Clock time (s):',[12,3]])
123    parms.append(['Temperature','Sample temperature (K): ',[10,3]])
124    parms.append(['Pressure','Sample pressure (MPa): ',[10,3]])
125    return parms
126
127def SetDefaultSASDModel():
128    'Fills in default items for the SASD Models dictionary'   
129    return {'Back':[0.0,False],'Size':{'MinDiam':50,'MaxDiam':10000,'Nbins':100,'logBins':True,'Method':'MaxEnt','Distribution':[],
130        'Shape':['Spheroid',1.0],'MaxEnt':{'Niter':100,'Precision':0.01,'Sky':-3},
131        'IPG':{'Niter':100,'Approach':0.8,'Power':-1},'Reg':{},},           
132        'Particle':{'Matrix':{'Name':'vacuum','VolFrac':[0.0,False]},'Levels':[],},
133        'Current':'Size dist.','BackFile':'',
134        }
135       
136def SetDefaultSubstances():
137    'Fills in default items for the SASD Substances dictionary'
138    return {'Substances':{'vacuum':{'Elements':{},'Volume':1.0,'Density':0.0,'Scatt density':0.0}}}
139
140def GetHistsLikeSelected(G2frame):
141    '''Get the histograms that match the current selected one:
142    The histogram prefix and data type (PXC etc.), the number of
143    wavelengths and the instrument geometry (Debye-Scherrer etc.)
144    must all match. The current histogram is not included in the list.
145
146    :param wx.Frame G2frame: pointer to main GSAS-II data tree
147    '''
148    histList = []
149    inst,inst2 = G2frame.PatternTree.GetItemPyData(
150        G2gd.GetPatternTreeItemId(
151            G2frame,G2frame.PatternId, 'Instrument Parameters')
152        )
153    hType = inst['Type'][0]
154    if 'Lam1' in inst:
155        hLam = 2
156    elif 'Lam' in inst:
157        hLam = 1
158    else:
159        hLam = 0
160    sample = G2frame.PatternTree.GetItemPyData(
161        G2gd.GetPatternTreeItemId(
162            G2frame,G2frame.PatternId, 'Sample Parameters')
163        )
164    hGeom = sample.get('Type')
165    hstName = G2frame.PatternTree.GetItemText(G2frame.PatternId)
166    hPrefix = hstName.split()[0]+' '
167    # cycle through tree looking for items that match the above
168    item, cookie = G2frame.PatternTree.GetFirstChild(G2frame.root)       
169    while item:
170        name = G2frame.PatternTree.GetItemText(item)
171        if name.startswith(hPrefix) and name != hstName:
172            cGeom,cType,cLam, = '?','?',-1
173            subitem, subcookie = G2frame.PatternTree.GetFirstChild(item)
174            while subitem:
175                subname = G2frame.PatternTree.GetItemText(subitem)
176                if subname == 'Sample Parameters':
177                    sample = G2frame.PatternTree.GetItemPyData(subitem)
178                    cGeom = sample.get('Type')
179                elif subname == 'Instrument Parameters':
180                    inst,inst2 = G2frame.PatternTree.GetItemPyData(subitem)
181                    cType = inst['Type'][0]
182                    if 'Lam1' in inst:
183                        cLam = 2
184                    elif 'Lam' in inst:
185                        cLam = 1
186                    else:
187                        cLam = 0
188                subitem, subcookie = G2frame.PatternTree.GetNextChild(item, subcookie)
189            if cLam == hLam and cType == hType and cGeom == hGeom:
190                if name not in histList: histList.append(name)
191        item, cookie = G2frame.PatternTree.GetNextChild(G2frame.root, cookie)
192    return histList
193
194def SetCopyNames(histName,dataType,addNames=[]):
195    '''Determine the items in the sample parameters that should be copied,
196    depending on the histogram type and the instrument type.
197    '''
198    copyNames = ['Scale',]
199    histType = 'HKLF'
200    if 'PWDR' in histName:
201        histType = 'PWDR'
202        if 'Debye' in dataType:
203            copyNames += ['DisplaceX','DisplaceY','Absorption']
204        else:       #Bragg-Brentano
205            copyNames += ['Shift','Transparency','SurfRoughA','SurfRoughB']
206    elif 'SASD' in histName:
207        histType = 'SASD'
208        copyNames += ['Materials','Thick',]
209    if len(addNames):
210        copyNames += addNames
211    return histType,copyNames
212   
213def CopyPlotCtrls(G2frame):
214    '''Global copy: Copy plot controls from current histogram to others.
215    '''
216    hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
217    histList = GetHistsLikeSelected(G2frame)
218    if not histList:
219        G2frame.ErrorDialog('No match','No other histograms match '+hst,G2frame.dataFrame)
220        return
221    sourceData = G2frame.PatternTree.GetItemPyData(G2frame.PatternId)
222   
223    if 'Offset' not in sourceData[0]:    #patch for old data
224        sourceData[0].update({'Offset':[0.0,0.0],'delOffset':0.02,'refOffset':-1.0,
225            'refDelt':0.01,'qPlot':False,'dPlot':False,'sqrtPlot':False})
226        G2frame.PatternTree.SetItemPyData(G2frame.PatternId,sourceData)
227       
228    dlg = G2G.G2MultiChoiceDialog(
229        G2frame.dataFrame, 
230        'Copy plot controls from\n'+str(hst[5:])+' to...',
231        'Copy plot controls', histList)
232    results = []
233    try:
234        if dlg.ShowModal() == wx.ID_OK:
235            results = dlg.GetSelections()
236    finally:
237        dlg.Destroy()
238    copyList = []
239    for i in results: 
240        copyList.append(histList[i])
241
242    keys = ['Offset','delOffset','refOffset','refDelt','qPlot','dPlot','sqrtPlot']
243    source = dict(zip(keys,[sourceData[0][item] for item in keys]))
244    for hist in copyList:
245        Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,hist)
246        data = G2frame.PatternTree.GetItemPyData(Id)
247        data[0].update(source)
248        G2frame.PatternTree.SetItemPyData(Id,data)
249    print 'Copy of plot controls successful'
250
251def CopySelectedHistItems(G2frame):
252    '''Global copy: Copy items from current histogram to others.
253    '''
254    hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
255    histList = GetHistsLikeSelected(G2frame)
256    if not histList:
257        G2frame.ErrorDialog('No match','No other histograms match '+hst,G2frame.dataFrame)
258        return
259    choices = ['Limits','Background','Instrument Parameters','Sample Parameters']
260    dlg = G2G.G2MultiChoiceDialog(
261        G2frame.dataFrame, 
262        'Copy which histogram sections from\n'+str(hst[5:]),
263        'Select copy sections', choices, filterBox=False)
264    dlg.SetSelections(range(len(choices)))
265    choiceList = []
266    if dlg.ShowModal() == wx.ID_OK:
267        choiceList = [choices[i] for i in dlg.GetSelections()]
268    if not choiceList: return
269   
270    dlg = G2G.G2MultiChoiceDialog(
271        G2frame.dataFrame, 
272        'Copy parameters from\n'+str(hst[5:])+' to...',
273        'Copy parameters', histList)
274    results = []
275    try:
276        if dlg.ShowModal() == wx.ID_OK:
277            results = dlg.GetSelections()
278    finally:
279        dlg.Destroy()
280    copyList = []
281    for i in results: 
282        copyList.append(histList[i])
283
284    if 'Limits' in choiceList: # Limits
285        data = G2frame.PatternTree.GetItemPyData(
286            G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId,'Limits'))
287        for item in copyList:
288            Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
289            G2frame.PatternTree.SetItemPyData(
290                G2gd.GetPatternTreeItemId(G2frame,Id,'Limits'),
291                copy.deepcopy(data))
292    if 'Background' in choiceList:  # Background
293        data = G2frame.PatternTree.GetItemPyData(
294            G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId,'Background'))
295        for item in copyList:
296            Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
297            G2frame.PatternTree.SetItemPyData(
298                G2gd.GetPatternTreeItemId(G2frame,Id,'Background'),
299                copy.deepcopy(data))
300    if 'Instrument Parameters' in choiceList:  # Instrument Parameters
301        # for now all items in Inst. parms are copied
302        data,data1 = G2frame.PatternTree.GetItemPyData(
303            G2gd.GetPatternTreeItemId(
304                G2frame,G2frame.PatternId,'Instrument Parameters'))
305        for item in copyList:
306            Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
307            G2frame.PatternTree.GetItemPyData(
308                G2gd.GetPatternTreeItemId(G2frame,Id,'Instrument Parameters')
309                )[0].update(copy.deepcopy(data))
310            G2frame.PatternTree.GetItemPyData(
311                G2gd.GetPatternTreeItemId(G2frame,Id,'Instrument Parameters')
312                )[1].update(copy.deepcopy(data1))
313    if 'Sample Parameters' in choiceList:  # Sample Parameters
314        data = G2frame.PatternTree.GetItemPyData(
315            G2gd.GetPatternTreeItemId(
316                G2frame,G2frame.PatternId,'Sample Parameters'))
317        # selects items to be copied
318        histType,copyNames = SetCopyNames(hst,data['Type'],
319            addNames = ['Omega','Chi','Phi','Gonio. radius','InstrName'])
320        copyDict = {parm:data[parm] for parm in copyNames}
321        for item in copyList:
322            Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
323            G2frame.PatternTree.GetItemPyData(
324                G2gd.GetPatternTreeItemId(G2frame,Id,'Sample Parameters')
325                ).update(copy.deepcopy(copyDict))
326                         
327################################################################################
328#####  Powder Peaks
329################################################################################           
330       
331def UpdatePeakGrid(G2frame, data):
332    '''respond to selection of PWDR powder peaks data tree item.
333    '''
334    if G2frame.dataDisplay:
335        G2frame.dataFrame.Clear()
336       
337    def OnAutoSearch(event):
338        PatternId = G2frame.PatternId
339        PickId = G2frame.PickId
340        limits = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Limits'))[1]
341        inst,inst2 = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Instrument Parameters'))
342        profile = G2frame.PatternTree.GetItemPyData(PatternId)[1]
343        x0 = profile[0]
344        iBeg = np.searchsorted(x0,limits[0])
345        iFin = np.searchsorted(x0,limits[1])
346        x = x0[iBeg:iFin]
347        y0 = profile[1][iBeg:iFin]
348        y1 = copy.copy(y0)
349        ysig = np.std(y1)
350        offset = [-1,1]
351        ymask = ma.array(y0,mask=(y0<ysig))
352        for off in offset:
353            ymask = ma.array(ymask,mask=(ymask-np.roll(y0,off)<=0.))
354        indx = ymask.nonzero()
355        mags = ymask[indx]
356        poss = x[indx]
357        refs = zip(poss,mags)
358        if 'C' in Inst['Type'][0]:   
359            refs = G2mth.sortArray(refs,0,reverse=True)     #small 2-Thetas first
360        else:   #'T'OF
361            refs = G2mth.sortArray(refs,0,reverse=False)    #big TOFs first
362        for i,ref1 in enumerate(refs):
363            for ref2 in refs[i+1:]:
364                if abs(ref2[0]-ref1[0]) < 0.1*G2pwd.getFWHM(ref1[0],inst):
365                    del(refs[i])
366        if 'C' in Inst['Type'][0]:   
367            refs = G2mth.sortArray(refs,1,reverse=True)
368        else:   #'T'OF
369            refs = G2mth.sortArray(refs,1,reverse=False)
370        for pos,mag in refs:
371            data['peaks'].append(G2mth.setPeakparms(inst,inst2,pos,mag))
372        UpdatePeakGrid(G2frame,data)
373        G2plt.PlotPatterns(G2frame,plotType='PWDR')
374       
375    def OnCopyPeaks(event):
376        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
377        histList = GetHistsLikeSelected(G2frame)
378        if not histList:
379            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
380            return
381        copyList = []
382        dlg = G2G.G2MultiChoiceDialog(
383            G2frame.dataFrame, 
384            'Copy peak list from\n'+str(hst[5:])+' to...',
385            'Copy peaks', histList)
386        try:
387            if dlg.ShowModal() == wx.ID_OK:
388                for i in dlg.GetSelections():
389                    copyList.append(histList[i])
390        finally:
391            dlg.Destroy()
392        for item in copyList:
393            Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
394            G2frame.PatternTree.SetItemPyData(
395                G2gd.GetPatternTreeItemId(G2frame,Id,'Peak List'),copy.deepcopy(data))
396   
397    def OnUnDo(event):
398        DoUnDo()
399        G2frame.dataFrame.UnDo.Enable(False)
400       
401    def DoUnDo():
402        print 'Undo last refinement'
403        file = open(G2frame.undofile,'rb')
404        PatternId = G2frame.PatternId
405        for item in ['Background','Instrument Parameters','Peak List']:
406            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, item),cPickle.load(file))
407            if G2frame.dataDisplay.GetName() == item:
408                if item == 'Background':
409                    UpdateBackground(G2frame,G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, item)))
410                elif item == 'Instrument Parameters':
411                    UpdateInstrumentGrid(G2frame,G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, item)))
412                elif item == 'Peak List':
413                    UpdatePeakGrid(G2frame,G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, item)))
414            print item,' recovered'
415        file.close()
416       
417    def SaveState():
418        G2frame.undofile = os.path.join(G2frame.dirname,'GSASII.save')
419        file = open(G2frame.undofile,'wb')
420        PatternId = G2frame.PatternId
421        for item in ['Background','Instrument Parameters','Peak List']:
422            cPickle.dump(G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId,item)),file,1)
423        file.close()
424        G2frame.dataFrame.UnDo.Enable(True)
425       
426    def OnLSQPeakFit(event):
427        if not G2frame.GSASprojectfile:            #force a save of the gpx file so SaveState can write in the same directory
428            G2frame.OnFileSaveas(event)
429        OnPeakFit('LSQ')
430       
431    def OnOneCycle(event):
432        OnPeakFit('LSQ',oneCycle=True)
433       
434    def OnSeqPeakFit(event):
435        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
436        histList = GetHistsLikeSelected(G2frame)
437        if not histList:
438            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
439            return
440        sel = []
441        dlg = G2G.G2MultiChoiceDialog(G2frame.dataFrame, 'Sequential peak fits',
442             'Select dataset to include',histList)
443        dlg.SetSelections(sel)
444        names = []
445        if dlg.ShowModal() == wx.ID_OK:
446            for sel in dlg.GetSelections():
447                names.append(histList[sel])
448        dlg.Destroy()
449        SeqResult = {}
450        Reverse = False
451        CopyForward = False
452        choice = ['Reverse sequence','Copy from prev.',]
453        dlg = wx.MultiChoiceDialog(G2frame.dataFrame,'Sequential controls','Select controls',choice)
454        if dlg.ShowModal() == wx.ID_OK:
455            for sel in dlg.GetSelections():
456                if sel:
457                    CopyForward = True
458                else:
459                    Reverse = True
460        dlg.Destroy()
461        dlg = wx.ProgressDialog('Sequential peak fit','Data set name = '+names[0],len(names), 
462            style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE|wx.PD_REMAINING_TIME|wx.PD_CAN_ABORT)
463        Controls = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.root, 'Controls'))
464        controls = {'deriv type':'analytic','min dM/M':0.0001,}
465        Controls['ShowCell'] = False
466        print 'Peak Fitting with '+controls['deriv type']+' derivatives:'
467        oneCycle = False
468        FitPgm = 'LSQ'
469        prevVaryList = []
470        Names = []
471        if Reverse:
472            names.reverse()
473        try:
474            for i,name in enumerate(names):
475                print ' Sequential fit for ',name
476                GoOn = dlg.Update(i,newmsg='Data set name = '+name)[0]
477                if not GoOn:
478                    break
479                PatternId =  G2gd.GetPatternTreeItemId(G2frame,G2frame.root,name)
480                if i and CopyForward:
481                    G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Peak List'),copy.deepcopy(peaks))
482                    prevVaryList = varyList[:]
483                peaks = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Peak List'))
484                background = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Background'))
485                limits = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Limits'))[1]
486                inst,inst2 = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Instrument Parameters'))
487                data = G2frame.PatternTree.GetItemPyData(PatternId)[1]
488                wx.BeginBusyCursor()
489                dlg2 = wx.ProgressDialog('Residual','Peak fit Rwp = ',101.0, 
490                    style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE|wx.PD_REMAINING_TIME|wx.PD_CAN_ABORT)
491                screenSize = wx.ClientDisplayRect()
492                Size = dlg.GetSize()
493                if 50 < Size[0] < 500: # sanity check on size, since this fails w/Win & wx3.0
494                    dlg2.SetSize((int(Size[0]*1.2),Size[1])) # increase size a bit along x
495                    dlg2.SetPosition(wx.Point(screenSize[2]-Size[0]-305,screenSize[1]+5))
496                try:
497                    peaks['sigDict'],result,sig,Rvals,varyList,parmDict,fullvaryList,badVary = G2pwd.DoPeakFit(FitPgm,peaks['peaks'],
498                        background,limits,inst,inst2,data,prevVaryList,oneCycle,controls,dlg2)
499                finally:
500                    dlg2.Destroy()
501                if len(result[0]) != len(fullvaryList):
502                    print ' ***** Sequential peak fit stopped at '+name+' *****'
503                    break
504                else:
505                    Names.append(name)   
506                    G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Peak List'),copy.deepcopy(peaks))
507                    SeqResult[name] = {'variables':result[0],'varyList':varyList,'sig':sig,'Rvals':Rvals,
508                        'covMatrix':np.eye(len(result[0])),'title':name,'parmDict':parmDict,
509                        'fullVary':fullvaryList,'badVary':badVary}
510            dlg.Destroy()
511            print ' ***** Sequential peak fit successful *****'
512        finally:
513            wx.EndBusyCursor()
514        SeqResult['histNames'] = Names
515        Id =  G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Sequential results')
516        if Id:
517            G2frame.PatternTree.SetItemPyData(Id,SeqResult)
518        else:
519            Id = G2frame.PatternTree.AppendItem(parent=G2frame.root,text='Sequential results')
520            G2frame.PatternTree.SetItemPyData(Id,SeqResult)
521        G2frame.PatternTree.SelectItem(Id)
522       
523    def OnClearPeaks(event):
524        dlg = wx.MessageDialog(G2frame,'Delete all peaks?','Clear peak list',wx.OK|wx.CANCEL)
525        try:
526            if dlg.ShowModal() == wx.ID_OK:
527                peaks = {'peaks':[],'sigDict':{}}
528        finally:
529            dlg.Destroy()
530        UpdatePeakGrid(G2frame,peaks)
531        G2plt.PlotPatterns(G2frame,plotType='PWDR')
532       
533    def OnPeakFit(FitPgm,oneCycle=False):
534        SaveState()
535        controls = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.root, 'Controls'))
536        if not controls:
537            controls = {'deriv type':'analytic','min dM/M':0.0001,}     #fill in defaults if needed
538        print 'Peak Fitting with '+controls['deriv type']+' derivatives:'
539        PatternId = G2frame.PatternId
540        PickId = G2frame.PickId
541        peaks = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Peak List'))
542        if not peaks:
543            G2frame.ErrorDialog('No peaks!','Nothing to fit!')
544            return
545        background = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Background'))
546        limits = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Limits'))[1]
547        inst,inst2 = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Instrument Parameters'))
548        data = G2frame.PatternTree.GetItemPyData(PatternId)[1]
549        wx.BeginBusyCursor()
550        dlg = wx.ProgressDialog('Residual','Peak fit Rwp = ',101.0, 
551            style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE|wx.PD_REMAINING_TIME|wx.PD_CAN_ABORT)
552        screenSize = wx.ClientDisplayRect()
553        Size = dlg.GetSize()
554        if 50 < Size[0] < 500: # sanity check on size, since this fails w/Win & wx3.0
555            dlg.SetSize((int(Size[0]*1.2),Size[1])) # increase size a bit along x
556            dlg.SetPosition(wx.Point(screenSize[2]-Size[0]-305,screenSize[1]+5))
557        try:
558            peaks['sigDict'] = G2pwd.DoPeakFit(FitPgm,peaks['peaks'],background,limits,inst,inst2,data,[],oneCycle,controls,dlg)[0]
559        finally:
560            wx.EndBusyCursor()   
561        G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Peak List'),copy.copy(peaks))
562        UpdatePeakGrid(G2frame,copy.copy(peaks))
563        G2plt.PlotPatterns(G2frame,plotType='PWDR')
564        print 'finished'
565        return
566       
567    def OnResetSigGam(event):
568        PatternId = G2frame.PatternId
569        PickId = G2frame.PickId
570        Inst,Inst2 = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Instrument Parameters'))
571        peaks = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Peak List'))
572        if not peaks['peaks']:
573            G2frame.ErrorDialog('No peaks!','Nothing to do!')
574            return
575        newpeaks = {'peaks':[],'sigDict':{}}
576        for peak in peaks['peaks']:
577            newpeaks['peaks'].append(G2mth.setPeakparms(Inst,Inst2,peak[0],peak[2]))
578        G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Peak List'),newpeaks)
579        UpdatePeakGrid(G2frame,newpeaks)
580               
581    def RefreshPeakGrid(event):
582        r,c =  event.GetRow(),event.GetCol()
583       
584        event.StopPropagation()
585        data['peaks'] = G2frame.PeakTable.GetData()
586        T = []
587        for peak in data['peaks']:T.append(peak[0])
588        D = dict(zip(T,data['peaks']))
589        T.sort()
590        X = []
591        for key in T: X.append(D[key])
592        data['peaks'] = X       
593       
594    def setBackgroundColors():
595       for r in range(G2frame.dataDisplay.GetNumberRows()):
596           for c in range(G2frame.dataDisplay.GetNumberCols()):
597               if G2frame.dataDisplay.GetColLabelValue(c) in ['position','intensity','alpha','beta','sigma','gamma']:
598                   if float(G2frame.dataDisplay.GetCellValue(r,c)) < 0.:
599                       G2frame.dataDisplay.SetCellBackgroundColour(r,c,wx.RED)
600                   else:
601                       G2frame.dataDisplay.SetCellBackgroundColour(r,c,wx.WHITE)
602                                                 
603    def KeyEditPeakGrid(event):
604        rowList = G2frame.dataDisplay.GetSelectedRows()
605        colList = G2frame.dataDisplay.GetSelectedCols()
606        selectList = G2frame.dataDisplay.GetSelectedCells()
607        data = G2frame.PatternTree.GetItemPyData(G2frame.PickId)
608        if event.GetKeyCode() == wx.WXK_RETURN:
609            event.Skip(True)
610        elif event.GetKeyCode() == wx.WXK_CONTROL:
611            event.Skip(True)
612        elif event.GetKeyCode() == wx.WXK_SHIFT:
613            event.Skip(True)
614        elif rowList:
615            G2frame.dataDisplay.ClearSelection()
616            if event.GetKeyCode() == wx.WXK_DELETE:
617                G2frame.dataDisplay.ClearGrid()
618                rowList.sort()
619                rowList.reverse()
620                nDel = 0
621                for row in rowList:
622                    G2frame.PeakTable.DeleteRow(row)
623                    nDel += 1
624                if nDel:
625                    msg = wg.GridTableMessage(G2frame.PeakTable, 
626                        wg.GRIDTABLE_NOTIFY_ROWS_DELETED,0,nDel)
627                    G2frame.dataDisplay.ProcessTableMessage(msg)
628                data = G2frame.PeakTable.GetData()
629                G2frame.PatternTree.SetItemPyData(G2frame.PickId,data['peaks'][:-nDel])
630                G2frame.dataDisplay.ForceRefresh()
631                setBackgroundColors()
632                       
633        elif colList:
634            G2frame.dataDisplay.ClearSelection()
635            key = event.GetKeyCode()
636            for col in colList:
637                if G2frame.PeakTable.GetTypeName(0,col) == wg.GRID_VALUE_BOOL:
638                    if key == 89: #'Y'
639                        for row in range(G2frame.PeakTable.GetNumberRows()): data['peaks'][row][col]=True
640                    elif key == 78:  #'N'
641                        for row in range(G2frame.PeakTable.GetNumberRows()): data['peaks'][row][col]=False
642        elif selectList:
643            G2frame.dataDisplay.ClearSelection()
644            key = event.GetKeyCode()
645            for row,col in selectList:
646                if G2frame.PeakTable.GetTypeName(row,col) == wg.GRID_VALUE_BOOL:
647                    if key == 89: #'Y'
648                        data['peaks'][row][col]=True
649                    elif key == 78:  #'N'
650                        data['peaks'][row][col]=False
651        G2plt.PlotPatterns(G2frame,plotType='PWDR')
652           
653    G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.PeakMenu)
654    if not G2frame.dataFrame.GetStatusBar():
655        Status = G2frame.dataFrame.CreateStatusBar()
656    Status.SetStatusText('Global refine: select refine column & press Y or N')
657    G2frame.Bind(wx.EVT_MENU, OnAutoSearch, id=G2gd.wxID_AUTOSEARCH)
658    G2frame.Bind(wx.EVT_MENU, OnCopyPeaks, id=G2gd.wxID_PEAKSCOPY)
659    G2frame.Bind(wx.EVT_MENU, OnUnDo, id=G2gd.wxID_UNDO)
660    G2frame.Bind(wx.EVT_MENU, OnLSQPeakFit, id=G2gd.wxID_LSQPEAKFIT)
661    G2frame.Bind(wx.EVT_MENU, OnOneCycle, id=G2gd.wxID_LSQONECYCLE)
662    G2frame.Bind(wx.EVT_MENU, OnSeqPeakFit, id=G2gd.wxID_SEQPEAKFIT)
663    G2frame.Bind(wx.EVT_MENU, OnClearPeaks, id=G2gd.wxID_CLEARPEAKS)
664    G2frame.Bind(wx.EVT_MENU, OnResetSigGam, id=G2gd.wxID_RESETSIGGAM)
665    if data['peaks']:
666        G2frame.dataFrame.AutoSearch.Enable(False)
667        G2frame.dataFrame.PeakCopy.Enable(True)
668        G2frame.dataFrame.PeakFit.Enable(True)
669        G2frame.dataFrame.PFOneCycle.Enable(True)
670        G2frame.dataFrame.SeqPeakFit.Enable(True)
671    else:
672        G2frame.dataFrame.PeakFit.Enable(False)
673        G2frame.dataFrame.PeakCopy.Enable(False)
674        G2frame.dataFrame.PFOneCycle.Enable(False)
675        G2frame.dataFrame.AutoSearch.Enable(True)
676        G2frame.dataFrame.SeqPeakFit.Enable(False)
677    G2frame.PickTable = []
678    rowLabels = []
679    PatternId = G2frame.PatternId
680    Inst = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Instrument Parameters'))[0]
681    for i in range(len(data['peaks'])): rowLabels.append(str(i+1))
682    if 'C' in Inst['Type'][0]:
683        colLabels = ['position','refine','intensity','refine','sigma','refine','gamma','refine']
684        Types = [wg.GRID_VALUE_FLOAT+':10,4',wg.GRID_VALUE_BOOL,
685            wg.GRID_VALUE_FLOAT+':10,1',wg.GRID_VALUE_BOOL,
686            wg.GRID_VALUE_FLOAT+':10,5',wg.GRID_VALUE_BOOL,
687            wg.GRID_VALUE_FLOAT+':10,5',wg.GRID_VALUE_BOOL]
688    else:
689        colLabels = ['position','refine','intensity','refine','alpha','refine',
690            'beta','refine','sigma','refine','gamma','refine']
691        Types = [wg.GRID_VALUE_FLOAT+':10,1',wg.GRID_VALUE_BOOL,
692            wg.GRID_VALUE_FLOAT+':10,4',wg.GRID_VALUE_BOOL,
693            wg.GRID_VALUE_FLOAT+':10,4',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            wg.GRID_VALUE_FLOAT+':10,5',wg.GRID_VALUE_BOOL]
697    T = []
698    for peak in data['peaks']:
699        T.append(peak[0])
700    D = dict(zip(T,data['peaks']))
701    T.sort()
702    if 'T' in Inst['Type'][0]:  #want big TOF's first
703        T.reverse()
704    X = []
705    for key in T: X.append(D[key])
706    data['peaks'] = X
707    G2frame.PatternTree.SetItemPyData(G2frame.PickId,data)
708    G2frame.PeakTable = G2G.Table(data['peaks'],rowLabels=rowLabels,colLabels=colLabels,types=Types)
709    G2frame.dataFrame.SetLabel('Peak List')
710    G2frame.dataDisplay = G2G.GSGrid(parent=G2frame.dataFrame)
711    G2frame.dataDisplay.SetTable(G2frame.PeakTable, True)
712    setBackgroundColors()                         
713    G2frame.dataDisplay.Bind(wg.EVT_GRID_CELL_CHANGE, RefreshPeakGrid)
714    G2frame.dataDisplay.Bind(wx.EVT_KEY_DOWN, KeyEditPeakGrid)
715    G2frame.dataDisplay.SetMargins(0,0)
716    G2frame.dataDisplay.AutoSizeColumns(False)
717    G2frame.dataFrame.setSizePosLeft([535,350])
718    G2frame.dataFrame.SendSizeEvent()
719       
720################################################################################
721#####  Background
722################################################################################           
723       
724def UpdateBackground(G2frame,data):
725    '''respond to selection of PWDR background data tree item.
726    '''
727    if len(data) < 2:       #add Debye diffuse & peaks scattering here
728        data.append({'nDebye':0,'debyeTerms':[],'nPeaks':0,'peaksList':[]})
729    if 'nPeaks' not in data[1]:
730        data[1].update({'nPeaks':0,'peaksList':[]})
731    ValObj = {}
732   
733    def OnBackFlagCopy(event):
734        flag = data[0][1]
735        backDict = data[-1]
736        if backDict['nDebye']:
737            DBflags = []
738            for term in backDict['debyeTerms']:
739                DBflags.append(term[1::2])
740        if backDict['nPeaks']:
741            PKflags = []
742            for term in backDict['peaksList']:
743                PKflags.append(term[1::2])           
744        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
745        histList = GetHistsLikeSelected(G2frame)
746        if not histList:
747            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
748            return
749        dlg = G2G.G2MultiChoiceDialog(
750            G2frame.dataFrame, 
751            'Copy bkg ref. flags from\n'+str(hst[5:])+' to...',
752            'Copy bkg flags', histList)
753        copyList = []
754        try:
755            if dlg.ShowModal() == wx.ID_OK:
756                for i in dlg.GetSelections(): 
757                    copyList.append(histList[i])
758        finally:
759            dlg.Destroy()
760        for item in copyList:
761            Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
762            backData = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Background'))
763            backData[0][1] = copy.copy(flag)
764            bkDict = backData[-1]
765            if bkDict['nDebye'] == backDict['nDebye']:
766                for i,term in enumerate(bkDict['debyeTerms']):
767                    term[1::2] = copy.copy(DBflags[i])
768            if bkDict['nPeaks'] == backDict['nPeaks']:
769                for i,term in enumerate(bkDict['peaksList']):
770                    term[1::2] = copy.copy(PKflags[i])                   
771           
772    def OnBackCopy(event):
773        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
774        histList = GetHistsLikeSelected(G2frame)
775        if not histList:
776            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
777            return
778        copyList = []
779        dlg = G2G.G2MultiChoiceDialog(
780            G2frame.dataFrame, 
781            'Copy bkg params from\n'+str(hst[5:])+' to...',
782            'Copy parameters', histList)
783        try:
784            if dlg.ShowModal() == wx.ID_OK:
785                for i in dlg.GetSelections():
786                    copyList.append(histList[i])
787        finally:
788            dlg.Destroy()
789        for item in copyList:
790            Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
791            G2frame.PatternTree.SetItemPyData(
792                G2gd.GetPatternTreeItemId(G2frame,Id,'Background'),copy.copy(data))
793
794    def OnBkgFit(event):
795        def SetInstParms(Inst):
796            dataType = Inst['Type'][0]
797            insVary = []
798            insNames = []
799            insVals = []
800            for parm in Inst:
801                insNames.append(parm)
802                insVals.append(Inst[parm][1])
803                if parm in ['U','V','W','X','Y','SH/L','I(L2)/I(L1)','alpha',
804                    'beta-0','beta-1','beta-q','sig-0','sig-1','sig-2','sig-q',] and Inst[parm][2]:
805                        insVary.append(parm)
806            instDict = dict(zip(insNames,insVals))
807            instDict['X'] = max(instDict['X'],0.01)
808            instDict['Y'] = max(instDict['Y'],0.01)
809            if 'SH/L' in instDict:
810                instDict['SH/L'] = max(instDict['SH/L'],0.002)
811            return dataType,instDict,insVary
812   
813        PatternId = G2frame.PatternId       
814        controls = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.root, 'Controls'))
815        background = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Background'))
816        limits = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Limits'))[1]
817        inst,inst2 = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Instrument Parameters'))
818        # sort the points for convenience and then separate them; extend the range if needed
819        background[1]['FixedPoints'] = sorted(background[1]['FixedPoints'],key=lambda pair:pair[0])       
820        X = [x for x,y in background[1]['FixedPoints']]
821        Y = [y for x,y in background[1]['FixedPoints']]
822        if X[0] > limits[0]:
823            X = [limits[0]] + X
824            Y = [Y[0]] + Y
825        if X[-1] < limits[1]:
826            X += [limits[1]]
827            Y += [Y[-1]]
828        # interpolate the fixed points onto the grid of data points within limits
829        pwddata = G2frame.PatternTree.GetItemPyData(PatternId)[1]
830        xBeg = np.searchsorted(pwddata[0],limits[0])
831        xFin = np.searchsorted(pwddata[0],limits[1])
832        xdata = pwddata[0][xBeg:xFin]
833        ydata = si.interp1d(X,Y)(xdata)
834        #GSASIIpath.IPyBreak()
835        W = [1]*len(xdata)
836        Z = [0]*len(xdata)
837
838        # load instrument and background params
839        dataType,insDict,insVary = SetInstParms(inst)
840        bakType,bakDict,bakVary = G2pwd.SetBackgroundParms(background)
841        # how many background parameters are refined?
842        if len(bakVary)*1.5 > len(X):
843            msg = ("You are attempting to vary "+str(len(bakVary))+
844                   " background terms with only "+str(len(X))+" background points"+
845                    "\nAdd more points or reduce the number of terms")
846            print msg
847            G2frame.ErrorDialog('Too few points',msg)
848            return
849       
850        wx.BeginBusyCursor()
851        try:
852            G2pwd.DoPeakFit('LSQ',[],background,limits,inst,inst2,
853                            np.array((xdata,ydata,W,Z,Z,Z)),bakVary,False,controls)
854        finally:
855            wx.EndBusyCursor()
856        # compute the background values and plot them
857        parmDict = {}
858        bakType,bakDict,bakVary = G2pwd.SetBackgroundParms(background)
859        parmDict.update(bakDict)
860        parmDict.update(insDict)
861        pwddata[3] *= 0
862        pwddata[5] *= 0
863        pwddata[4][xBeg:xFin] = G2pwd.getBackground(
864            '',parmDict,bakType,dataType,xdata)[0]
865        G2plt.PlotPatterns(G2frame,plotType='PWDR')
866        # show the updated background values
867        wx.CallLater(100,UpdateBackground,G2frame,data)
868       
869    def OnBkgClear(event):
870        if 'FixedPoints' not in data[1]:
871            return
872        else:
873            del data[1]['FixedPoints']
874            G2plt.PlotPatterns(G2frame,plotType='PWDR')
875   
876    def OnPeaksMove(event):
877        if not data[1]['nPeaks']:
878            G2frame.ErrorDialog('Error','No peaks to move')
879            return
880        Peaks = {'peaks':[],'sigDict':{}}
881        for peak in data[1]['peaksList']:
882            Peaks['peaks'].append([peak[0],0,peak[2],0,peak[4],0,peak[6],0])
883        G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Peak List'),Peaks)
884       
885    def BackSizer():
886       
887        def OnNewType(event):
888            data[0][0] = bakType.GetValue()
889           
890        def OnBakRef(event):
891            data[0][1] = bakRef.GetValue()
892           
893        def OnBakTerms(event):
894            data[0][2] = int(bakTerms.GetValue())
895            M = len(data[0])
896            N = data[0][2]+3
897            item = data[0]
898            if N > M:       #add terms
899                for i in range(M,N): 
900                    item.append(0.0)
901            elif N < M:     #delete terms
902                for i in range(N,M):
903                    del(item[-1])
904            G2frame.PatternTree.SetItemPyData(BackId,data)
905            #wx.CallAfter(UpdateBackground,G2frame,data)
906            wx.CallLater(100,UpdateBackground,G2frame,data)
907           
908        def OnBakVal(event):
909            Obj = event.GetEventObject()
910            item = ValObj[Obj.GetId()][0]
911            try:
912                value = float(Obj.GetValue())
913            except ValueError:
914                value = data[0][item]
915            data[0][item] = value
916            Obj.SetValue('%10.4f'%(value))
917       
918        backSizer = wx.BoxSizer(wx.VERTICAL)
919        topSizer = wx.BoxSizer(wx.HORIZONTAL)
920        topSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' Background function: '),0,WACV)
921        bakType = wx.ComboBox(G2frame.dataDisplay,value=data[0][0],
922                choices=Choices,style=wx.CB_READONLY|wx.CB_DROPDOWN)
923        bakType.Bind(wx.EVT_COMBOBOX, OnNewType)
924        topSizer.Add(bakType)
925        topSizer.Add((5,0),0)
926        bakRef = wx.CheckBox(G2frame.dataDisplay,label=' Refine?')
927        bakRef.SetValue(bool(data[0][1]))
928        bakRef.Bind(wx.EVT_CHECKBOX, OnBakRef)
929        topSizer.Add(bakRef,0,WACV)
930        topSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' No. coeff.: '),0,WACV)
931        bakTerms = wx.ComboBox(G2frame.dataDisplay,-1,value=str(data[0][2]),choices=[str(i+1) for i in range(36)],
932            style=wx.CB_READONLY|wx.CB_DROPDOWN)
933        bakTerms.Bind(wx.EVT_COMBOBOX,OnBakTerms)
934        topSizer.Add(bakTerms,0,WACV)
935        topSizer.Add((5,0),0)
936        backSizer.Add(topSizer)
937        backSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' Background coefficients:'),0,WACV)
938        bakSizer = wx.FlexGridSizer(0,5,5,5)
939        for i,value in enumerate(data[0][3:]):
940            bakVal = wx.TextCtrl(G2frame.dataDisplay,wx.ID_ANY,'%10.4g'%(value),style=wx.TE_PROCESS_ENTER)
941            bakSizer.Add(bakVal,0,WACV)
942            ValObj[bakVal.GetId()] = [i+3]
943            bakVal.Bind(wx.EVT_TEXT_ENTER,OnBakVal)
944            bakVal.Bind(wx.EVT_KILL_FOCUS,OnBakVal)
945        backSizer.Add(bakSizer)
946        return backSizer
947       
948    def DebyeSizer():
949       
950        def OnDebTerms(event):
951            data[1]['nDebye'] = int(debTerms.GetValue())
952            M = len(data[1]['debyeTerms'])
953            N = data[1]['nDebye']
954            if N > M:       #add terms
955                for i in range(M,N): 
956                    data[1]['debyeTerms'].append([1.0,False,1.0,False,0.010,False])
957            elif N < M:     #delete terms
958                for i in range(N,M):
959                    del(data[1]['debyeTerms'][-1])
960            #wx.CallAfter(UpdateBackground,G2frame,data)
961            wx.CallLater(100,UpdateBackground,G2frame,data)
962
963        def KeyEditPeakGrid(event):
964            colList = debyeGrid.GetSelectedCols()
965            if event.GetKeyCode() == wx.WXK_RETURN:
966                event.Skip(True)
967            elif event.GetKeyCode() == wx.WXK_CONTROL:
968                event.Skip(True)
969            elif event.GetKeyCode() == wx.WXK_SHIFT:
970                event.Skip(True)
971            elif colList:
972                debyeGrid.ClearSelection()
973                key = event.GetKeyCode()
974                for col in colList:
975                    if debyeTable.GetTypeName(0,col) == wg.GRID_VALUE_BOOL:
976                        if key == 89: #'Y'
977                            for row in range(debyeGrid.GetNumberRows()): data[1]['debyeTerms'][row][col]=True
978                        elif key == 78:  #'N'
979                            for row in range(debyeGrid.GetNumberRows()): data[1]['debyeTerms'][row][col]=False
980
981       
982        debSizer = wx.BoxSizer(wx.VERTICAL)
983        topSizer = wx.BoxSizer(wx.HORIZONTAL)
984        topSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' Debye scattering: '),0,WACV)
985        topSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' No. coeff.: '),0,WACV)
986        debTerms = wx.ComboBox(G2frame.dataDisplay,-1,value=str(data[1]['nDebye']),choices=[str(i) for i in range(12)],
987            style=wx.CB_READONLY|wx.CB_DROPDOWN)
988        debTerms.Bind(wx.EVT_COMBOBOX,OnDebTerms)
989        topSizer.Add(debTerms,0,WACV)
990        topSizer.Add((5,0),0)
991        debSizer.Add(topSizer)
992        if data[1]['nDebye']:
993            debSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' Debye diffuse terms:'),0,WACV)       
994            rowLabels = []
995            for i in range(len(data[1]['debyeTerms'])): rowLabels.append(str(i))
996            colLabels = ['A','refine','R','refine','U','refine']
997            Types = [wg.GRID_VALUE_FLOAT+':10,2',wg.GRID_VALUE_BOOL,
998            wg.GRID_VALUE_FLOAT+':10,3',wg.GRID_VALUE_BOOL,
999            wg.GRID_VALUE_FLOAT+':10,5',wg.GRID_VALUE_BOOL]
1000            debyeTable = G2G.Table(data[1]['debyeTerms'],rowLabels=rowLabels,colLabels=colLabels,types=Types)
1001            debyeGrid = G2G.GSGrid(parent=G2frame.dataDisplay)
1002            debyeGrid.SetTable(debyeTable, True)
1003            debyeGrid.Bind(wx.EVT_KEY_DOWN, KeyEditPeakGrid)
1004            debyeGrid.AutoSizeColumns(False)
1005            debSizer.Add(debyeGrid)       
1006        return debSizer
1007     
1008    def PeaksSizer():
1009
1010        def OnPeaks(event):
1011            data[1]['nPeaks'] = int(peaks.GetValue())
1012            M = len(data[1]['peaksList'])
1013            N = data[1]['nPeaks']
1014            if N > M:       #add terms
1015                for i in range(M,N): 
1016                    data[1]['peaksList'].append([1.0,False,1.0,False,0.10,False,0.10,False])
1017            elif N < M:     #delete terms
1018                for i in range(N,M):
1019                    del(data[1]['peaksList'][-1])
1020            #wx.CallAfter(UpdateBackground,G2frame,data)
1021            wx.CallLater(100,UpdateBackground,G2frame,data)
1022           
1023        def KeyEditPeakGrid(event):
1024            colList = peaksGrid.GetSelectedCols()
1025            if event.GetKeyCode() == wx.WXK_RETURN:
1026                event.Skip(True)
1027            elif event.GetKeyCode() == wx.WXK_CONTROL:
1028                event.Skip(True)
1029            elif event.GetKeyCode() == wx.WXK_SHIFT:
1030                event.Skip(True)
1031            elif colList:
1032                peaksGrid.ClearSelection()
1033                key = event.GetKeyCode()
1034                for col in colList:
1035                    if peaksTable.GetTypeName(0,col) == wg.GRID_VALUE_BOOL:
1036                        if key == 89: #'Y'
1037                            for row in range(peaksGrid.GetNumberRows()): data[1]['peaksList'][row][col]=True
1038                        elif key == 78:  #'N'
1039                            for row in range(peaksGrid.GetNumberRows()): data[1]['peaksList'][row][col]=False
1040
1041        peaksSizer = wx.BoxSizer(wx.VERTICAL)
1042        topSizer = wx.BoxSizer(wx.HORIZONTAL)
1043        topSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' Peaks in background: '),0,WACV)
1044        topSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' No. peaks: '),0,WACV)
1045        peaks = wx.ComboBox(G2frame.dataDisplay,-1,value=str(data[1]['nPeaks']),choices=[str(i) for i in range(30)],
1046            style=wx.CB_READONLY|wx.CB_DROPDOWN)
1047        peaks.Bind(wx.EVT_COMBOBOX,OnPeaks)
1048        topSizer.Add(peaks,0,WACV)
1049        topSizer.Add((5,0),0)
1050        peaksSizer.Add(topSizer)
1051        if data[1]['nPeaks']:
1052            peaksSizer.Add(wx.StaticText(G2frame.dataDisplay,-1,' Peak list:'),0,WACV)       
1053            rowLabels = []
1054            for i in range(len(data[1]['peaksList'])): rowLabels.append(str(i))
1055            colLabels = ['pos','refine','int','refine','sig','refine','gam','refine']
1056            Types = [wg.GRID_VALUE_FLOAT+':10,2',wg.GRID_VALUE_BOOL,
1057            wg.GRID_VALUE_FLOAT+':10,3',wg.GRID_VALUE_BOOL,
1058            wg.GRID_VALUE_FLOAT+':10,3',wg.GRID_VALUE_BOOL,
1059            wg.GRID_VALUE_FLOAT+':10,5',wg.GRID_VALUE_BOOL]
1060            peaksTable = G2G.Table(data[1]['peaksList'],rowLabels=rowLabels,colLabels=colLabels,types=Types)
1061            peaksGrid = G2G.GSGrid(parent=G2frame.dataDisplay)
1062            peaksGrid.SetTable(peaksTable, True)
1063            peaksGrid.Bind(wx.EVT_KEY_DOWN, KeyEditPeakGrid)
1064            peaksGrid.AutoSizeColumns(False)
1065            peaksSizer.Add(peaksGrid)       
1066        return peaksSizer
1067               
1068    if G2frame.dataDisplay:
1069        G2frame.dataFrame.DestroyChildren()
1070    G2frame.dataDisplay = wx.Panel(G2frame.dataFrame)
1071    G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.BackMenu)
1072    G2frame.dataFrame.SetLabel('Background')
1073    if not G2frame.dataFrame.GetStatusBar():
1074        Status = G2frame.dataFrame.CreateStatusBar()
1075    G2frame.Bind(wx.EVT_MENU,OnBackCopy,id=G2gd.wxID_BACKCOPY)
1076    G2frame.Bind(wx.EVT_MENU,OnBackFlagCopy,id=G2gd.wxID_BACKFLAGCOPY)
1077    G2frame.Bind(wx.EVT_MENU,OnPeaksMove,id=G2gd.wxID_PEAKSMOVE)
1078    G2frame.Bind(wx.EVT_MENU,OnBkgFit,id=G2frame.dataFrame.wxID_BackPts['Fit'])
1079    G2frame.Bind(wx.EVT_MENU,OnBkgClear,id=G2frame.dataFrame.wxID_BackPts['Clear'])   
1080    BackId = G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Background')
1081    Choices = ['chebyschev','cosine','Q^2 power series','Q^-2 power series','lin interpolate','inv interpolate','log interpolate']
1082    mainSizer = wx.BoxSizer(wx.VERTICAL)
1083    mainSizer.Add(BackSizer())
1084    mainSizer.Add((0,5),0)
1085    mainSizer.Add(DebyeSizer())
1086    mainSizer.Add((0,5),0)
1087    mainSizer.Add(PeaksSizer())
1088    mainSizer.Layout()   
1089    G2frame.dataDisplay.SetSizer(mainSizer)
1090    G2frame.dataFrame.setSizePosLeft(mainSizer.Fit(G2frame.dataFrame))
1091       
1092################################################################################
1093#####  Limits
1094################################################################################           
1095       
1096def UpdateLimitsGrid(G2frame, data,plottype):
1097    '''respond to selection of PWDR Limits data tree item.
1098    '''
1099    if G2frame.dataDisplay:
1100        G2frame.dataFrame.Clear()
1101    G2frame.ifGetExclude = False
1102       
1103    def KeyEditPeakGrid(event):
1104        if event.GetKeyCode() == wx.WXK_DELETE:
1105            row = G2frame.dataDisplay.GetSelectedRows()[0]
1106            if row > 1: #can't delete limits!
1107                del(data[row])
1108                wx.CallAfter(UpdateLimitsGrid,G2frame,data,plottype)
1109                G2plt.PlotPatterns(G2frame,plotType=plottype)
1110                       
1111    def RefreshLimitsGrid(event):
1112        event.StopPropagation()
1113        data = G2frame.LimitsTable.GetData()
1114        old = data[0]
1115        new = data[1]
1116        new[0] = max(old[0],new[0])
1117        new[1] = max(new[0],min(old[1],new[1]))
1118        excl = []
1119        if len(data) > 2:
1120            excl = data[2:]
1121            for item in excl:
1122                item[0] = max(old[0],item[0])
1123                item[1] = max(item[0],min(old[1],item[1]))
1124        data = [old,new]+excl
1125        G2frame.LimitsTable.SetData(data)
1126        G2plt.PlotPatterns(G2frame,plotType=plottype)
1127       
1128    def OnLimitCopy(event):
1129        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
1130        histList = GetHistsLikeSelected(G2frame)
1131        if not histList:
1132            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
1133            return
1134        copyList = []
1135        dlg = G2G.G2MultiChoiceDialog(
1136            G2frame.dataFrame, 
1137            'Copy limits from\n'+str(hst[5:])+' to...',
1138            'Copy limits', histList)
1139        try:
1140            if dlg.ShowModal() == wx.ID_OK:
1141                for i in dlg.GetSelections(): 
1142                    item = histList[i]
1143                    Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
1144                    G2frame.PatternTree.SetItemPyData(
1145                        G2gd.GetPatternTreeItemId(G2frame,Id,'Limits'),copy.copy(data))
1146        finally:
1147            dlg.Destroy()
1148           
1149    def OnAddExcl(event):
1150        G2frame.ifGetExclude = True
1151        print 'Add excluded region'
1152       
1153    G2frame.LimitsTable = []
1154    colLabels = ['Tmin','Tmax']
1155    rowLabels = ['original','changed']
1156    for i in range(len(data)-2):
1157        rowLabels.append('exclude')
1158    Types = 2*[wg.GRID_VALUE_FLOAT+':12,5',]
1159    G2frame.LimitsTable = G2G.Table(data,rowLabels=rowLabels,colLabels=colLabels,types=Types)
1160    G2frame.dataFrame.SetLabel('Limits')
1161    G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.LimitMenu)
1162    if not G2frame.dataFrame.GetStatusBar():
1163        Status = G2frame.dataFrame.CreateStatusBar()
1164    G2frame.Bind(wx.EVT_MENU,OnLimitCopy,id=G2gd.wxID_LIMITCOPY)
1165    G2frame.Bind(wx.EVT_MENU,OnAddExcl,id=G2gd.wxID_ADDEXCLREGION)   
1166    G2frame.dataDisplay = G2G.GSGrid(parent=G2frame.dataFrame)
1167    G2frame.dataDisplay.SetTable(G2frame.LimitsTable, True)   
1168    G2frame.dataDisplay.SetCellStyle(0,0,VERY_LIGHT_GREY,True)
1169    G2frame.dataDisplay.SetCellStyle(0,1,VERY_LIGHT_GREY,True)
1170    G2frame.dataDisplay.Bind(wg.EVT_GRID_CELL_CHANGE, RefreshLimitsGrid)               
1171    G2frame.dataDisplay.Bind(wx.EVT_KEY_DOWN, KeyEditPeakGrid)
1172    G2frame.dataDisplay.SetMargins(0,0)
1173    G2frame.dataDisplay.AutoSizeColumns(False)
1174    G2frame.dataFrame.setSizePosLeft([230,260])                               
1175    G2frame.dataFrame.SendSizeEvent()
1176   
1177################################################################################
1178#####  Instrument parameters
1179################################################################################           
1180       
1181def UpdateInstrumentGrid(G2frame,data):
1182    '''respond to selection of PWDR/SASD Instrument Parameters
1183    data tree item.
1184    '''
1185    if 'Bank' not in data:  #get it from name; absent for default parms selection
1186        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
1187        if 'Bank' in hst:
1188            bank = int(hst.split('Bank')[1].split('_')[0])
1189            data['Bank'] = [bank,bank,0]
1190        else:
1191            data['Bank'] = [1,1,0]
1192
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','P4/mmm',
2464        '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 controls[5] in ['Fm3m','Im3m','Pm3m']:
2479            controls[7] = controls[8] = controls[6]
2480            controls[9] = controls[10] = controls[11] = 90.
2481        elif controls[5] in ['R3m','P6/mmm','I4/mmm','P4/mmm']:
2482            controls[7] = controls[6]
2483            controls[9] = controls[10] = controls[11] = 90.
2484            if controls[5] in ['R3-H','P6/mmm']:
2485                controls[11] = 120.
2486        elif controls[5] in ['Fmmm','Immm','Cmmm','Pmmm']:
2487            controls[9] = controls[10] = controls[11] = 90.
2488        elif controls[5] in ['C2/m','P2/m']:
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 controls[5] in ['Fm3m','Im3m','Pm3m']:
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 controls[5] in ['R3-H','P6/mmm','I4/mmm','P4/mmm']:
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 controls[5] in ['R3-H','P6/mmm']:
2613                controls[11] = 120.
2614        elif controls[5] in ['Fmmm','Immm','Cmmm','Pmmm']:
2615            controls[6+ObjId] = value
2616            Obj.SetValue("%.5f"%(controls[6+ObjId]))
2617            controls[9] = controls[10] = controls[11] = 90.0
2618        elif controls[5] in ['C2/m','P2/m']:
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        wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)
2678       
2679    def OnHklShow(event):
2680        PatternId = G2frame.PatternId
2681        PickId = G2frame.PickId   
2682        peaks = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Index Peak List'))
2683        limits = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Limits'))[1]
2684        controls,bravais,cells,dminx,ssopt = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Unit Cells List'))
2685        cell = controls[6:12]
2686        A = G2lat.cell2A(cell)
2687#        ibrav = bravaisSymb.index(controls[5])
2688        spc = controls[13]
2689        SGData = G2spc.SpcGroup(spc)[1]
2690        if ssopt.get('Use',False):
2691            SSGData = G2spc.SSpcGroup(SGData,ssopt['ssSymb'])[1]
2692            Vec = ssopt['ModVec']
2693            maxH = ssopt['maxH']
2694            G2frame.HKL = G2pwd.getHKLMpeak(dmin,Inst,SGData,SSGData,Vec,maxH,A)
2695            peaks = [G2indx.IndexSSPeaks(peaks[0],G2frame.HKL)[1],peaks[1]]   #keep esds from peak fit
2696            M20,X20 = G2indx.calc_M20SS(peaks[0],G2frame.HKL)
2697        else:
2698            if len(peaks[0]):
2699#                dmin = peaks[0][-1][7]
2700                G2frame.HKL = G2pwd.getHKLpeak(dmin,SGData,A,Inst)
2701                peaks = [G2indx.IndexPeaks(peaks[0],G2frame.HKL)[1],peaks[1]]   #keep esds from peak fit
2702                M20,X20 = G2indx.calc_M20(peaks[0],G2frame.HKL)
2703            else:
2704                M20 = X20 = 0.
2705                G2frame.HKL = G2pwd.getHKLpeak(dmin,SGData,A,Inst)
2706        G2frame.HKL = np.array(G2frame.HKL)
2707        if len(G2frame.HKL):
2708            print ' new M20,X20: %.2f %d fraction found: %.3f'%(M20,X20,float(len(peaks[0]))/len(G2frame.HKL))
2709        G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Index Peak List'),peaks)
2710        if 'PKS' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
2711            G2plt.PlotPowderLines(G2frame)
2712        else:
2713            G2plt.PlotPatterns(G2frame)
2714           
2715    def OnSortCells(event):
2716        controls,bravais,cells,dminx,ssopt = G2frame.PatternTree.GetItemPyData(UnitCellsId)
2717        c =  event.GetCol()
2718        if colLabels[c] == 'M20':
2719            cells = G2indx.sortM20(cells)
2720        elif colLabels[c] in ['X20','Bravais','a','b','c','alpha','beta','gamma','Volume']:
2721            if c == 1:
2722                c += 1  #X20 before Use
2723            cells = G2indx.sortCells(cells,c-1)     #an extra column (Use) not in cells
2724        else:
2725            return
2726        data = [controls,bravais,cells,dmin,ssopt]
2727        G2frame.PatternTree.SetItemPyData(UnitCellsId,data)
2728        wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)
2729       
2730    def CopyUnitCell(event):
2731        controls,bravais,cells,dminx,ssopt = G2frame.PatternTree.GetItemPyData(UnitCellsId)
2732        for Cell in cells:
2733            if Cell[-2]:
2734                break
2735        cell = Cell[2:9]
2736        controls[4] = 1
2737        controls[5] = bravaisSymb[cell[0]]
2738        controls[6:12] = cell[1:8]
2739        controls[12] = G2lat.calc_V(G2lat.cell2A(controls[6:12]))
2740        controls[13] = spaceGroups[bravaisSymb.index(controls[5])]
2741        G2frame.PatternTree.SetItemPyData(UnitCellsId,[controls,bravais,cells,dmin,ssopt])
2742        G2frame.dataFrame.RefineCell.Enable(True)
2743        wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)       
2744               
2745    def RefineCell(event):
2746       
2747        def cellPrint(ibrav,A):
2748            cell = G2lat.A2cell(A)
2749            Vol = G2lat.calc_V(A)
2750            if ibrav in ['Fm3m','Im3m','Pm3m']:
2751                print " %s%10.6f" % ('a =',cell[0])
2752            elif ibrav in ['R3-H','P6/mmm','I4/mmm','P4/mmm']:
2753                print " %s%10.6f %s%10.6f %s%12.3f" % ('a =',cell[0],' c =',cell[2],' volume =',Vol)
2754            elif ibrav in ['P4/mmm','Fmmm','Immm','Cmmm','Pmmm']:
2755                print " %s%10.6f %s%10.6f %s%10.6f %s%12.3f" % ('a =',cell[0],'b =',cell[1],'c =',cell[2],' volume =',Vol)
2756            elif ibrav in ['C2/m','P2/m']:
2757                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)
2758            else:
2759                print " %s%10.6f %s%10.6f %s%10.6f" % ('a =',cell[0],'b =',cell[1],'c =',cell[2])
2760                print " %s%8.3f %s%8.3f %s%8.3f %s%12.3f" % ('alpha =',cell[3],'beta =',cell[4],'gamma =',cell[5],' volume =',Vol)
2761               
2762        def vecPrint(Vec):
2763            print ' %s %10.5f %10.5f %10.5f'%('Modulation vector:',Vec[0],Vec[1],Vec[2])
2764             
2765        PatternId = G2frame.PatternId
2766        PickId = G2frame.PickId   
2767        peaks = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Index Peak List'))
2768        if not len(peaks[0]):
2769            G2frame.ErrorDialog('No peaks!', 'Nothing to refine!')
2770            return       
2771        print ' Refine cell'
2772        controls,bravais,cells,dminx,ssopt = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Unit Cells List'))
2773        cell = controls[6:12]
2774        A = G2lat.cell2A(cell)
2775        ibrav = bravaisSymb.index(controls[5])
2776        SGData = G2spc.SpcGroup(controls[13])[1]
2777        if 'C' in Inst['Type'][0] or 'PKS' in Inst['Type'][0]:
2778            if ssopt.get('Use',False):
2779                vecFlags = [True if x in ssopt['ssSymb'] else False for x in ['a','b','g']]
2780                SSGData = G2spc.SSpcGroup(SGData,ssopt['ssSymb'])[1]
2781                G2frame.HKL = G2pwd.getHKLMpeak(dmin,Inst,SGData,SSGData,ssopt['ModVec'],ssopt['maxH'],A)
2782                peaks = [G2indx.IndexSSPeaks(peaks[0],G2frame.HKL)[1],peaks[1]]   #put peak fit esds back in peaks
2783                Lhkl,M20,X20,Aref,Vec,Zero = \
2784                    G2indx.refinePeaksZSS(peaks[0],wave,Inst,SGData,SSGData,ssopt['maxH'],ibrav,A,ssopt['ModVec'],vecFlags,controls[1],controls[0])
2785            else:
2786                G2frame.HKL = G2pwd.getHKLpeak(dmin,SGData,A,Inst)
2787                peaks = [G2indx.IndexPeaks(peaks[0],G2frame.HKL)[1],peaks[1]]   #put peak fit esds back in peaks
2788                Lhkl,M20,X20,Aref,Zero = G2indx.refinePeaksZ(peaks[0],wave,ibrav,A,controls[1],controls[0])
2789        else:   
2790            if ssopt.get('Use',False):
2791                vecFlags = [True if x in ssopt['ssSymb'] else False for x in ['a','b','g']]
2792                SSGData = G2spc.SSpcGroup(SGData,ssopt['ssSymb'])[1]
2793                G2frame.HKL = G2pwd.getHKLMpeak(dmin,Inst,SGData,SSGData,ssopt['ModVec'],ssopt['maxH'],A)
2794                peaks = [G2indx.IndexSSPeaks(peaks[0],G2frame.HKL)[1],peaks[1]]   #put peak fit esds back in peaks
2795                Lhkl,M20,X20,Aref,Vec,Zero = \
2796                    G2indx.refinePeaksTSS(peaks[0],difC,Inst,SGData,SSGData,ssopt['maxH'],ibrav,A,ssopt['ModVec'],vecFlags,controls[1],controls[0])
2797            else:
2798                G2frame.HKL = G2pwd.getHKLpeak(dmin,SGData,A,Inst)
2799                peaks = [G2indx.IndexPeaks(peaks[0],G2frame.HKL)[1],peaks[1]]   #put peak fit esds back in peaks
2800                Lhkl,M20,X20,Aref,Zero = G2indx.refinePeaksT(peaks[0],difC,ibrav,A,controls[1],controls[0])           
2801        G2frame.HKL = np.array(G2frame.HKL)
2802        controls[1] = Zero
2803        controls[6:12] = G2lat.A2cell(Aref)
2804        controls[12] = G2lat.calc_V(Aref)
2805        cells = G2frame.PatternTree.GetItemPyData(UnitCellsId)[2]
2806        for cell in cells:
2807            cell[-2] = False
2808        cells.insert(0,[M20,X20,ibrav]+controls[6:13]+[True,False])
2809        if ssopt.get('Use',False):
2810            ssopt['ModVec'] = Vec
2811            G2frame.HKL = G2pwd.getHKLMpeak(dmin,Inst,SGData,SSGData,ssopt['ModVec'],ssopt['maxH'],A)
2812        else:
2813            G2frame.HKL = G2pwd.getHKLpeak(dmin,SGData,A,Inst)
2814        data = [controls,bravais,cells,dmin,ssopt]
2815        G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Unit Cells List'),data)
2816        print " %s%10.3f" % ('refinement M20 = ',M20)
2817        print ' unindexed lines = ',X20
2818        cellPrint(controls[5],Aref)
2819        ip = 4
2820        if ssopt.get('Use',False):
2821            vecPrint(Vec)
2822            ip = 5
2823        for hkl in G2frame.HKL:
2824            hkl[ip] = G2lat.Dsp2pos(Inst,hkl[ip-1])+controls[1]
2825        G2frame.HKL = np.array(G2frame.HKL)
2826        if 'PKS' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
2827            G2plt.PlotPowderLines(G2frame)
2828        else:
2829            G2plt.PlotPatterns(G2frame)
2830        wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)
2831       
2832    def OnIndexPeaks(event):
2833        PatternId = G2frame.PatternId   
2834        print 'Peak Indexing'
2835        keepcells = []
2836        try:
2837            controls,bravais,cells,dminx,ssopt = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Unit Cells List'))
2838            for cell in cells:
2839                if cell[11]:
2840                    cell[10] = False    #clear selection flag on keepers
2841                    keepcells.append(cell)
2842        except IndexError:
2843            pass
2844        except ValueError:
2845            G2frame.ErrorDialog('Error','Need to set controls in Unit Cell List first')
2846            return
2847        if ssopt.get('Use',False):
2848            G2frame.ErrorDialog('Super lattice error','Indexing not available for super lattices')
2849            return
2850        if True not in bravais:
2851            G2frame.ErrorDialog('Error','No Bravais lattices selected')
2852            return
2853        if not len(peaks[0]):
2854            G2frame.ErrorDialog('Error','Index Peak List is empty')
2855            return
2856        if len(peaks[0][0]) > 9:
2857            G2frame.ErrorDialog('Error','You need to reload Index Peaks List first')
2858            return
2859        G2frame.dataFrame.CopyCell.Enable(False)
2860        G2frame.dataFrame.RefineCell.Enable(False)
2861        dlg = wx.ProgressDialog("Generated reflections",'0 '+" cell search for "+bravaisNames[ibrav],101, 
2862#            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
2863            style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE|wx.PD_REMAINING_TIME|wx.PD_CAN_ABORT)
2864        OK,dmin,newcells = G2indx.DoIndexPeaks(peaks[0],controls,bravais,dlg,G2frame.ifX20)
2865        dlg.Destroy()
2866        cells = keepcells+newcells
2867        cells = G2indx.sortM20(cells)
2868        if OK:
2869            cells[0][10] = True         #select best M20
2870            data = [controls,bravais,cells,dmin,ssopt]
2871            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Unit Cells List'),data)
2872            bestCell = cells[0]
2873            if bestCell[0] > 10.:
2874                G2frame.HKL = G2lat.GenHBravais(dmin,bestCell[2],G2lat.cell2A(bestCell[3:9]))
2875                for hkl in G2frame.HKL:
2876                    hkl.insert(4,G2lat.Dsp2pos(Inst,hkl[3])+controls[1])
2877                G2frame.HKL = np.array(G2frame.HKL)
2878                if 'PKS' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
2879                    G2plt.PlotPowderLines(G2frame)
2880                else:
2881                    G2plt.PlotPatterns(G2frame)
2882            G2frame.dataFrame.CopyCell.Enable(True)
2883            G2frame.dataFrame.IndexPeaks.Enable(True)
2884            G2frame.dataFrame.MakeNewPhase.Enable(True)
2885            G2frame.ifX20 = True
2886            wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)
2887               
2888    def RefreshUnitCellsGrid(event):
2889        data = G2frame.PatternTree.GetItemPyData(UnitCellsId)
2890        cells,dminx = data[2:4]
2891        r,c =  event.GetRow(),event.GetCol()
2892        if cells:
2893            if c == 2:
2894                for i in range(len(cells)):
2895                    cells[i][-2] = False
2896                    UnitCellsTable.SetValue(i,c,False)
2897                UnitCellsTable.SetValue(r,c,True)
2898                gridDisplay.ForceRefresh()
2899                cells[r][-2] = True
2900                ibrav = cells[r][2]
2901                A = G2lat.cell2A(cells[r][3:9])
2902                G2frame.HKL = G2lat.GenHBravais(dmin,ibrav,A)
2903                for hkl in G2frame.HKL:
2904                    hkl.insert(4,G2lat.Dsp2pos(Inst,hkl[3])+controls[1])
2905                G2frame.HKL = np.array(G2frame.HKL)
2906                if 'PKS' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
2907                    G2plt.PlotPowderLines(G2frame)
2908                else:
2909                    G2plt.PlotPatterns(G2frame)
2910            elif c == 11:
2911                if UnitCellsTable.GetValue(r,c):
2912                    UnitCellsTable.SetValue(r,c,False)
2913                    cells[r][c] = False
2914                else:
2915                    cells[r][c] = True
2916                    UnitCellsTable.SetValue(r,c,True)
2917                gridDisplay.ForceRefresh()
2918            G2frame.PatternTree.SetItemPyData(UnitCellsId,data)
2919       
2920    def MakeNewPhase(event):
2921        if not G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Phases'):
2922            sub = G2frame.PatternTree.AppendItem(parent=G2frame.root,text='Phases')
2923        else:
2924            sub = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Phases')
2925        PhaseName = ''
2926        dlg = wx.TextEntryDialog(None,'Enter a name for this phase','Phase Name Entry','New phase',
2927            style=wx.OK)
2928        try:
2929            if dlg.ShowModal() == wx.ID_OK:
2930                PhaseName = dlg.GetValue()
2931                cells = G2frame.PatternTree.GetItemPyData(UnitCellsId)[2]
2932                for Cell in cells:
2933                    if Cell[-2]:
2934                        break
2935                cell = Cell[2:10]       
2936                sub = G2frame.PatternTree.AppendItem(parent=sub,text=PhaseName)
2937                E,SGData = G2spc.SpcGroup(controls[13])
2938                G2frame.PatternTree.SetItemPyData(sub, \
2939                    G2IO.SetNewPhase(Name=PhaseName,SGData=SGData,cell=cell[1:],Super=ssopt))
2940                Status.SetStatusText('Change space group from '+str(controls[13])+' if needed')
2941        finally:
2942            dlg.Destroy()
2943           
2944    if G2frame.dataDisplay:
2945        G2frame.dataFrame.DestroyChildren()
2946    G2frame.dataDisplay = wxscroll.ScrolledPanel(G2frame.dataFrame)
2947    G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.IndexMenu)
2948    if not G2frame.dataFrame.GetStatusBar():
2949        Status = G2frame.dataFrame.CreateStatusBar()
2950    G2frame.Bind(wx.EVT_MENU, OnIndexPeaks, id=G2gd.wxID_INDEXPEAKS)
2951    G2frame.Bind(wx.EVT_MENU, CopyUnitCell, id=G2gd.wxID_COPYCELL)
2952    G2frame.Bind(wx.EVT_MENU, RefineCell, id=G2gd.wxID_REFINECELL)
2953    G2frame.Bind(wx.EVT_MENU, MakeNewPhase, id=G2gd.wxID_MAKENEWPHASE)
2954    G2frame.Bind(wx.EVT_MENU, OnExportCells, id=G2gd.wxID_EXPORTCELLS)
2955       
2956    controls,bravais,cells,dminx,ssopt = data
2957    if len(controls) < 13:              #add cell volume if missing
2958        controls.append(G2lat.calc_V(G2lat.cell2A(controls[6:12])))
2959    if len(controls) < 14:              #add space group used in indexing
2960        controls.append(spaceGroups[bravaisSymb.index(controls[5])])
2961    G2frame.PatternTree.SetItemPyData(UnitCellsId,data)            #update with volume
2962    bravaisNames = ['Cubic-F','Cubic-I','Cubic-P','Trigonal-R','Trigonal/Hexagonal-P',
2963        'Tetragonal-I','Tetragonal-P','Orthorhombic-F','Orthorhombic-I','Orthorhombic-C',
2964        'Orthorhombic-P','Monoclinic-C','Monoclinic-P','Triclinic']
2965    cellGUIlist = [[[0,1,2],4,zip([" Unit cell: a = "," Vol = "],["%.5f","%.3f"],[True,False],[0,0])],
2966    [[3,4,5,6],6,zip([" Unit cell: a = "," c = "," Vol = "],["%.5f","%.5f","%.3f"],[True,True,False],[0,2,0])],
2967    [[7,8,9,10],8,zip([" Unit cell: a = "," b = "," c = "," Vol = "],["%.5f","%.5f","%.5f","%.3f"],
2968        [True,True,True,False],[0,1,2,0])],
2969    [[11,12],10,zip([" Unit cell: a = "," b = "," c = "," beta = "," Vol = "],
2970        ["%.5f","%.5f","%.5f","%.3f","%.3f"],[True,True,True,True,False],[0,1,2,4,0])],
2971    [[13,],8,zip([" Unit cell: a = "," b = "," c = "," Vol = "," alpha = "," beta = "," gamma = "],
2972        ["%.5f","%.5f","%.5f","%.3f","%.3f","%.3f","%.3f"],
2973        [True,True,True,False,True,True,True],[0,1,2,0,3,4,5])]]
2974   
2975    G2frame.dataFrame.SetLabel('Unit Cells List')
2976    G2frame.dataFrame.IndexPeaks.Enable(False)
2977    peaks = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Index Peak List'))
2978    if peaks:
2979        G2frame.dataFrame.IndexPeaks.Enable(True)
2980    G2frame.dataFrame.RefineCell.Enable(False)
2981    if controls[12] > 1.0:                               #if a "real" volume (i.e. not default)
2982        G2frame.dataFrame.RefineCell.Enable(True)   
2983    G2frame.dataFrame.CopyCell.Enable(False)
2984    G2frame.dataFrame.MakeNewPhase.Enable(False)       
2985    G2frame.dataFrame.ExportCells.Enable(False)
2986    if cells:
2987        G2frame.dataFrame.CopyCell.Enable(True)
2988        G2frame.dataFrame.MakeNewPhase.Enable(True)
2989        G2frame.dataFrame.ExportCells.Enable(True)
2990    mainSizer = wx.BoxSizer(wx.VERTICAL)
2991    mainSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Indexing controls: '),0,WACV)
2992    mainSizer.Add((5,5),0)
2993    littleSizer = wx.FlexGridSizer(0,5,5,5)
2994    littleSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Max Nc/Nobs '),0,WACV)
2995    NcNo = wx.SpinCtrl(G2frame.dataDisplay)
2996    NcNo.SetRange(2,8)
2997    NcNo.SetValue(controls[2])
2998    NcNo.Bind(wx.EVT_SPINCTRL,OnNcNo)
2999    littleSizer.Add(NcNo,0,WACV)
3000    littleSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Start Volume '),0,WACV)
3001    startVol = wx.TextCtrl(G2frame.dataDisplay,value=str('%d'%(controls[3])),style=wx.TE_PROCESS_ENTER)
3002    startVol.Bind(wx.EVT_TEXT_ENTER,OnStartVol)
3003    startVol.Bind(wx.EVT_KILL_FOCUS,OnStartVol)
3004    littleSizer.Add(startVol,0,WACV)
3005    x20 = wx.CheckBox(G2frame.dataDisplay,label='Use M20/(X20+1)?')
3006    x20.SetValue(G2frame.ifX20)
3007    x20.Bind(wx.EVT_CHECKBOX,OnIfX20)
3008    littleSizer.Add(x20,0,WACV)
3009    mainSizer.Add(littleSizer,0)
3010    mainSizer.Add((5,5),0)
3011    mainSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Select Bravais Lattices for indexing: '),
3012        0,WACV)
3013    mainSizer.Add((5,5),0)
3014    littleSizer = wx.FlexGridSizer(0,7,5,5)
3015    bravList = []
3016    bravs = zip(bravais,bravaisNames)
3017    for brav,bravName in bravs:
3018        bravCk = wx.CheckBox(G2frame.dataDisplay,label=bravName)
3019        bravList.append(bravCk.GetId())
3020        bravCk.SetValue(brav)
3021        bravCk.Bind(wx.EVT_CHECKBOX,OnBravais)
3022        littleSizer.Add(bravCk,0,WACV)
3023    mainSizer.Add(littleSizer,0)
3024    mainSizer.Add((5,5),0)
3025   
3026    mainSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Cell Test & Refinement: '),0,WACV)
3027    mainSizer.Add((5,5),0)
3028    littleSizer = wx.BoxSizer(wx.HORIZONTAL)
3029    littleSizer.Add(wx.StaticText(G2frame.dataDisplay,label=" Bravais lattice "),0,WACV)
3030    bravSel = wx.Choice(G2frame.dataDisplay,choices=bravaisSymb)
3031    bravSel.SetSelection(bravaisSymb.index(controls[5]))
3032    bravSel.Bind(wx.EVT_CHOICE,OnBravSel)
3033    littleSizer.Add(bravSel,0,WACV)
3034    littleSizer.Add(wx.StaticText(G2frame.dataDisplay,label=" Space group "),0,WACV)
3035    spcSel = wx.Choice(G2frame.dataDisplay,choices=SPGlist[controls[5]])
3036    spcSel.SetSelection(SPGlist[controls[5]].index(controls[13]))
3037    spcSel.Bind(wx.EVT_CHOICE,OnSpcSel)
3038    littleSizer.Add(spcSel,0,WACV)
3039    if ssopt.get('Use',False):        #zero for super lattice doesn't work!
3040        controls[0] = False
3041    else:
3042        littleSizer.Add(wx.StaticText(G2frame.dataDisplay,label=" Zero offset"),0,WACV)
3043        zero = wx.TextCtrl(G2frame.dataDisplay,value="%.4f"%(controls[1]),style=wx.TE_PROCESS_ENTER)
3044        zero.Bind(wx.EVT_TEXT_ENTER,OnZero)
3045        zero.Bind(wx.EVT_KILL_FOCUS,OnZero)
3046        littleSizer.Add(zero,0,WACV)
3047        zeroVar = wx.CheckBox(G2frame.dataDisplay,label="Refine?")
3048        zeroVar.SetValue(controls[0])
3049        zeroVar.Bind(wx.EVT_CHECKBOX,OnZeroVar)
3050        littleSizer.Add(zeroVar,0,WACV)
3051    SSopt = wx.CheckBox(G2frame.dataDisplay,label="Super lattice?")
3052    SSopt.SetValue(ssopt.get('Use',False))
3053    SSopt.Bind(wx.EVT_CHECKBOX,OnSSopt)
3054    littleSizer.Add(SSopt,0,WACV)
3055    hklShow = wx.Button(G2frame.dataDisplay,label="Show hkl positions")
3056    hklShow.Bind(wx.EVT_BUTTON,OnHklShow)
3057    littleSizer.Add(hklShow,0,WACV)
3058    mainSizer.Add(littleSizer,0)
3059   
3060    mainSizer.Add((5,5),0)
3061    ibrav = SetLattice(controls)
3062    for cellGUI in cellGUIlist:
3063        if ibrav in cellGUI[0]:
3064            useGUI = cellGUI
3065    cellList = []
3066    valDict = {}
3067    littleSizer = wx.FlexGridSizer(0,useGUI[1],5,5)
3068    for txt,fmt,ifEdit,Id in useGUI[2]:
3069        littleSizer.Add(wx.StaticText(G2frame.dataDisplay,label=txt),0,WACV)
3070        if ifEdit:          #a,b,c,etc.
3071            cellVal = wx.TextCtrl(G2frame.dataDisplay,value=(fmt%(controls[6+Id])),style=wx.TE_PROCESS_ENTER)
3072            cellVal.Bind(wx.EVT_TEXT_ENTER,OnCellChange)       
3073            cellVal.Bind(wx.EVT_KILL_FOCUS,OnCellChange)
3074            valSizer = wx.BoxSizer(wx.HORIZONTAL)
3075            valSizer.Add(cellVal,0,WACV)
3076            cellSpin = wx.SpinButton(G2frame.dataDisplay,style=wx.SP_VERTICAL,size=wx.Size(20,20))
3077            cellSpin.SetValue(0)
3078            cellSpin.SetRange(-1,1)
3079            cellSpin.Bind(wx.EVT_SPIN, OnMoveCell)
3080            valSizer.Add(cellSpin,0,WACV)
3081            littleSizer.Add(valSizer,0,WACV)
3082            cellList.append(cellVal.GetId())
3083            cellList.append(cellSpin.GetId())
3084            valDict[cellSpin.GetId()] = cellVal
3085        else:               #volume
3086            volVal = wx.TextCtrl(G2frame.dataDisplay,value=(fmt%(controls[12])),style=wx.TE_READONLY)
3087            volVal.SetBackgroundColour(VERY_LIGHT_GREY)
3088            littleSizer.Add(volVal,0,WACV)
3089    mainSizer.Add(littleSizer,0)
3090    if ssopt.get('Use',False):        #super lattice display
3091        indChoice = ['1','2','3','4',]
3092        SpSg = controls[13]
3093        ssChoice = G2spc.ssdict[SpSg]
3094        if ssopt['ssSymb'] not in ssChoice:
3095            ssopt['ssSymb'] = ssChoice[0]
3096        ssSizer = wx.BoxSizer(wx.HORIZONTAL)
3097        ssSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Supersymmetry space group: '+SpSg+' '),0,WACV)
3098        selMG = wx.ComboBox(G2frame.dataDisplay,value=ssopt['ssSymb'],
3099                choices=ssChoice,style=wx.CB_READONLY|wx.CB_DROPDOWN)
3100        selMG.Bind(wx.EVT_COMBOBOX, OnSelMG)
3101        ssSizer.Add(selMG,0,WACV)
3102        ssSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Mod. vector: '),0,WACV)
3103        modS = G2spc.splitSSsym(ssopt['ssSymb'])[0]
3104        ssopt['ModVec'],ifShow = G2spc.SSGModCheck(ssopt['ModVec'],modS)
3105        Indx = {}
3106        for i,[val,show] in enumerate(zip(ssopt['ModVec'],ifShow)):
3107            if show:
3108                valSizer = wx.BoxSizer(wx.HORIZONTAL)
3109                modVal = wx.TextCtrl(G2frame.dataDisplay,value=('%.4f'%(val)),
3110                    size=wx.Size(50,20),style=wx.TE_PROCESS_ENTER)
3111                modVal.Bind(wx.EVT_TEXT_ENTER,OnModVal)       
3112                modVal.Bind(wx.EVT_KILL_FOCUS,OnModVal)
3113                valSizer.Add(modVal,0,WACV)
3114                modSpin = wx.SpinButton(G2frame.dataDisplay,style=wx.SP_VERTICAL,size=wx.Size(20,20))
3115                modSpin.SetValue(0)
3116                modSpin.SetRange(-1,1)
3117                modSpin.Bind(wx.EVT_SPIN, OnMoveMod)
3118                valSizer.Add(modSpin,0,WACV)
3119                ssSizer.Add(valSizer,0,WACV)
3120                Indx[modVal.GetId()] = i
3121                Indx[modSpin.GetId()] = [i,modVal]
3122            else:
3123                modVal = wx.TextCtrl(G2frame.dataDisplay,value=('%.3f'%(val)),
3124                    size=wx.Size(50,20),style=wx.TE_READONLY)
3125                modVal.SetBackgroundColour(VERY_LIGHT_GREY)
3126                ssSizer.Add(modVal,0,WACV)
3127        ssSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Max. M: '),0,WACV)
3128        maxMH = wx.ComboBox(G2frame.dataDisplay,value=str(ssopt['maxH']),
3129            choices=indChoice,style=wx.CB_READONLY|wx.CB_DROPDOWN)
3130        maxMH.Bind(wx.EVT_COMBOBOX, OnMaxMH)
3131        ssSizer.Add(maxMH,0,WACV)
3132        findMV = wx.Button(G2frame.dataDisplay,label="Find mod. vec.?")
3133        findMV.Bind(wx.EVT_BUTTON,OnFindMV)
3134        ssSizer.Add(findMV,0,WACV)
3135        mainSizer.Add(ssSizer,0)
3136
3137    if cells:
3138        mainSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label='\n Indexing Result:'),0,WACV)
3139        rowLabels = []
3140        colLabels = ['M20','X20','use','Bravais','a','b','c','alpha','beta','gamma','Volume','Keep']
3141        Types = [wg.GRID_VALUE_FLOAT+':10,2',wg.GRID_VALUE_NUMBER,wg.GRID_VALUE_BOOL,wg.GRID_VALUE_STRING,]+ \
3142            3*[wg.GRID_VALUE_FLOAT+':10,5',]+3*[wg.GRID_VALUE_FLOAT+':10,3',]+ \
3143            [wg.GRID_VALUE_FLOAT+':10,2',wg.GRID_VALUE_BOOL]
3144        numRows = len(cells)
3145        table = []
3146        for cell in cells:
3147            rowLabels.append('')
3148            row = cell[0:2]+[cell[-2]]+[bravaisSymb[cell[2]]]+cell[3:10]+[cell[11],]
3149            if cell[-2]:
3150                A = G2lat.cell2A(cell[3:9])
3151                G2frame.HKL = G2lat.GenHBravais(dmin,cell[2],A)
3152                for hkl in G2frame.HKL:
3153                    hkl.insert(4,G2lat.Dsp2pos(Inst,hkl[3])+controls[1])
3154                G2frame.HKL = np.array(G2frame.HKL)
3155            table.append(row)
3156        UnitCellsTable = G2G.Table(table,rowLabels=rowLabels,colLabels=colLabels,types=Types)
3157        gridDisplay = G2G.GSGrid(G2frame.dataDisplay)
3158        gridDisplay.SetTable(UnitCellsTable, True)
3159        G2frame.dataFrame.CopyCell.Enable(True)
3160        gridDisplay.Bind(wg.EVT_GRID_CELL_LEFT_CLICK,RefreshUnitCellsGrid)
3161        gridDisplay.Bind(wg.EVT_GRID_LABEL_LEFT_DCLICK,OnSortCells)
3162        gridDisplay.SetMargins(0,0)
3163        gridDisplay.SetRowLabelSize(0)
3164        gridDisplay.AutoSizeColumns(False)
3165        for r in range(gridDisplay.GetNumberRows()):
3166            for c in range(gridDisplay.GetNumberCols()):
3167                if c == 2:
3168                    gridDisplay.SetReadOnly(r,c,isReadOnly=False)
3169                else:
3170                    gridDisplay.SetReadOnly(r,c,isReadOnly=True)
3171        mainSizer.Add(gridDisplay,0,WACV)
3172    mainSizer.Layout()   
3173    G2frame.dataDisplay.SetSizer(mainSizer)
3174    G2frame.dataDisplay.SetAutoLayout(1)
3175    G2frame.dataDisplay.SetupScrolling()
3176    Size = mainSizer.Fit(G2frame.dataFrame)
3177    Size[0] += 25
3178    G2frame.dataDisplay.SetSize(Size)
3179    G2frame.dataFrame.setSizePosLeft(Size)   
3180   
3181################################################################################
3182#####  Reflection list
3183################################################################################           
3184       
3185def UpdateReflectionGrid(G2frame,data,HKLF=False,Name=''):
3186    '''respond to selection of PWDR Reflections data tree item by displaying
3187    a table of reflections in the data window.
3188    '''
3189    Controls = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.root, 'Controls'))
3190    dMin = 0.05
3191    if 'UsrReject' in Controls:
3192        dMin = Controls['UsrReject'].get('MinD',0.05)
3193    def OnPlotHKL(event):
3194        '''Plots a layer of reflections
3195        '''
3196        phaseName = G2frame.RefList
3197        if phaseName not in ['Unknown',]:
3198            pId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Phases')
3199            phaseId =  G2gd.GetPatternTreeItemId(G2frame,pId,phaseName)
3200            General = G2frame.PatternTree.GetItemPyData(phaseId)['General']
3201            Super = General.get('Super',0)
3202            SuperVec = General.get('SuperVec',[])
3203        else:
3204            Super = 0
3205            SuperVec = []       
3206        if 'list' in str(type(data)):   #single crystal data is 2 dict in list
3207            refList = data[1]['RefList']
3208        else:                           #powder data is a dict of dicts; each same structure as SC 2nd dict
3209            refList = np.array(data[phaseName]['RefList'])
3210        FoMax = np.max(refList.T[8+Super])
3211        Hmin = np.array([int(np.min(refList.T[0])),int(np.min(refList.T[1])),int(np.min(refList.T[2]))])
3212        Hmax = np.array([int(np.max(refList.T[0])),int(np.max(refList.T[1])),int(np.max(refList.T[2]))])
3213        controls = {'Type' : 'Fo','ifFc' : True,'HKLmax' : Hmax,'HKLmin' : Hmin,
3214            'FoMax' : FoMax,'Zone' : '001','Layer' : 0,'Scale' : 1.0,'Super':Super,'SuperVec':SuperVec}
3215        G2plt.PlotSngl(G2frame,newPlot=True,Data=controls,hklRef=refList,Title=phaseName)
3216       
3217    def OnPlot3DHKL(event):
3218        '''Plots the reflections in 3D
3219        '''
3220        phaseName = G2frame.RefList
3221        if phaseName not in ['Unknown',]:
3222            pId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Phases')
3223            phaseId =  G2gd.GetPatternTreeItemId(G2frame,pId,phaseName)
3224            General = G2frame.PatternTree.GetItemPyData(phaseId)['General']
3225            Super = General.get('Super',0)
3226            SuperVec = General.get('SuperVec',[])
3227        else:
3228            Super = 0
3229            SuperVec = []       
3230        if 'list' in str(type(data)):   #single crystal data is 2 dict in list
3231            refList = data[1]['RefList']
3232        else:                           #powder data is a dict of dicts; each same structure as SC 2nd dict
3233            refList = np.array(data[phaseName]['RefList'])
3234        refList.T[3+Super] = np.where(refList.T[4+Super]<dMin,-refList.T[3+Super],refList.T[3+Super])
3235        FoMax = np.max(refList.T[8+Super])
3236        Hmin = np.array([int(np.min(refList.T[0])),int(np.min(refList.T[1])),int(np.min(refList.T[2]))])
3237        Hmax = np.array([int(np.max(refList.T[0])),int(np.max(refList.T[1])),int(np.max(refList.T[2]))])
3238        Vpoint = np.array([int(np.mean(refList.T[0])),int(np.mean(refList.T[1])),int(np.mean(refList.T[2]))])
3239        controls = {'Type':'Fosq','Iscale':False,'HKLmax':Hmax,'HKLmin':Hmin,'Zone':False,'viewKey':'L',
3240            'FoMax' : FoMax,'Scale' : 1.0,'Drawing':{'viewPoint':[Vpoint,[]],'default':Vpoint[:],
3241            'backColor':[0,0,0],'depthFog':False,'Zclip':10.0,'cameraPos':10.,'Zstep':0.05,'viewUp':[0,1,0],
3242            'Scale':1.0,'oldxy':[],'viewDir':[0,0,1]},'Super':Super,'SuperVec':SuperVec}
3243        G2plt.Plot3DSngl(G2frame,newPlot=True,Data=controls,hklRef=refList,Title=phaseName)
3244       
3245    def MakeReflectionTable(phaseName):
3246        '''Returns a wx.grid table (G2G.Table) containing a list of all reflections
3247        for a phase.       
3248        '''
3249        if phaseName not in ['Unknown',]:
3250            pId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Phases')
3251            phaseId =  G2gd.GetPatternTreeItemId(G2frame,pId,phaseName)
3252            General = G2frame.PatternTree.GetItemPyData(phaseId)['General']
3253            Super = General.get('Super',0)
3254            SuperVec = General.get('SuperVec',[])
3255        else:
3256            Super = 0
3257            SuperVec = []       
3258        rowLabels = []
3259        if HKLF:
3260            refList = data[1]['RefList']
3261            refs = refList
3262        else:
3263            if len(data) > 1:
3264                G2frame.dataFrame.SelectPhase.Enable(True)
3265            try:            #patch for old reflection lists
3266                if not len(data[phaseName]):
3267                    return None
3268                refList = np.array(data[phaseName]['RefList'])
3269                I100 = refList.T[8+Super]*refList.T[11+Super]
3270            except TypeError:
3271                refList = np.array([refl[:11+Super] for refl in data[phaseName]])
3272                I100 = refList.T[8+Super]*np.array([refl[11+Super] for refl in data[phaseName]])
3273            Imax = np.max(I100)
3274            if Imax:
3275                I100 *= 100.0/Imax
3276            if 'C' in Inst['Type'][0]:
3277                refs = np.vstack((refList.T[:15+Super],I100)).T
3278            elif 'T' in Inst['Type'][0]:
3279                refs = np.vstack((refList.T[:18+Super],I100)).T
3280            G2frame.HKL = np.vstack((refList.T[:6+Super])).T    #build for plots
3281        rowLabels = [str(i) for i in range(len(refs))]
3282        Types = (4+Super)*[wg.GRID_VALUE_LONG,]+4*[wg.GRID_VALUE_FLOAT+':10,4',]+ \
3283            2*[wg.GRID_VALUE_FLOAT+':10,2',]+[wg.GRID_VALUE_FLOAT+':10,3',]+ \
3284            [wg.GRID_VALUE_FLOAT+':10,3',]
3285        if HKLF:
3286            colLabels = ['H','K','L','twin','d','Fosq','sig','Fcsq','FoTsq','FcTsq','phase','ExtC',]
3287            if 'T' in Inst['Type'][0]:
3288                colLabels = ['H','K','L','twin','d','Fosq','sig','Fcsq','FoTsq','FcTsq','phase','ExtC','wave','tbar']
3289                Types += 2*[wg.GRID_VALUE_FLOAT+':10,3',]
3290            if Super:
3291                colLabels.insert(3,'M')
3292        else:
3293            if 'C' in Inst['Type'][0]:
3294                colLabels = ['H','K','L','mul','d','pos','sig','gam','Fosq','Fcsq','phase','Icorr','Prfo','Trans','ExtP','I100']
3295                Types += 4*[wg.GRID_VALUE_FLOAT+':10,3',]
3296            elif 'T' in Inst['Type'][0]:
3297                colLabels = ['H','K','L','mul','d','pos','sig','gam','Fosq','Fcsq','phase','Icorr','alp','bet','wave','Prfo','Abs','Ext','I100']
3298                Types += 7*[wg.GRID_VALUE_FLOAT+':10,3',]
3299            if Super:
3300                colLabels.insert(3,'M')
3301        refs.T[3+Super] = np.where(refs.T[4+Super]<dMin,-refs.T[3+Super],refs.T[3+Super])
3302        return G2G.Table(refs,rowLabels=rowLabels,colLabels=colLabels,types=Types)
3303
3304    def ShowReflTable(phaseName):
3305        '''Posts a table of reflections for a phase, creating the table
3306        if needed using MakeReflectionTable
3307        '''
3308        def setBackgroundColors(im,it):
3309            for r in range(G2frame.refTable[phaseName].GetNumberRows()):
3310                if HKLF:
3311                    if float(G2frame.refTable[phaseName].GetCellValue(r,3+im)) <= 0.:
3312                        G2frame.refTable[phaseName].SetCellBackgroundColour(r,3+im,wx.RED)
3313                    Fosq = float(G2frame.refTable[phaseName].GetCellValue(r,5+im))
3314                    Fcsq = float(G2frame.refTable[phaseName].GetCellValue(r,7+im))
3315                    sig = float(G2frame.refTable[phaseName].GetCellValue(r,6+im))
3316                    rat = abs(Fosq-Fcsq)/sig
3317                    if  rat > 10.:
3318                        G2frame.refTable[phaseName].SetCellBackgroundColour(r,7+im,wx.RED)
3319                    elif rat > 3.0:
3320                        G2frame.refTable[phaseName].SetCellBackgroundColour(r,7+im,wx.Colour(255,255,0))
3321#                    else:
3322#                        G2frame.refTable[phaseName].SetCellBackgroundColour(r,7+im,wx.WHITE)
3323                else:   #PWDR
3324                    if float(G2frame.refTable[phaseName].GetCellValue(r,12+im+itof)) < 0.:
3325                        G2frame.refTable[phaseName].SetCellBackgroundColour(r,12+im+itof,wx.RED)
3326                    if float(G2frame.refTable[phaseName].GetCellValue(r,3+im)) < 0:
3327                        G2frame.refTable[phaseName].SetCellBackgroundColour(r,8+im,wx.RED)
3328                       
3329                                                 
3330        G2frame.RefList = phaseName
3331        G2frame.dataFrame.SetLabel('Reflection List for '+phaseName)
3332        if HKLF:
3333            Status.SetStatusText('abs(DF)/sig > 10 red; > 3 yellow; twin < 0 (user rejected) red; twin=0 (sp. gp. absent) red')
3334        else:
3335            Status.SetStatusText('Prfo < 0. in red; if excluded Fosq in red & mul < 0')
3336        itof = 0
3337        if HKLF:
3338            im = data[1].get('Super',0)
3339        else:
3340            if 'T' in data[phaseName].get('Type',''):
3341                itof = 3
3342            im = data[phaseName].get('Super',0)
3343        # has this table already been displayed?
3344        if G2frame.refTable[phaseName].GetTable() is None:
3345            PeakTable = MakeReflectionTable(phaseName)
3346            G2frame.refTable[phaseName].SetTable(PeakTable, True)
3347            G2frame.refTable[phaseName].EnableEditing(False)
3348            G2frame.refTable[phaseName].SetMargins(0,0)
3349            G2frame.refTable[phaseName].AutoSizeColumns(False)
3350            setBackgroundColors(im,itof)
3351        # raise the tab (needed for 1st use and from OnSelectPhase)
3352        for PageNum in range(G2frame.dataDisplay.GetPageCount()):
3353            if phaseName == G2frame.dataDisplay.GetPageText(PageNum):
3354                G2frame.dataDisplay.SetSelection(PageNum)
3355                break
3356        else:
3357            print phaseName
3358            print phases
3359            raise Exception("how did we not find a phase name?")
3360       
3361    def OnPageChanged(event):
3362        '''Respond to a press on a phase tab by displaying the reflections. This
3363        routine is needed because the reflection table may not have been created yet.
3364        '''
3365        page = event.GetSelection()
3366        phaseName = G2frame.dataDisplay.GetPageText(page)
3367        ShowReflTable(phaseName)
3368
3369    def OnSelectPhase(event):
3370        '''For PWDR, selects a phase with a selection box. Called from menu.
3371        '''
3372        if len(phases) < 2: return
3373        dlg = wx.SingleChoiceDialog(G2frame,'Select','Phase',phases)
3374        try:
3375            if dlg.ShowModal() == wx.ID_OK:
3376                sel = dlg.GetSelection()
3377                ShowReflTable(phases[sel])
3378        finally:
3379            dlg.Destroy()
3380           
3381    if not data:
3382        print 'No phases, no reflections'
3383        return
3384    if HKLF:
3385        G2frame.RefList = 1
3386        phaseName = IsHistogramInAnyPhase(G2frame,Name)
3387        if not phaseName:
3388            phaseName = 'Unknown'
3389        phases = [phaseName]
3390    else:
3391        phaseName = G2frame.RefList
3392        phases = data.keys()
3393    if G2frame.dataDisplay:
3394        G2frame.dataFrame.Clear()
3395    Inst = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Instrument Parameters'))[0]
3396    if HKLF:
3397        G2gd.SetDataMenuBar(G2frame)
3398        G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.ReflMenu)
3399        if not G2frame.dataFrame.GetStatusBar():
3400            Status = G2frame.dataFrame.CreateStatusBar()   
3401        G2frame.Bind(wx.EVT_MENU, OnPlotHKL, id=G2gd.wxID_PWDHKLPLOT)
3402        G2frame.Bind(wx.EVT_MENU, OnPlot3DHKL, id=G2gd.wxID_PWD3DHKLPLOT)
3403        G2frame.dataFrame.SelectPhase.Enable(False)
3404    else:
3405        G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.ReflMenu)
3406        if not G2frame.dataFrame.GetStatusBar():
3407            Status = G2frame.dataFrame.CreateStatusBar()   
3408        G2frame.Bind(wx.EVT_MENU, OnSelectPhase, id=G2gd.wxID_SELECTPHASE)
3409        G2frame.Bind(wx.EVT_MENU, OnPlotHKL, id=G2gd.wxID_PWDHKLPLOT)
3410        G2frame.Bind(wx.EVT_MENU, OnPlot3DHKL, id=G2gd.wxID_PWD3DHKLPLOT)
3411        G2frame.dataFrame.SelectPhase.Enable(False)
3412           
3413    G2frame.dataDisplay = G2G.GSNoteBook(parent=G2frame.dataFrame,size=G2frame.dataFrame.GetClientSize())
3414    G2frame.refTable = {}
3415    for tabnum,phase in enumerate(phases):
3416        G2frame.refTable[phase] = G2G.GSGrid(parent=G2frame.dataDisplay)
3417        G2frame.dataDisplay.AddPage(G2frame.refTable[phase],phase)
3418#    if phaseName not in G2frame.refTable:
3419#        print phaseName
3420#        print phases
3421#        raise Exception("how did we get a invalid phase name?")   
3422    ShowReflTable(phaseName)
3423#    G2frame.refTable[phaseName].Fit()   #slow!!
3424#    size = G2frame.refTable[phaseName].GetSize()
3425#    G2frame.dataFrame.setSizePosLeft([size[0]+32,350])
3426    G2frame.dataFrame.setSizePosLeft([550,350])
3427    G2frame.dataDisplay.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CHANGED, OnPageChanged)
3428   
3429################################################################################
3430#####  SASD Substances
3431################################################################################
3432           
3433def UpdateSubstanceGrid(G2frame,data):
3434    '''respond to selection of SASD Substance data tree item.
3435    '''
3436    import Substances as substFile
3437   
3438    def OnLoadSubstance(event):
3439        names = substFile.Substances.keys()
3440        names.sort()
3441        dlg = wx.SingleChoiceDialog(G2frame, 'Which substance?', 'Select substance', names, wx.CHOICEDLG_STYLE)
3442        try:
3443            if dlg.ShowModal() == wx.ID_OK:
3444                name = names[dlg.GetSelection()]
3445            else:
3446                return
3447        finally:
3448            dlg.Destroy()
3449        data['Substances'][name] = {'Elements':{},'Volume':1.0,'Density':1.0,
3450            'Scatt density':0.0,'XAnom density':0.0,'XAbsorption':0.0}
3451        subst = substFile.Substances[name]
3452        ElList = subst['Elements'].keys()
3453        for El in ElList:
3454            Info = G2elem.GetAtomInfo(El.strip().capitalize())
3455            Info.update(subst['Elements'][El])
3456            data['Substances'][name]['Elements'][El] = Info
3457            if 'Volume' in subst:
3458                data['Substances'][name]['Volume'] = subst['Volume']
3459                data['Substances'][name]['Density'] = \
3460                    G2mth.Vol2Den(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])
3461            elif 'Density' in subst:
3462                data['Substances'][name]['Density'] = subst['Density']
3463                data['Substances'][name]['Volume'] = \
3464                    G2mth.Den2Vol(data['Substances'][name]['Elements'],data['Substances'][name]['Density'])
3465            else:
3466                data['Substances'][name]['Volume'] = G2mth.El2EstVol(data['Substances'][name]['Elements'])
3467                data['Substances'][name]['Density'] = \
3468                    G2mth.Vol2Den(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])
3469            data['Substances'][name]['Scatt density'] = \
3470                G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])[0]
3471            contrst,absorb = G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'],wave)         
3472            data['Substances'][name]['XAnom density'] = contrst
3473            data['Substances'][name]['XAbsorption'] = absorb
3474                         
3475        UpdateSubstanceGrid(G2frame,data)
3476       
3477    def OnCopySubstance(event):
3478        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
3479        histList = GetHistsLikeSelected(G2frame)
3480        if not histList:
3481            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
3482            return
3483        copyList = []
3484        dlg = G2G.G2MultiChoiceDialog(
3485            G2frame.dataFrame, 
3486            'Copy substances from\n'+hst[5:]+' to...',
3487            'Copy substances', histList)
3488        try:
3489            if dlg.ShowModal() == wx.ID_OK:
3490                for i in dlg.GetSelections(): 
3491                    copyList.append(histList[i])
3492        finally:
3493            dlg.Destroy()       
3494        for item in copyList:
3495            Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
3496            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Substances'),
3497                copy.copy(data))
3498   
3499    def OnAddSubstance(event):
3500        dlg = wx.TextEntryDialog(None,'Enter a name for this substance','Substance Name Entry','New substance',
3501            style=wx.OK)
3502        if dlg.ShowModal() == wx.ID_OK:
3503            Name = dlg.GetValue()
3504            data['Substances'][Name] = {'Elements':{},'Volume':1.0,'Density':1.0,
3505                'Scatt density':0.0,'XAnom density':0.,'XAbsorption':0.}
3506        dlg.Destroy()
3507        AddElement(Name)
3508        UpdateSubstanceGrid(G2frame,data)
3509       
3510    def OnDeleteSubstance(event):
3511        TextList = []
3512        for name in data['Substances']:
3513            if name != 'vacuum':
3514                TextList += [name,]
3515        if not TextList:
3516            return
3517        dlg = wx.SingleChoiceDialog(G2frame, 'Which substance?', 'Select substance to delete', TextList, wx.CHOICEDLG_STYLE)
3518        try:
3519            if dlg.ShowModal() == wx.ID_OK:
3520                name = TextList[dlg.GetSelection()]
3521            else:
3522                return
3523        finally:
3524            dlg.Destroy()
3525        del(data['Substances'][name])
3526        UpdateSubstanceGrid(G2frame,data)       
3527               
3528    def OnAddElement(event):       
3529        TextList = []
3530        for name in data['Substances']:
3531            if name != 'vacuum':
3532                TextList += [name,]
3533        if not TextList:
3534            return
3535        dlg = wx.SingleChoiceDialog(G2frame, 'Which substance?', 'Select substance', TextList, wx.CHOICEDLG_STYLE)
3536        try:
3537            if dlg.ShowModal() == wx.ID_OK:
3538                name = TextList[dlg.GetSelection()]
3539            else:
3540                return
3541        finally:
3542            dlg.Destroy()
3543        AddElement(name)
3544        UpdateSubstanceGrid(G2frame,data)
3545       
3546    def AddElement(name):
3547        ElList = data['Substances'][name]['Elements'].keys()
3548        dlg = G2elemGUI.PickElements(G2frame,ElList)
3549        if dlg.ShowModal() == wx.ID_OK:
3550            for El in dlg.Elem:
3551                El = El.strip().capitalize()
3552                Info = G2elem.GetAtomInfo(El)
3553                Info.update({'Num':1})
3554                data['Substances'][name]['Elements'][El] = Info
3555                data['Substances'][name]['Volume'] = G2mth.El2EstVol(data['Substances'][name]['Elements'])
3556                data['Substances'][name]['Density'] = \
3557                    G2mth.Vol2Den(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])
3558                data['Substances'][name]['Scatt density'] = \
3559                    G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])[0]
3560                contrst,absorb = G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'],wave)         
3561                data['Substances'][name]['XAnom density'] = contrst
3562                data['Substances'][name]['XAbsorption'] = absorb
3563        dlg.Destroy()
3564       
3565    def OnDeleteElement(event):
3566        TextList = []
3567        for name in data['Substances']:
3568            if name != 'vacuum':
3569                TextList += [name,]
3570        if not TextList:
3571            return
3572        dlg = wx.SingleChoiceDialog(G2frame, 'Which substance?', 'Select substance', TextList, wx.CHOICEDLG_STYLE)
3573        try:
3574            if dlg.ShowModal() == wx.ID_OK:
3575                name = TextList[dlg.GetSelection()]
3576            else:
3577                return
3578        finally:
3579            dlg.Destroy()
3580        ElList = data['Substances'][name]['Elements'].keys()
3581        if len(ElList):
3582            DE = G2elemGUI.DeleteElement(G2frame,ElList)
3583            if DE.ShowModal() == wx.ID_OK:
3584                El = DE.GetDeleteElement().strip().upper()
3585                del(data['Substances'][name]['Elements'][El])
3586                data['Substances'][name]['Volume'] = G2mth.El2EstVol(data['Substances'][name]['Elements'])
3587                data['Substances'][name]['Density'] = \
3588                    G2mth.Vol2Den(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])
3589                data['Substances'][name]['Scatt density'] = \
3590                    G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])[0]
3591                contrst,absorb = G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'],wave)         
3592                data['Substances'][name]['XAnom density'] = contrst
3593                data['Substances'][name]['XAbsorption'] = absorb
3594        UpdateSubstanceGrid(G2frame,data)
3595               
3596    def SubstSizer():
3597       
3598        def OnValueChange(event):
3599            Obj = event.GetEventObject()
3600            if len(Indx[Obj.GetId()]) == 3:
3601                name,El,keyId = Indx[Obj.GetId()]
3602                try:
3603                    value = max(0,float(Obj.GetValue()))
3604                except ValueError:
3605                    value = 0
3606                    Obj.SetValue('%.2f'%(value))
3607                data['Substances'][name]['Elements'][El][keyId] = value
3608                data['Substances'][name]['Volume'] = G2mth.El2EstVol(data['Substances'][name]['Elements'])
3609                data['Substances'][name]['Density'] = \
3610                    G2mth.Vol2Den(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])
3611            else:
3612                name,keyId = Indx[Obj.GetId()]
3613                try:
3614                    value = max(0,float(Obj.GetValue()))
3615                except ValueError:
3616                    value = 1.0
3617                data['Substances'][name][keyId] = value
3618                if keyId in 'Volume':
3619                    data['Substances'][name]['Density'] = \
3620                        G2mth.Vol2Den(data['Substances'][name]['Elements'],value)
3621                elif keyId in 'Density':
3622                    data['Substances'][name]['Volume'] = \
3623                        G2mth.Den2Vol(data['Substances'][name]['Elements'],value)
3624            data['Substances'][name]['Scatt density'] = \
3625                G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])[0]
3626            contrst,absorb = G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'],wave)         
3627            data['Substances'][name]['XAnom density'] = contrst
3628            data['Substances'][name]['XAbsorption'] = absorb
3629            wx.CallAfter(UpdateSubstanceGrid,G2frame,data)
3630       
3631        Indx = {}
3632        substSizer = wx.BoxSizer(wx.VERTICAL)
3633        substSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Substance list: wavelength: %.5fA'%(wave)),
3634            0,WACV)
3635        for name in data['Substances']:
3636            G2G.HorizontalLine(substSizer,G2frame.dataDisplay)   
3637            substSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Data for '+name+':'),
3638                0,WACV)
3639            if name == 'vacuum':
3640                substSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label='        Not applicable'),
3641                    0,WACV)
3642            else:   
3643                elSizer = wx.FlexGridSizer(0,6,5,5)
3644                Substance = data['Substances'][name]
3645                Elems = Substance['Elements']
3646                for El in Elems:    #do elements as pull downs for isotopes for neutrons
3647                    elSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' '+El+': '),
3648                        0,WACV)
3649                    num = wx.TextCtrl(G2frame.dataDisplay,value='%.2f'%(Elems[El]['Num']),style=wx.TE_PROCESS_ENTER)
3650                    Indx[num.GetId()] = [name,El,'Num']
3651                    num.Bind(wx.EVT_TEXT_ENTER,OnValueChange)       
3652                    num.Bind(wx.EVT_KILL_FOCUS,OnValueChange)
3653                    elSizer.Add(num,0,WACV)
3654                substSizer.Add(elSizer,0)
3655                vdsSizer = wx.FlexGridSizer(0,4,5,5)
3656                vdsSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Volume: '),
3657                    0,WACV)
3658                vol = wx.TextCtrl(G2frame.dataDisplay,value='%.3f'%(Substance['Volume']),style=wx.TE_PROCESS_ENTER)
3659                Indx[vol.GetId()] = [name,'Volume']
3660                vol.Bind(wx.EVT_TEXT_ENTER,OnValueChange)       
3661                vol.Bind(wx.EVT_KILL_FOCUS,OnValueChange)
3662                vdsSizer.Add(vol,0,WACV)               
3663                vdsSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Density: '),
3664                    0,WACV)
3665                den = wx.TextCtrl(G2frame.dataDisplay,value='%.3f'%(Substance['Density']),style=wx.TE_PROCESS_ENTER)
3666                Indx[den.GetId()] = [name,'Density']
3667                den.Bind(wx.EVT_TEXT_ENTER,OnValueChange)       
3668                den.Bind(wx.EVT_KILL_FOCUS,OnValueChange)
3669                vdsSizer.Add(den,0,WACV)
3670                substSizer.Add(vdsSizer,0)
3671                substSizer.Add(wx.StaticText(G2frame.dataDisplay,
3672                    label=' Scattering density  : %.2f *10%scm%s'%(Substance['Scatt density'],Pwr10,Pwrm2)),
3673                    0,WACV)               
3674                substSizer.Add(wx.StaticText(G2frame.dataDisplay,       #allow neutrons here into NAnom density & NAbsorption
3675                    label=' Anomalous density : %.2f *10%scm%s'%(Substance['XAnom density'],Pwr10,Pwrm2)),
3676                    0,WACV)               
3677                substSizer.Add(wx.StaticText(G2frame.dataDisplay,
3678                    label=' X-ray absorption   : %.2f cm%s'%(Substance['XAbsorption'],Pwrm1)),
3679                    0,WACV)               
3680        return substSizer
3681           
3682    Inst = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Instrument Parameters'))[0]
3683    wave = G2mth.getWave(Inst)
3684    if G2frame.dataDisplay:
3685        G2frame.dataFrame.DestroyChildren()  # is this a ScrolledWindow? If so, bad!
3686    G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.SubstanceMenu)
3687    if not G2frame.dataFrame.GetStatusBar():
3688        Status = G2frame.dataFrame.CreateStatusBar()
3689    G2frame.dataDisplay = wxscroll.ScrolledPanel(G2frame.dataFrame)
3690    G2frame.dataFrame.SetLabel('Substances')
3691    G2frame.dataFrame.Bind(wx.EVT_MENU, OnLoadSubstance, id=G2gd.wxID_LOADSUBSTANCE)   
3692    G2frame.dataFrame.Bind(wx.EVT_MENU, OnAddSubstance, id=G2gd.wxID_ADDSUBSTANCE)
3693    G2frame.dataFrame.Bind(wx.EVT_MENU, OnCopySubstance, id=G2gd.wxID_COPYSUBSTANCE)
3694    G2frame.dataFrame.Bind(wx.EVT_MENU, OnDeleteSubstance, id=G2gd.wxID_DELETESUBSTANCE)   
3695    G2frame.dataFrame.Bind(wx.EVT_MENU, OnAddElement, id=G2gd.wxID_ELEMENTADD)
3696    G2frame.dataFrame.Bind(wx.EVT_MENU, OnDeleteElement, id=G2gd.wxID_ELEMENTDELETE)
3697    mainSizer = wx.BoxSizer(wx.VERTICAL)
3698    mainSizer.Add(SubstSizer(),0)
3699
3700    mainSizer.Layout()   
3701    G2frame.dataDisplay.SetSizer(mainSizer)
3702    G2frame.dataDisplay.SetAutoLayout(1)
3703    G2frame.dataDisplay.SetupScrolling()
3704    Size = mainSizer.Fit(G2frame.dataFrame)
3705    Size[0] += 25
3706    G2frame.dataDisplay.SetSize(Size)
3707    G2frame.dataFrame.setSizePosLeft(Size)   
3708       
3709################################################################################
3710#####  SASD Models
3711################################################################################           
3712       
3713def UpdateModelsGrid(G2frame,data):
3714    '''respond to selection of SASD Models data tree item.
3715    '''
3716    #patches
3717    if 'Current' not in data:
3718        data['Current'] = 'Size dist.'
3719    if 'logBins' not in data['Size']:
3720        data['Size']['logBins'] = True
3721    if 'MinMaxDiam' in data['Size']:
3722        data['Size']['MinDiam'] = 50.
3723        data['Size']['MaxDiam'] = 10000.
3724        del data['Size']['MinMaxDiam']
3725    if isinstance(data['Size']['MaxEnt']['Sky'],float):
3726        data['Size']['MaxEnt']['Sky'] = -3
3727    if 'Power' not in data['Size']['IPG']:
3728        data['Size']['IPG']['Power'] = -1
3729    if 'Matrix' not in data['Particle']:
3730        data['Particle']['Matrix'] = {'Name':'vacuum','VolFrac':[0.0,False]}
3731    if 'BackFile' not in data:
3732        data['BackFile'] = ''
3733    #end patches
3734   
3735    def RefreshPlots(newPlot=False):
3736        PlotText = G2frame.G2plotNB.nb.GetPageText(G2frame.G2plotNB.nb.GetSelection())
3737        if 'Powder' in PlotText:
3738            G2plt.PlotPatterns(G2frame,plotType='SASD',newPlot=newPlot)
3739        elif 'Size' in PlotText:
3740            G2plt.PlotSASDSizeDist(G2frame)
3741               
3742    def OnAddModel(event):
3743        if data['Current'] == 'Particle fit':
3744            material = 'vacuum'
3745            if len(data['Particle']['Levels']):
3746                material = data['Particle']['Levels'][-1]['Controls']['Material']
3747            data['Particle']['Levels'].append({
3748                'Controls':{'FormFact':'Sphere','DistType':'LogNormal','Material':material,
3749                    'FFargs':{},'SFargs':{},'NumPoints':50,'Cutoff':0.01,'Contrast':0.0,
3750                    'SlitSmear':[0.0,False],'StrFact':'Dilute'},    #last 2 not used - future?
3751                'LogNormal':{'Volume':[0.05,False],'Mean':[1000.,False],'StdDev':[0.5,False],'MinSize':[10.,False],},
3752                'Gaussian':{'Volume':[0.05,False],'Mean':[1000.,False],'StdDev':[300.,False],},
3753                'LSW':{'Volume':[0.05,False],'Mean':[1000.0,False],},
3754                'Schulz-Zimm':{'Volume':[0.05,False],'Mean':[1000.,False],'StdDev':[300.,False],},
3755                'Unified':{'G':[1.e3,False],'Rg':[100,False],'B':[1.e-5,False],'P':[4,False],'Cutoff':[1e-5,False],},
3756                'Porod':{'B':[1.e-4,False],'P':[4,False],'Cutoff':[1e-5,False],},
3757                'Monodisperse':{'Volume':[0.05,False],'Radius':[100,False],},   #OK for spheres
3758                'Bragg':{'PkInt':[100,False],'PkPos':[0.2,False],
3759                    'PkSig':[10,False],'PkGam':[10,False],},        #reasonable 31A peak
3760                })
3761            G2sasd.ModelFxn(Profile,ProfDict,Limits,Sample,data)
3762            RefreshPlots(True)
3763                   
3764        wx.CallAfter(UpdateModelsGrid,G2frame,data)
3765       
3766    def OnCopyModel(event):
3767        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
3768        histList = GetHistsLikeSelected(G2frame)
3769        if not histList:
3770            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
3771            return
3772        copyList = []
3773        dlg = G2G.G2MultiChoiceDialog(
3774            G2frame.dataFrame, 
3775            'Copy models from\n'+hst[5:]+' to...',
3776            'Copy models', histList)
3777        try:
3778            if dlg.ShowModal() == wx.ID_OK:
3779                for i in dlg.GetSelections(): 
3780                    copyList.append(histList[i])
3781        finally:
3782            dlg.Destroy()       
3783        for item in copyList:
3784            Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
3785            newdata = copy.deepcopy(data)
3786            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Models'),newdata)
3787            if newdata['BackFile']:
3788                Profile = G2frame.PatternTree.GetItemPyData(Id)[1]
3789                BackId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,newdata['BackFile'])
3790                BackSample = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,BackId, 'Sample Parameters'))
3791                Profile[5] = BackSample['Scale'][0]*G2frame.PatternTree.GetItemPyData(BackId)[1][1]
3792        RefreshPlots(True)
3793               
3794    def OnCopyFlags(event):
3795        thisModel = copy.deepcopy(data)
3796        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
3797        histList = GetHistsLikeSelected(G2frame)
3798        if not histList:
3799            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
3800            return
3801        dlg = G2G.G2MultiChoiceDialog(
3802            G2frame.dataFrame, 
3803            'Copy sample ref. flags from\n'+str(hst[5:])+' to...',
3804            'Copy sample flags', histList)
3805        distChoice = ['LogNormal','Gaussian','LSW','Schulz-Zimm','Bragg','Unified',
3806            'Porod','Monodisperse',]
3807        parmOrder = ['Volume','Radius','Mean','StdDev','G','Rg','B','P',
3808            'Cutoff','PkInt','PkPos','PkSig','PkGam','VolFr','Dist',]
3809        try:
3810            if dlg.ShowModal() == wx.ID_OK:
3811                result = dlg.GetSelections()
3812                for i in result: 
3813                    item = histList[i]
3814                    Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
3815                    newModel = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Models'))
3816                    newModel['Back'][1] = copy.copy(thisModel['Back'][1])
3817                    for ilev,level in enumerate(newModel['Particle']['Levels']):
3818                        for form in level:
3819                            if form in distChoice:
3820                                thisForm = thisModel['Particle']['Levels'][ilev][form]                               
3821                                for item in parmOrder:
3822                                    if item in thisForm:
3823                                       level[form][item][1] = copy.copy(thisForm[item][1])
3824                            elif form == 'Controls':
3825                                thisForm = thisModel['Particle']['Levels'][ilev][form]['SFargs']
3826                                for item in parmOrder:
3827                                    if item in thisForm:
3828                                        level[form]['SFargs'][item][1] = copy.copy(thisForm[item][1])
3829        finally:
3830            dlg.Destroy()
3831               
3832    def OnFitModelAll(event):
3833        choices = G2gd.GetPatternTreeDataNames(G2frame,['SASD',])
3834        sel = []
3835        dlg = G2G.G2MultiChoiceDialog(G2frame.dataFrame, 'Sequential SASD refinement',
3836             'Select dataset to include',choices)
3837        dlg.SetSelections(sel)
3838        names = []
3839        if dlg.ShowModal() == wx.ID_OK:
3840            for sel in dlg.GetSelections():
3841                names.append(choices[sel])
3842        dlg.Destroy()
3843        SeqResult = {'histNames':names}
3844        Reverse = False
3845        CopyForward = False
3846        choice = ['Reverse sequence','Copy from prev.']
3847        dlg = wx.MultiChoiceDialog(G2frame.dataFrame,'Sequential controls','Select controls',choice)
3848        if dlg.ShowModal() == wx.ID_OK:
3849            for sel in dlg.GetSelections():
3850                if sel:
3851                    CopyForward = True
3852                else:
3853                    Reverse = True
3854        dlg.Destroy()
3855        dlg = wx.ProgressDialog('SASD Sequential fit','Data set name = '+names[0],len(names), 
3856            style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE|wx.PD_REMAINING_TIME|wx.PD_CAN_ABORT)
3857        wx.BeginBusyCursor()
3858        if Reverse:
3859            names.reverse()
3860        try:
3861            for i,name in enumerate(names):
3862                print ' Sequential fit for ',name
3863                GoOn = dlg.Update(i,newmsg='Data set name = '+name)[0]
3864                if not GoOn:
3865                    break
3866                Id =  G2gd.GetPatternTreeItemId(G2frame,G2frame.root,name)
3867                if i and CopyForward:
3868                    G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Models'),JModel)
3869                IProfDict,IProfile = G2frame.PatternTree.GetItemPyData(Id)[:2]
3870                IModel = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Models'))
3871                ISample = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Sample Parameters'))
3872                ILimits = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Limits'))
3873                IfOK,result,varyList,sig,Rvals,covMatrix,parmDict,Msg = G2sasd.ModelFit(IProfile,IProfDict,ILimits,ISample,IModel)
3874                JModel = copy.deepcopy(IModel)
3875                if not IfOK:
3876                    G2frame.ErrorDialog('Failed sequential refinement for data '+name,
3877                        ' Msg: '+Msg+'\nYou need to rethink your selection of parameters\n'+    \
3878                        ' Model restored to previous version for'+name)
3879                    SeqResult['histNames'] = names[:i]
3880                    dlg.Destroy()
3881                    break
3882                else:
3883                    G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Models'),copy.deepcopy(IModel))
3884               
3885                G2sasd.ModelFxn(IProfile,IProfDict,ILimits,ISample,IModel)
3886                SeqResult[name] = {'variables':result[0],'varyList':varyList,'sig':sig,'Rvals':Rvals,
3887                    'covMatrix':covMatrix,'title':name,'parmDict':parmDict}
3888            else:
3889                dlg.Destroy()
3890                print ' ***** Small angle sequential refinement successful *****'
3891        finally:
3892            wx.EndBusyCursor()   
3893        Id =  G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Sequential results')
3894        if Id:
3895            G2frame.PatternTree.SetItemPyData(Id,SeqResult)
3896        else:
3897            Id = G2frame.PatternTree.AppendItem(parent=G2frame.root,text='Sequential results')
3898            G2frame.PatternTree.SetItemPyData(Id,SeqResult)
3899        G2frame.PatternTree.SelectItem(Id)
3900       
3901    def OnFitModel(event):
3902        if data['Current'] == 'Size dist.':
3903            if not any(Sample['Contrast']):
3904                G2frame.ErrorDialog('No contrast; your sample is a vacuum!',
3905                    'You need to define a scattering substance!\n'+    \
3906                    ' Do Substances and then Sample parameters')
3907                return
3908            G2sasd.SizeDistribution(Profile,ProfDict,Limits,Sample,data)
3909            G2plt.PlotSASDSizeDist(G2frame)
3910            RefreshPlots(True)
3911           
3912        elif data['Current'] == 'Particle fit':
3913            SaveState()
3914            Results = G2sasd.ModelFit(Profile,ProfDict,Limits,Sample,data)
3915            if not Results[0]:
3916                    G2frame.ErrorDialog('Failed refinement',
3917                        ' Msg: '+Results[-1]+'\nYou need to rethink your selection of parameters\n'+    \
3918                        ' Model restored to previous version')
3919            G2sasd.ModelFxn(Profile,ProfDict,Limits,Sample,data)
3920            RefreshPlots(True)
3921            wx.CallAfter(UpdateModelsGrid,G2frame,data)
3922           
3923    def OnUnDo(event):
3924        DoUnDo()
3925        data = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,
3926            G2frame.PatternId,'Models'))
3927        G2frame.dataFrame.SasdUndo.Enable(False)
3928        UpdateModelsGrid(G2frame,data)
3929        G2sasd.ModelFxn(Profile,ProfDict,Limits,Sample,data)
3930        RefreshPlots(True)
3931
3932    def DoUnDo():
3933        print 'Undo last refinement'
3934        file = open(G2frame.undosasd,'rb')
3935        PatternId = G2frame.PatternId
3936        G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Models'),cPickle.load(file))
3937        print ' Models recovered'
3938        file.close()
3939       
3940    def SaveState():
3941        G2frame.undosasd = os.path.join(G2frame.dirname,'GSASIIsasd.save')
3942        file = open(G2frame.undosasd,'wb')
3943        PatternId = G2frame.PatternId
3944        for item in ['Models']:
3945            cPickle.dump(G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId,item)),file,1)
3946        file.close()
3947        G2frame.dataFrame.SasdUndo.Enable(True)
3948       
3949    def OnSelectFit(event):
3950        data['Current'] = fitSel.GetValue()
3951        wx.CallAfter(UpdateModelsGrid,G2frame,data)
3952       
3953    def OnCheckBox(event):
3954        Obj = event.GetEventObject()
3955        item,ind = Indx[Obj.GetId()]
3956        item[ind] = Obj.GetValue()
3957       
3958    def OnIntVal(event):
3959        Obj = event.GetEventObject()
3960        item,ind,minVal = Indx[Obj.GetId()]
3961        try:
3962            value = int(Obj.GetValue())
3963            if value <= minVal:
3964                raise ValueError
3965        except ValueError:
3966            value = item[ind]
3967        Obj.SetValue(str(value))
3968        item[ind] = value
3969
3970    def SizeSizer():
3971       
3972        def OnShape(event):
3973            data['Size']['Shape'][0] = partsh.GetValue()
3974            wx.CallAfter(UpdateModelsGrid,G2frame,data)
3975           
3976        def OnMethod(event):
3977            data['Size']['Method'] = method.GetValue()
3978            wx.CallAfter(UpdateModelsGrid,G2frame,data)
3979           
3980        def OnPartVal(event):
3981            try:
3982                val = max(0.0,float(partprm.GetValue()))
3983            except ValueError:
3984                val = 1
3985            data['Size']['Shape'][1] = val
3986            partprm.SetValue('%.3f'%(val))
3987           
3988        sizeSizer = wx.BoxSizer(wx.VERTICAL)
3989        sizeSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Size distribution parameters: '),0,WACV)
3990        binSizer = wx.FlexGridSizer(0,7,5,5)
3991        binSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' No. size bins: '),0,WACV)
3992        bins = ['50','100','150','200']
3993        nbins = wx.ComboBox(G2frame.dataDisplay,value=str(data['Size']['Nbins']),choices=bins,
3994            style=wx.CB_READONLY|wx.CB_DROPDOWN)
3995        Indx[nbins.GetId()] = [data['Size'],'Nbins',0]
3996        nbins.Bind(wx.EVT_COMBOBOX,OnIntVal)       
3997        binSizer.Add(nbins,0,WACV)
3998        binSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Min diam.: '),0,WACV)
3999        minDias = ['10','25','50','100','150','200']
4000        mindiam = wx.ComboBox(G2frame.dataDisplay,value=str(data['Size']['MinDiam']),choices=minDias,
4001            style=wx.CB_DROPDOWN)
4002        mindiam.Bind(wx.EVT_LEAVE_WINDOW,OnIntVal)
4003        mindiam.Bind(wx.EVT_TEXT_ENTER,OnIntVal)       
4004        mindiam.Bind(wx.EVT_KILL_FOCUS,OnIntVal)
4005        Indx[mindiam.GetId()] = [data['Size'],'MinDiam',0]
4006        binSizer.Add(mindiam,0,WACV)
4007        binSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Max diam.: '),0,WACV)
4008        maxDias = [str(1000*(i+1)) for i in range(10)]
4009        maxdiam = wx.ComboBox(G2frame.dataDisplay,value=str(data['Size']['MaxDiam']),choices=maxDias,
4010            style=wx.CB_DROPDOWN)
4011        maxdiam.Bind(wx.EVT_LEAVE_WINDOW,OnIntVal)
4012        maxdiam.Bind(wx.EVT_TEXT_ENTER,OnIntVal)       
4013        maxdiam.Bind(wx.EVT_KILL_FOCUS,OnIntVal)
4014        Indx[maxdiam.GetId()] = [data['Size'],'MaxDiam',0]
4015        binSizer.Add(maxdiam,0,WACV)
4016        logbins = wx.CheckBox(G2frame.dataDisplay,label='Log bins?')
4017        Indx[logbins.GetId()] = [data['Size'],'logBins']
4018        logbins.SetValue(data['Size']['logBins'])
4019        logbins.Bind(wx.EVT_CHECKBOX, OnCheckBox)
4020        binSizer.Add(logbins,0,WACV)
4021        sizeSizer.Add(binSizer,0)
4022        sizeSizer.Add((5,5),0)
4023        partSizer = wx.BoxSizer(wx.HORIZONTAL)
4024        partSizer.Add(wx.StaticText(G2frame.dataDisplay,label='Particle description: '),0,WACV)
4025        shapes = {'Spheroid':' Aspect ratio: ','Cylinder':' Diameter ','Cylinder AR':' Aspect ratio: ',
4026            'Unified sphere':'','Unified rod':' Diameter: ','Unified rod AR':' Aspect ratio: ',
4027            'Unified disk':' Thickness: '}
4028        partsh = wx.ComboBox(G2frame.dataDisplay,value=str(data['Size']['Shape'][0]),choices=shapes.keys(),
4029            style=wx.CB_READONLY|wx.CB_DROPDOWN)
4030        partsh.Bind(wx.EVT_COMBOBOX,OnShape)       
4031        partSizer.Add(partsh,0,WACV)
4032        if data['Size']['Shape'][0] not in ['Unified sphere',]:
4033            partSizer.Add(wx.StaticText(G2frame.dataDisplay,label=shapes[data['Size']['Shape'][0]]),0,WACV)
4034            partprm = wx.TextCtrl(G2frame.dataDisplay,value='%.3f'%(data['Size']['Shape'][1]),
4035                style=wx.TE_PROCESS_ENTER)
4036            partprm.Bind(wx.EVT_TEXT_ENTER,OnPartVal)       
4037            partprm.Bind(wx.EVT_KILL_FOCUS,OnPartVal)
4038            partSizer.Add(partprm,0,WACV)
4039        sizeSizer.Add(partSizer,0)
4040        sizeSizer.Add((5,5),0)
4041        fitSizer = wx.BoxSizer(wx.HORIZONTAL)
4042        methods = ['MaxEnt','IPG',]
4043        fitSizer.Add(wx.StaticText(G2frame.dataDisplay,label='Fitting method: '),0,WACV)
4044        method = wx.ComboBox(G2frame.dataDisplay,value=data['Size']['Method'],choices=methods,
4045            style=wx.CB_READONLY|wx.CB_DROPDOWN)
4046        method.Bind(wx.EVT_COMBOBOX,OnMethod)
4047        fitSizer.Add(method,0,WACV)
4048        iters = ['10','25','50','100','150','200']       
4049        fitSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' No. iterations: '),0,WACV)
4050        Method = data['Size']['Method']
4051        iter = wx.ComboBox(G2frame.dataDisplay,value=str(data['Size'][Method]['Niter']),choices=iters,
4052            style=wx.CB_READONLY|wx.CB_DROPDOWN)
4053        Indx[iter.GetId()] = [data['Size'][Method],'Niter',0]
4054        iter.Bind(wx.EVT_COMBOBOX,OnIntVal)
4055        fitSizer.Add(iter,0,WACV)
4056        if 'MaxEnt' in data['Size']['Method']:
4057            fitSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Log floor factor: '),0,WACV)
4058            floors = [str(-i) for i in range(9)]
4059            floor = wx.ComboBox(G2frame.dataDisplay,value=str(data['Size']['MaxEnt']['Sky']),choices=floors,
4060                style=wx.CB_READONLY|wx.CB_DROPDOWN)
4061            Indx[floor.GetId()] = [data['Size']['MaxEnt'],'Sky',-10]
4062            floor.Bind(wx.EVT_COMBOBOX,OnIntVal)
4063            fitSizer.Add(floor,0,WACV)
4064        elif 'IPG' in data['Size']['Method']:
4065            fitSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Q power weight (-1 for sigma): '),0,WACV)
4066            choices = ['-1','0','1','2','3','4']
4067            power = wx.ComboBox(G2frame.dataDisplay,value=str(data['Size']['IPG']['Power']),choices=choices,
4068                style=wx.CB_READONLY|wx.CB_DROPDOWN)
4069            Indx[power.GetId()] = [data['Size']['IPG'],'Power',-2]
4070            power.Bind(wx.EVT_COMBOBOX,OnIntVal)
4071            fitSizer.Add(power,0,WACV)
4072        sizeSizer.Add(fitSizer,0)
4073
4074        return sizeSizer
4075       
4076    def PartSizer():
4077       
4078        FormFactors = {'Sphere':{},'Spheroid':{'Aspect ratio':[1.0,False]},
4079            'Cylinder':{'Length':[100.,False]},'Cylinder diam':{'Diameter':[100.,False]},
4080            'Cylinder AR':{'Aspect ratio':[1.0,False]},'Unified sphere':{},
4081            'Unified rod':{'Length':[100.,False]},'Unified rod AR':{'Aspect ratio':[1.0,False]},
4082            'Unified disk':{'Thickness':[100.,False]},
4083            'Unified tube':{'Length':[100.,False],'Thickness':[10.,False]},}
4084               
4085        StructureFactors = {'Dilute':{},'Hard sphere':{'VolFr':[0.1,False],'Dist':[100.,False]},
4086            'Sticky hard sphere':{'VolFr':[0.1,False],'Dist':[100.,False],'epis':[0.05,False],'Sticky':[0.2,False]},
4087            'Square well':{'VolFr':[0.1,False],'Dist':[100.,False],'Depth':[0.1,False],'Width':[1.,False]},
4088            'InterPrecipitate':{'VolFr':[0.1,False],'Dist':[100.,False]},}
4089               
4090        ffDistChoices =  ['Sphere','Spheroid','Cylinder','Cylinder diam',
4091            'Cylinder AR','Unified sphere','Unified rod','Unified rod AR',
4092            'Unified disk','Unified tube',]
4093               
4094        ffMonoChoices = ['Sphere','Spheroid','Cylinder','Cylinder AR',]
4095       
4096        sfChoices = ['Dilute','Hard sphere','Sticky hard sphere','Square well','InterPrecipitate',]
4097           
4098        slMult = 1000.
4099                 
4100        def OnValue(event):
4101            Obj = event.GetEventObject()
4102            item,key,sldrObj = Indx[Obj.GetId()]
4103            try:
4104                value = float(Obj.GetValue())
4105                if value <= 0.:
4106                    raise ValueError
4107            except ValueError:
4108                value = item[key][0]
4109            item[key][0] = value
4110            Obj.SetValue('%.3g'%(value))
4111            if key in ['P','epis','Sticky','Depth','Width','VolFr','Dist']:
4112                sldrObj.SetValue(slMult*value)
4113            else:
4114                logv = np.log10(value)
4115                valMinMax = [logv-1,logv+1]
4116                sldrObj.SetRange(slMult*valMinMax[0],slMult*valMinMax[1])
4117                sldrObj.SetValue(slMult*logv)
4118            G2sasd.ModelFxn(Profile,ProfDict,Limits,Sample,data)
4119            RefreshPlots()
4120           
4121        def OnSelect(event):
4122            Obj = event.GetEventObject()
4123            item,key = Indx[Obj.GetId()]
4124            item[key] = Obj.GetValue()
4125            if 'Refine' not in Obj.GetLabel():
4126                if 'FormFact' in key :
4127                    item['FFargs'] = FormFactors[Obj.GetValue()]
4128                elif 'StrFact' in key:
4129                    item['SFargs'] = StructureFactors[Obj.GetValue()]
4130                wx.CallAfter(UpdateModelsGrid,G2frame,data)
4131                G2sasd.ModelFxn(Profile,ProfDict,Limits,Sample,data)
4132                RefreshPlots()
4133               
4134        def OnDelLevel(event):
4135            Obj = event.GetEventObject()
4136            item = Indx[Obj.GetId()]
4137            del data['Particle']['Levels'][item