source: trunk/GSASIIpwdGUI.py @ 1912

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

more twin stuff - nonmerohedral mods
refl[3] now twin id not mul.

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