source: trunk/GSASIIpwdGUI.py @ 1945

Last change on this file since 1945 was 1945, checked in by vondreele, 8 years ago

fix another new histo in new phase error
some cleanup in texture calculations - unneeded list generation

  • Property svn:eol-style set to native
  • Property svn:keywords set to Date Author Revision URL Id
File size: 227.4 KB
Line 
1# -*- coding: utf-8 -*-
2#GSASIIpwdGUI - powder data display routines
3########### SVN repository information ###################
4# $Date: 2015-07-23 20:36:38 +0000 (Thu, 23 Jul 2015) $
5# $Author: vondreele $
6# $Revision: 1945 $
7# $URL: trunk/GSASIIpwdGUI.py $
8# $Id: GSASIIpwdGUI.py 1945 2015-07-23 20:36:38Z 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: 1945 $")
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 ValueError:
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                G2frame.HKL = np.array(G2frame.HKL)
2302                data[0] = G2indx.IndexSSPeaks(data[0],G2frame.HKL)[1]
2303            else:        #select cell from table - no SS
2304                for i,cell in enumerate(cellist):
2305                    if cell[-2]:
2306                        ibrav = cell[2]
2307                        A = G2lat.cell2A(cell[3:9])
2308                        G2frame.HKL = G2lat.GenHBravais(dmin,ibrav,A)
2309                        for hkl in G2frame.HKL:
2310                            hkl.insert(4,G2lat.Dsp2pos(Inst,hkl[3]))
2311                        G2frame.HKL = np.array(G2frame.HKL)
2312                        data[0] = G2indx.IndexPeaks(data[0],G2frame.HKL)[1]
2313                        break
2314    rowLabels = []
2315    for i in range(len(data[0])): rowLabels.append(str(i+1))
2316    colLabels = ['position','intensity','use','indexed','h','k','l','d-obs','d-calc']
2317    Types = [wg.GRID_VALUE_FLOAT+':10,4',wg.GRID_VALUE_FLOAT+':10,1',]+2*[wg.GRID_VALUE_BOOL,]+ \
2318        3*[wg.GRID_VALUE_LONG,]+2*[wg.GRID_VALUE_FLOAT+':10,5',]
2319    if len(data[0]) and len(data[0][0]) > 9:
2320        colLabels = ['position','intensity','use','indexed','h','k','l','m','d-obs','d-calc']
2321        Types = [wg.GRID_VALUE_FLOAT+':10,4',wg.GRID_VALUE_FLOAT+':10,1',]+2*[wg.GRID_VALUE_BOOL,]+ \
2322            4*[wg.GRID_VALUE_LONG,]+2*[wg.GRID_VALUE_FLOAT+':10,5',]
2323    G2frame.PatternTree.SetItemPyData(IndexId,data)
2324    G2frame.IndexPeaksTable = G2G.Table(data[0],rowLabels=rowLabels,colLabels=colLabels,types=Types)
2325    G2frame.dataFrame.SetLabel('Index Peak List')
2326    G2frame.dataDisplay = G2G.GSGrid(parent=G2frame.dataFrame)               
2327    G2frame.dataDisplay.SetTable(G2frame.IndexPeaksTable, True)
2328    XY = []
2329    Sigs = []
2330    for r in range(G2frame.dataDisplay.GetNumberRows()):
2331        for c in range(G2frame.dataDisplay.GetNumberCols()):
2332            if c == 2:
2333                G2frame.dataDisplay.SetReadOnly(r,c,isReadOnly=False)
2334            else:
2335                G2frame.dataDisplay.SetReadOnly(r,c,isReadOnly=True)
2336        if data[0][r][2] and data[0][r][3]:
2337            XY.append([data[0][r][-1],data[0][r][0]])
2338            try:
2339                sig = data[1][r]
2340            except IndexError:
2341                sig = 0.
2342            Sigs.append(sig)
2343    G2frame.dataDisplay.Bind(wg.EVT_GRID_CELL_LEFT_CLICK, RefreshIndexPeaksGrid)
2344    G2frame.dataDisplay.Bind(wx.EVT_KEY_DOWN, KeyEditPickGrid)                 
2345    G2frame.dataDisplay.SetMargins(0,0)
2346    G2frame.dataDisplay.AutoSizeColumns(False)
2347    G2frame.dataFrame.setSizePosLeft([490,300])
2348    if len(XY):
2349        XY = np.array(XY)
2350        G2plt.PlotCalib(G2frame,Inst,XY,Sigs,newPlot=True)
2351    G2frame.dataFrame.SendSizeEvent()
2352     
2353################################################################################
2354#####  Unit cells
2355################################################################################           
2356       
2357def UpdateUnitCellsGrid(G2frame, data):
2358    '''respond to selection of PWDR Unit Cells data tree item.
2359    '''
2360    UnitCellsId = G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Unit Cells List')
2361    SPGlist = G2spc.spglist
2362    bravaisSymb = ['Fm3m','Im3m','Pm3m','R3-H','P6/mmm','I4/mmm',
2363        'P4/mmm','Fmmm','Immm','Cmmm','Pmmm','C2/m','P2/m','P1']
2364    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',
2365        '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']
2366    Inst = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Instrument Parameters'))[0]
2367    if 'C' in Inst['Type'][0] or 'PKS' in Inst['Type'][0]:
2368        wave = G2mth.getWave(Inst)
2369    else:
2370        difC = Inst['difC'][1]
2371   
2372    def SetLattice(controls):
2373        ibrav = bravaisSymb.index(controls[5])
2374        if ibrav in [0,1,2]:
2375            controls[7] = controls[8] = controls[6]
2376            controls[9] = controls[10] = controls[11] = 90.
2377        elif ibrav in [3,4,5,6]:
2378            controls[7] = controls[6]
2379            controls[9] = controls[10] = controls[11] = 90.
2380            if ibrav in [3,4]:
2381                controls[11] = 120.
2382        elif ibrav in [7,8,9,10]:
2383            controls[9] = controls[10] = controls[11] = 90.
2384        elif ibrav in [11,12]:
2385            controls[9] = controls[11] = 90.  # b unique
2386        if len(controls) < 13: controls.append(0)
2387        controls[12] = G2lat.calc_V(G2lat.cell2A(controls[6:12]))
2388        return ibrav
2389       
2390    def OnNcNo(event):
2391        controls[2] = NcNo.GetValue()
2392       
2393    def OnIfX20(event):
2394        G2frame.ifX20 = x20.GetValue()
2395       
2396    def OnStartVol(event):
2397        try:
2398            stVol = int(float(startVol.GetValue()))
2399            if stVol < 25:
2400                raise ValueError
2401        except ValueError:
2402            stVol = 25
2403        controls[3] = stVol
2404        startVol.SetValue("%d"%(stVol))
2405       
2406    def OnBravais(event):
2407        Obj = event.GetEventObject()
2408        bravais[bravList.index(Obj.GetId())] = Obj.GetValue()
2409       
2410    def OnZero(event):
2411        try:
2412            Zero = min(5.0,max(-5.0,float(zero.GetValue())))
2413        except ValueError:
2414            Zero = 0.0
2415        controls[1] = Zero
2416        zero.SetValue("%.4f"%(Zero))
2417       
2418    def OnZeroVar(event):
2419        controls[0] = zeroVar.GetValue()
2420       
2421    def OnSSopt(event):
2422        if controls[5] in ['Fm3m','Im3m','Pm3m']:
2423            SSopt.SetValue(False)
2424            G2frame.ErrorDialog('Cubic lattice', 'Superlattice not allowed for a cubic lattice')
2425            return
2426        ssopt['Use'] = SSopt.GetValue()
2427        if 'ssSymb' not in ssopt:
2428            ssopt.update({'ssSymb':'(abg)','ModVec':[0.1,0.1,0.1],'maxH':1})
2429        wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)
2430       
2431    def OnSelMG(event):
2432        ssopt['ssSymb'] = selMG.GetValue()
2433        Vec = ssopt['ModVec']
2434        modS = G2spc.splitSSsym(ssopt['ssSymb'])[0]
2435        ssopt['ModVec'] = G2spc.SSGModCheck(Vec,modS)[0]
2436        print ' Selecting: ',controls[13],ssopt['ssSymb'], 'maxH:',ssopt['maxH']
2437        OnHklShow(event)
2438        wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)
2439       
2440    def OnModVal(event):
2441        Obj = event.GetEventObject()
2442        ObjId = Obj.GetId()
2443        Id = Indx[ObjId]
2444        try:
2445            value = min(1.0,max(0.,float(Obj.GetValue())))
2446        except ValueError:
2447            value = ssopt['ModVec'][Id]
2448        Obj.SetValue('%.4f'%(value))
2449        ssopt['ModVec'][Id] = value
2450        OnHklShow(event)
2451       
2452    def OnMoveMod(event):
2453        Obj = event.GetEventObject()
2454        ObjId = Obj.GetId()
2455        Id,valObj = Indx[ObjId]
2456        move = Obj.GetValue()*0.0005
2457        Obj.SetValue(0)
2458        value = min(1.0,max(.0,float(valObj.GetValue())+move))
2459        valObj.SetValue('%.4f'%(value)) 
2460        ssopt['ModVec'][Id] = value
2461        OnHklShow(event)
2462       
2463    def OnMaxMH(event):
2464        ssopt['maxH'] = int(maxMH.GetValue())
2465        print ' Selecting: ',controls[13],ssopt['ssSymb'], 'maxH:',ssopt['maxH']
2466        OnHklShow(event)
2467       
2468    def OnFindMV(event):
2469        Peaks = np.copy(peaks[0])
2470        print ' Trying: ',controls[13],ssopt['ssSymb'], 'maxH:',ssopt['maxH']
2471        dlg = wx.ProgressDialog('Elapsed time','Modulation vector search',
2472            style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE)
2473        try:
2474            ssopt['ModVec'] = G2indx.findMV(Peaks,controls,ssopt,Inst,dlg)
2475        finally:
2476            dlg.Destroy()
2477        OnHklShow(event)
2478        wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)
2479       
2480    def OnBravSel(event):
2481        brav = bravSel.GetString(bravSel.GetSelection())
2482        controls[5] = brav
2483        controls[13] = SPGlist[brav][0]       
2484        wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)
2485       
2486    def OnSpcSel(event):
2487        controls[13] = spcSel.GetString(spcSel.GetSelection())
2488        G2frame.dataFrame.RefineCell.Enable(True)
2489        OnHklShow(event)
2490       
2491    def SetCellValue(Obj,ObjId,value):
2492        ibrav = bravaisSymb.index(controls[5])
2493        if ibrav in [0,1,2]:
2494            controls[6] = controls[7] = controls[8] = value
2495            controls[9] = controls[10] = controls[11] = 90.0
2496            Obj.SetValue("%.5f"%(controls[6]))
2497        elif ibrav in [3,4,5,6]:
2498            if ObjId == 0:
2499                controls[6] = controls[7] = value
2500                Obj.SetValue("%.5f"%(controls[6]))
2501            else:
2502                controls[8] = value
2503                Obj.SetValue("%.5f"%(controls[8]))
2504            controls[9] = controls[10] = controls[11] = 90.0
2505            if ibrav in [3,4]:
2506                controls[11] = 120.
2507        elif ibrav in [7,8,9,10]:
2508            controls[6+ObjId] = value
2509            Obj.SetValue("%.5f"%(controls[6+ObjId]))
2510            controls[9] = controls[10] = controls[11] = 90.0
2511        elif ibrav in [11,12]:
2512            controls[9] = controls[11] = 90.0
2513            if ObjId != 3:
2514                controls[6+ObjId] = value
2515                Obj.SetValue("%.5f"%(controls[6+ObjId]))
2516            else:
2517                controls[10] = value
2518                Obj.SetValue("%.3f"%(controls[10]))
2519        else:
2520            controls[6+ObjId] = value
2521            if ObjId < 3:
2522                Obj.SetValue("%.5f"%(controls[6+ObjId]))
2523            else:
2524                Obj.SetValue("%.3f"%(controls[6+ObjId]))
2525        controls[12] = G2lat.calc_V(G2lat.cell2A(controls[6:12]))
2526        volVal.SetValue("%.3f"%(controls[12]))
2527       
2528    def OnMoveCell(event):
2529        Obj = event.GetEventObject()
2530        ObjId = cellList.index(Obj.GetId())
2531        valObj = valDict[Obj.GetId()]
2532        if ObjId/2 < 3:
2533            move = Obj.GetValue()*0.01
2534        else:
2535            move = Obj.GetValue()*0.1
2536        Obj.SetValue(0)
2537        value = float(valObj.GetValue())+move 
2538        SetCellValue(valObj,ObjId/2,value)
2539        OnHklShow(event)
2540       
2541    def OnExportCells(event):
2542        dlg = wx.FileDialog(G2frame, 'Choose Indexing Result csv file', '.', '', 
2543            'indexing result file (*.csv)|*.csv',wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT|wx.CHANGE_DIR)
2544        try:
2545            if dlg.ShowModal() == wx.ID_OK:
2546                filename = dlg.GetPath()
2547                filename = os.path.splitext(filename)[0]+'.csv'
2548                File = open(filename,'w')
2549                names = 'M20,X20,Bravais,a,b,c,alpha,beta,gamma,volume\n'
2550                File.write(names)
2551                fmt = '%.2f,%d,%s,%.4f,%.4f,%.4f,%.2f,%.2f,%.2f,%.3f\n'
2552                for cell in cells:
2553                    File.write(fmt%(cell[0],cell[1],bravaisSymb[cell[2]], cell[3],cell[4],cell[5], cell[6],cell[7],cell[8],cell[9]))
2554                File.close()
2555        finally:
2556            dlg.Destroy()
2557       
2558    def OnCellChange(event):
2559        Obj = event.GetEventObject()
2560        ObjId = cellList.index(Obj.GetId())
2561        try:
2562            value = max(1.0,float(Obj.GetValue()))
2563        except ValueError:
2564            if ObjId/2 < 3:               #bad cell edge - reset
2565                value = controls[6+ObjId/2]
2566            else:                       #bad angle
2567                value = 90.
2568        SetCellValue(Obj,ObjId/2,value)
2569       
2570    def OnHklShow(event):
2571        PatternId = G2frame.PatternId
2572        PickId = G2frame.PickId   
2573        peaks = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Index Peak List'))
2574        limits = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Limits'))[1]
2575        controls,bravais,cells,dmin,ssopt = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Unit Cells List'))
2576        cell = controls[6:12]
2577        A = G2lat.cell2A(cell)
2578        ibrav = bravaisSymb.index(controls[5])
2579        spc = controls[13]
2580        SGData = G2spc.SpcGroup(spc)[1]
2581        if 'C' in Inst['Type'][0]:
2582            dmin = G2lat.Pos2dsp(Inst,limits[1])
2583        else:   #TOF - use other limit!
2584            dmin = G2lat.Pos2dsp(Inst,limits[0])
2585        if ssopt.get('Use',False):
2586            dmin = peaks[0][-1][8]
2587            SSGData = G2spc.SSpcGroup(SGData,ssopt['ssSymb'])[1]
2588            Vec = ssopt['ModVec']
2589            maxH = ssopt['maxH']
2590            G2frame.HKL = G2pwd.getHKLMpeak(dmin,Inst,SGData,SSGData,Vec,maxH,A)
2591            peaks = [G2indx.IndexSSPeaks(peaks[0],G2frame.HKL)[1],peaks[1]]   #keep esds from peak fit
2592            M20,X20 = G2indx.calc_M20SS(peaks[0],G2frame.HKL)
2593        else:
2594            if len(peaks[0]):
2595                dmin = peaks[0][-1][7]
2596                G2frame.HKL = G2pwd.getHKLpeak(dmin,SGData,A,Inst)
2597                peaks = [G2indx.IndexPeaks(peaks[0],G2frame.HKL)[1],peaks[1]]   #keep esds from peak fit
2598                M20,X20 = G2indx.calc_M20(peaks[0],G2frame.HKL)
2599            else:
2600                M20 = X20 = 0.
2601                G2frame.HKL = G2pwd.getHKLpeak(dmin,SGData,A,Inst)
2602        G2frame.HKL = np.array(G2frame.HKL)
2603        if len(G2frame.HKL):
2604            print ' new M20,X20: %.2f %d fraction found: %.3f'%(M20,X20,float(len(peaks[0]))/len(G2frame.HKL))
2605        G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Index Peak List'),peaks)
2606        if 'PKS' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
2607            G2plt.PlotPowderLines(G2frame)
2608        else:
2609            G2plt.PlotPatterns(G2frame)
2610           
2611    def OnSortCells(event):
2612        controls,bravais,cells,dmin,ssopt = G2frame.PatternTree.GetItemPyData(UnitCellsId)
2613        c =  event.GetCol()
2614        if colLabels[c] == 'M20':
2615            cells = G2indx.sortM20(cells)
2616        elif colLabels[c] in ['X20','Bravais','a','b','c','alpha','beta','gamma','Volume']:
2617            if c == 1:
2618                c += 1  #X20 before Use
2619            cells = G2indx.sortCells(cells,c-1)     #an extra column (Use) not in cells
2620        else:
2621            return
2622        data = [controls,bravais,cells,dmin,ssopt]
2623        G2frame.PatternTree.SetItemPyData(UnitCellsId,data)
2624        wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)
2625       
2626    def CopyUnitCell(event):
2627        controls,bravais,cells,dmin,ssopt = G2frame.PatternTree.GetItemPyData(UnitCellsId)
2628        for Cell in cells:
2629            if Cell[-2]:
2630                break
2631        cell = Cell[2:9]
2632        controls[4] = 1
2633        controls[5] = bravaisSymb[cell[0]]
2634        controls[6:12] = cell[1:8]
2635        controls[12] = G2lat.calc_V(G2lat.cell2A(controls[6:12]))
2636        controls[13] = spaceGroups[bravaisSymb.index(controls[5])]
2637        G2frame.PatternTree.SetItemPyData(UnitCellsId,[controls,bravais,cells,dmin,ssopt])
2638        G2frame.dataFrame.RefineCell.Enable(True)
2639        wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)       
2640               
2641    def RefineCell(event):
2642       
2643        def cellPrint(ibrav,A):
2644            cell = G2lat.A2cell(A)
2645            Vol = G2lat.calc_V(A)
2646            if ibrav in [0,1,2]:
2647                print " %s%10.6f" % ('a =',cell[0])
2648            elif ibrav in [3,4,5,6]:
2649                print " %s%10.6f %s%10.6f %s%12.3f" % ('a =',cell[0],' c =',cell[2],' volume =',Vol)
2650            elif ibrav in [7,8,9,10]:
2651                print " %s%10.6f %s%10.6f %s%10.6f %s%12.3f" % ('a =',cell[0],'b =',cell[1],'c =',cell[2],' volume =',Vol)
2652            elif ibrav in [11,12]:
2653                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)
2654            else:
2655                print " %s%10.6f %s%10.6f %s%10.6f" % ('a =',cell[0],'b =',cell[1],'c =',cell[2])
2656                print " %s%8.3f %s%8.3f %s%8.3f %s%12.3f" % ('alpha =',cell[3],'beta =',cell[4],'gamma =',cell[5],' volume =',Vol)
2657               
2658        def vecPrint(Vec):
2659            print ' %s %10.5f %10.5f %10.5f'%('Modulation vector:',Vec[0],Vec[1],Vec[2])
2660             
2661        PatternId = G2frame.PatternId
2662        PickId = G2frame.PickId   
2663        peaks = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Index Peak List'))
2664        if not len(peaks[0]):
2665            G2frame.ErrorDialog('No peaks!', 'Nothing to refine!')
2666            return       
2667        print ' Refine cell'
2668        controls,bravais,cells,dmin,ssopt = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Unit Cells List'))
2669        cell = controls[6:12]
2670        A = G2lat.cell2A(cell)
2671        ibrav = bravaisSymb.index(controls[5])
2672        SGData = G2spc.SpcGroup(controls[13])[1]
2673        dmin = G2indx.getDmin(peaks[0])-0.005
2674        if 'C' in Inst['Type'][0]:
2675            if ssopt.get('Use',False):
2676                vecFlags = [True if x in ssopt['ssSymb'] else False for x in ['a','b','g']]
2677                SSGData = G2spc.SSpcGroup(SGData,ssopt['ssSymb'])[1]
2678                G2frame.HKL = G2pwd.getHKLMpeak(dmin,Inst,SGData,SSGData,ssopt['ModVec'],ssopt['maxH'],A)
2679                peaks = [G2indx.IndexSSPeaks(peaks[0],G2frame.HKL)[1],peaks[1]]   #put peak fit esds back in peaks
2680                Lhkl,M20,X20,Aref,Vec,Zero = \
2681                    G2indx.refinePeaksZSS(peaks[0],wave,Inst,SGData,SSGData,ssopt['maxH'],ibrav,A,ssopt['ModVec'],vecFlags,controls[1],controls[0])
2682            else:
2683                G2frame.HKL = G2pwd.getHKLpeak(dmin,SGData,A,Inst)
2684                peaks = [G2indx.IndexPeaks(peaks[0],G2frame.HKL)[1],peaks[1]]   #put peak fit esds back in peaks
2685                Lhkl,M20,X20,Aref,Zero = G2indx.refinePeaksZ(peaks[0],wave,ibrav,A,controls[1],controls[0])
2686        else:   #'T'OF - doesn't seem to work
2687            G2frame.HKL = G2pwd.getHKLpeak(dmin,SGData,A,Inst)
2688            peaks = [G2indx.IndexPeaks(peaks[0],G2frame.HKL)[1],peaks[1]]   #put peak fit esds back in peaks
2689            Lhkl,M20,X20,Aref,Zero = G2indx.refinePeaksT(peaks[0],difC,ibrav,A,controls[1],controls[0])           
2690        G2frame.HKL = np.array(G2frame.HKL)
2691        controls[1] = Zero
2692        controls[6:12] = G2lat.A2cell(Aref)
2693        controls[12] = G2lat.calc_V(Aref)
2694        cells = G2frame.PatternTree.GetItemPyData(UnitCellsId)[2]
2695        for cell in cells:
2696            cell[-2] = False
2697        cells.insert(0,[M20,X20,ibrav]+controls[6:13]+[True,False])
2698        if ssopt.get('Use',False):
2699            ssopt['ModVec'] = Vec
2700            G2frame.HKL = G2pwd.getHKLMpeak(dmin,Inst,SGData,SSGData,ssopt['ModVec'],ssopt['maxH'],A)
2701        else:
2702            G2frame.HKL = G2pwd.getHKLpeak(dmin,SGData,A,Inst)
2703        data = [controls,bravais,cells,dmin,ssopt]
2704        G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Unit Cells List'),data)
2705        print " %s%10.3f" % ('refinement M20 = ',M20)
2706        print ' unindexed lines = ',X20
2707        cellPrint(ibrav,Aref)
2708        ip = 4
2709        if ssopt.get('Use',False):
2710            vecPrint(Vec)
2711            ip = 5
2712        for hkl in G2frame.HKL:
2713            hkl[ip] = G2lat.Dsp2pos(Inst,hkl[ip-1])+controls[1]
2714        G2frame.HKL = np.array(G2frame.HKL)
2715        if 'PKS' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
2716            G2plt.PlotPowderLines(G2frame)
2717        else:
2718            G2plt.PlotPatterns(G2frame)
2719        wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)
2720       
2721    def IndexPeaks(event):
2722        PatternId = G2frame.PatternId   
2723        print 'Peak Indexing'
2724        keepcells = []
2725        try:
2726            controls,bravais,cells,dmin,ssopt = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Unit Cells List'))
2727            for cell in cells:
2728                if cell[11]:
2729                    cell[10] = False    #clear selection flag on keepers
2730                    keepcells.append(cell)
2731        except IndexError:
2732            pass
2733        except ValueError:
2734            G2frame.ErrorDialog('Error','Need to set controls in Unit Cell List first')
2735            return
2736        if ssopt.get('Use',False):
2737            G2frame.ErrorDialog('Super lattice error','Indexing not available for super lattices')
2738            return
2739        if True not in bravais:
2740            G2frame.ErrorDialog('Error','No Bravais lattices selected')
2741            return
2742        if not len(peaks[0]):
2743            G2frame.ErrorDialog('Error','Index Peak List is empty')
2744            return
2745        if len(peaks[0][0]) > 9:
2746            G2frame.ErrorDialog('Error','You need to reload Index Peaks List first')
2747            return
2748        G2frame.dataFrame.CopyCell.Enable(False)
2749        G2frame.dataFrame.RefineCell.Enable(False)
2750        OK,dmin,newcells = G2indx.DoIndexPeaks(peaks[0],controls,bravais,G2frame.ifX20)
2751        cells = keepcells+newcells
2752        cells = G2indx.sortM20(cells)
2753        if OK:
2754            cells[0][10] = True         #select best M20
2755            data = [controls,bravais,cells,dmin,ssopt]
2756            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Unit Cells List'),data)
2757            bestCell = cells[0]
2758            if bestCell[0] > 10.:
2759                G2frame.HKL = G2lat.GenHBravais(dmin,bestCell[2],G2lat.cell2A(bestCell[3:9]))
2760                for hkl in G2frame.HKL:
2761                    hkl.insert(4,G2lat.Dsp2pos(Inst,hkl[3])+controls[1])
2762                G2frame.HKL = np.array(G2frame.HKL)
2763                if 'PKS' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
2764                    G2plt.PlotPowderLines(G2frame)
2765                else:
2766                    G2plt.PlotPatterns(G2frame)
2767            G2frame.dataFrame.CopyCell.Enable(True)
2768            G2frame.dataFrame.IndexPeaks.Enable(True)
2769            G2frame.dataFrame.MakeNewPhase.Enable(True)
2770            G2frame.ifX20 = True
2771            wx.CallAfter(UpdateUnitCellsGrid,G2frame,data)
2772               
2773    def RefreshUnitCellsGrid(event):
2774        data = G2frame.PatternTree.GetItemPyData(UnitCellsId)
2775        cells,dmin = data[2:4]
2776        r,c =  event.GetRow(),event.GetCol()
2777        if cells:
2778            if c == 2:
2779                for i in range(len(cells)):
2780                    cells[i][-2] = False
2781                    UnitCellsTable.SetValue(i,c,False)
2782                UnitCellsTable.SetValue(r,c,True)
2783                gridDisplay.Refresh()
2784                cells[r][-2] = True
2785                ibrav = cells[r][2]
2786                A = G2lat.cell2A(cells[r][3:9])
2787                G2frame.HKL = G2lat.GenHBravais(dmin,ibrav,A)
2788                for hkl in G2frame.HKL:
2789                    hkl.insert(4,G2lat.Dsp2pos(Inst,hkl[3])+controls[1])
2790                G2frame.HKL = np.array(G2frame.HKL)
2791                if 'PKS' in G2frame.PatternTree.GetItemText(G2frame.PatternId):
2792                    G2plt.PlotPowderLines(G2frame)
2793                else:
2794                    G2plt.PlotPatterns(G2frame)
2795            elif c == 11:
2796                if UnitCellsTable.GetValue(r,c):
2797                    UnitCellsTable.SetValue(r,c,False)
2798                    cells[r][c] = False
2799                else:
2800                    cells[r][c] = True
2801                    UnitCellsTable.SetValue(r,c,True)
2802                gridDisplay.ForceRefresh()
2803            G2frame.PatternTree.SetItemPyData(UnitCellsId,data)
2804       
2805    def MakeNewPhase(event):
2806        if not G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Phases'):
2807            sub = G2frame.PatternTree.AppendItem(parent=G2frame.root,text='Phases')
2808        else:
2809            sub = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Phases')
2810        PhaseName = ''
2811        dlg = wx.TextEntryDialog(None,'Enter a name for this phase','Phase Name Entry','New phase',
2812            style=wx.OK)
2813        try:
2814            if dlg.ShowModal() == wx.ID_OK:
2815                PhaseName = dlg.GetValue()
2816                cells = G2frame.PatternTree.GetItemPyData(UnitCellsId)[2]
2817                for Cell in cells:
2818                    if Cell[-2]:
2819                        break
2820                cell = Cell[2:10]       
2821                sub = G2frame.PatternTree.AppendItem(parent=sub,text=PhaseName)
2822                E,SGData = G2spc.SpcGroup(controls[13])
2823                G2frame.PatternTree.SetItemPyData(sub, \
2824                    G2IO.SetNewPhase(Name=PhaseName,SGData=SGData,cell=cell[1:],Super=ssopt))
2825                Status.SetStatusText('Change space group from '+str(controls[13])+' if needed')
2826        finally:
2827            dlg.Destroy()
2828           
2829    if G2frame.dataDisplay:
2830        G2frame.dataFrame.DestroyChildren()
2831    G2frame.dataDisplay = wxscroll.ScrolledPanel(G2frame.dataFrame)
2832    G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.IndexMenu)
2833    if not G2frame.dataFrame.GetStatusBar():
2834        Status = G2frame.dataFrame.CreateStatusBar()
2835    G2frame.Bind(wx.EVT_MENU, IndexPeaks, id=G2gd.wxID_INDEXPEAKS)
2836    G2frame.Bind(wx.EVT_MENU, CopyUnitCell, id=G2gd.wxID_COPYCELL)
2837    G2frame.Bind(wx.EVT_MENU, RefineCell, id=G2gd.wxID_REFINECELL)
2838    G2frame.Bind(wx.EVT_MENU, MakeNewPhase, id=G2gd.wxID_MAKENEWPHASE)
2839    G2frame.Bind(wx.EVT_MENU, OnExportCells, id=G2gd.wxID_EXPORTCELLS)
2840       
2841    controls,bravais,cells,dmin,ssopt = data
2842    if len(controls) < 13:              #add cell volume if missing
2843        controls.append(G2lat.calc_V(G2lat.cell2A(controls[6:12])))
2844    if len(controls) < 14:              #add space gropu used in indexing
2845        controls.append(spaceGroups[bravaisSymb.index(controls[5])])
2846    G2frame.PatternTree.SetItemPyData(UnitCellsId,data)            #update with volume
2847    bravaisNames = ['Cubic-F','Cubic-I','Cubic-P','Trigonal-R','Trigonal/Hexagonal-P',
2848        'Tetragonal-I','Tetragonal-P','Orthorhombic-F','Orthorhombic-I','Orthorhombic-C',
2849        'Orthorhombic-P','Monoclinic-C','Monoclinic-P','Triclinic']
2850    cellGUIlist = [[[0,1,2],4,zip([" Unit cell: a = "," Vol = "],["%.5f","%.3f"],[True,False],[0,0])],
2851    [[3,4,5,6],6,zip([" Unit cell: a = "," c = "," Vol = "],["%.5f","%.5f","%.3f"],[True,True,False],[0,2,0])],
2852    [[7,8,9,10],8,zip([" Unit cell: a = "," b = "," c = "," Vol = "],["%.5f","%.5f","%.5f","%.3f"],
2853        [True,True,True,False],[0,1,2,0])],
2854    [[11,12],10,zip([" Unit cell: a = "," b = "," c = "," beta = "," Vol = "],
2855        ["%.5f","%.5f","%.5f","%.3f","%.3f"],[True,True,True,True,False],[0,1,2,4,0])],
2856    [[13,],8,zip([" Unit cell: a = "," b = "," c = "," Vol = "," alpha = "," beta = "," gamma = "],
2857        ["%.5f","%.5f","%.5f","%.3f","%.3f","%.3f","%.3f"],
2858        [True,True,True,False,True,True,True],[0,1,2,0,3,4,5])]]
2859   
2860    G2frame.dataFrame.SetLabel('Unit Cells List')
2861    G2frame.dataFrame.IndexPeaks.Enable(False)
2862    peaks = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Index Peak List'))
2863    if peaks:
2864        G2frame.dataFrame.IndexPeaks.Enable(True)
2865    G2frame.dataFrame.RefineCell.Enable(False)
2866    if controls[12] > 1.0:                               #if a "real" volume (i.e. not default)
2867        G2frame.dataFrame.RefineCell.Enable(True)   
2868    G2frame.dataFrame.CopyCell.Enable(False)
2869    G2frame.dataFrame.MakeNewPhase.Enable(False)       
2870    G2frame.dataFrame.ExportCells.Enable(False)
2871    if cells:
2872        G2frame.dataFrame.CopyCell.Enable(True)
2873        G2frame.dataFrame.MakeNewPhase.Enable(True)
2874        G2frame.dataFrame.ExportCells.Enable(True)
2875    mainSizer = wx.BoxSizer(wx.VERTICAL)
2876    mainSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Indexing controls: '),0,WACV)
2877    mainSizer.Add((5,5),0)
2878    littleSizer = wx.FlexGridSizer(0,5,5,5)
2879    littleSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Max Nc/Nobs '),0,WACV)
2880    NcNo = wx.SpinCtrl(G2frame.dataDisplay)
2881    NcNo.SetRange(2,6)
2882    NcNo.SetValue(controls[2])
2883    NcNo.Bind(wx.EVT_SPINCTRL,OnNcNo)
2884    littleSizer.Add(NcNo,0,WACV)
2885    littleSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Start Volume '),0,WACV)
2886    startVol = wx.TextCtrl(G2frame.dataDisplay,value=str('%d'%(controls[3])),style=wx.TE_PROCESS_ENTER)
2887    startVol.Bind(wx.EVT_TEXT_ENTER,OnStartVol)
2888    startVol.Bind(wx.EVT_KILL_FOCUS,OnStartVol)
2889    littleSizer.Add(startVol,0,WACV)
2890    x20 = wx.CheckBox(G2frame.dataDisplay,label='Use M20/(X20+1)?')
2891    x20.SetValue(G2frame.ifX20)
2892    x20.Bind(wx.EVT_CHECKBOX,OnIfX20)
2893    littleSizer.Add(x20,0,WACV)
2894    mainSizer.Add(littleSizer,0)
2895    mainSizer.Add((5,5),0)
2896    mainSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Select Bravais Lattices for indexing: '),
2897        0,WACV)
2898    mainSizer.Add((5,5),0)
2899    littleSizer = wx.FlexGridSizer(0,7,5,5)
2900    bravList = []
2901    bravs = zip(bravais,bravaisNames)
2902    for brav,bravName in bravs:
2903        bravCk = wx.CheckBox(G2frame.dataDisplay,label=bravName)
2904        bravList.append(bravCk.GetId())
2905        bravCk.SetValue(brav)
2906        bravCk.Bind(wx.EVT_CHECKBOX,OnBravais)
2907        littleSizer.Add(bravCk,0,WACV)
2908    mainSizer.Add(littleSizer,0)
2909    mainSizer.Add((5,5),0)
2910   
2911    mainSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Cell Refinement: '),0,WACV)
2912    mainSizer.Add((5,5),0)
2913    littleSizer = wx.BoxSizer(wx.HORIZONTAL)
2914    littleSizer.Add(wx.StaticText(G2frame.dataDisplay,label=" Bravais lattice "),0,WACV)
2915    bravSel = wx.Choice(G2frame.dataDisplay,choices=bravaisSymb)
2916    bravSel.SetSelection(bravaisSymb.index(controls[5]))
2917    bravSel.Bind(wx.EVT_CHOICE,OnBravSel)
2918    littleSizer.Add(bravSel,0,WACV)
2919    littleSizer.Add(wx.StaticText(G2frame.dataDisplay,label=" Space group "),0,WACV)
2920    spcSel = wx.Choice(G2frame.dataDisplay,choices=SPGlist[controls[5]])
2921    spcSel.SetSelection(SPGlist[controls[5]].index(controls[13]))
2922    spcSel.Bind(wx.EVT_CHOICE,OnSpcSel)
2923    littleSizer.Add(spcSel,0,WACV)
2924    if ssopt.get('Use',False):        #zero for super lattice doesn't work!
2925        controls[0] = False
2926    else:
2927        littleSizer.Add(wx.StaticText(G2frame.dataDisplay,label=" Zero offset"),0,WACV)
2928        zero = wx.TextCtrl(G2frame.dataDisplay,value="%.4f"%(controls[1]),style=wx.TE_PROCESS_ENTER)
2929        zero.Bind(wx.EVT_TEXT_ENTER,OnZero)
2930        zero.Bind(wx.EVT_KILL_FOCUS,OnZero)
2931        littleSizer.Add(zero,0,WACV)
2932        zeroVar = wx.CheckBox(G2frame.dataDisplay,label="Refine?")
2933        zeroVar.SetValue(controls[0])
2934        zeroVar.Bind(wx.EVT_CHECKBOX,OnZeroVar)
2935        littleSizer.Add(zeroVar,0,WACV)
2936    SSopt = wx.CheckBox(G2frame.dataDisplay,label="Super lattice?")
2937    SSopt.SetValue(ssopt.get('Use',False))
2938    SSopt.Bind(wx.EVT_CHECKBOX,OnSSopt)
2939    littleSizer.Add(SSopt,0,WACV)
2940    hklShow = wx.Button(G2frame.dataDisplay,label="Show hkl positions")
2941    hklShow.Bind(wx.EVT_BUTTON,OnHklShow)
2942    littleSizer.Add(hklShow,0,WACV)
2943    mainSizer.Add(littleSizer,0)
2944   
2945    mainSizer.Add((5,5),0)
2946    ibrav = SetLattice(controls)
2947    for cellGUI in cellGUIlist:
2948        if ibrav in cellGUI[0]:
2949            useGUI = cellGUI
2950    cellList = []
2951    valDict = {}
2952    littleSizer = wx.FlexGridSizer(0,useGUI[1],5,5)
2953    for txt,fmt,ifEdit,Id in useGUI[2]:
2954        littleSizer.Add(wx.StaticText(G2frame.dataDisplay,label=txt),0,WACV)
2955        if ifEdit:          #a,b,c,etc.
2956            cellVal = wx.TextCtrl(G2frame.dataDisplay,value=(fmt%(controls[6+Id])),style=wx.TE_PROCESS_ENTER)
2957            cellVal.Bind(wx.EVT_TEXT_ENTER,OnCellChange)       
2958            cellVal.Bind(wx.EVT_KILL_FOCUS,OnCellChange)
2959            valSizer = wx.BoxSizer(wx.HORIZONTAL)
2960            valSizer.Add(cellVal,0,WACV)
2961            cellSpin = wx.SpinButton(G2frame.dataDisplay,style=wx.SP_VERTICAL,size=wx.Size(20,20))
2962            cellSpin.SetValue(0)
2963            cellSpin.SetRange(-1,1)
2964            cellSpin.Bind(wx.EVT_SPIN, OnMoveCell)
2965            valSizer.Add(cellSpin,0,WACV)
2966            littleSizer.Add(valSizer,0,WACV)
2967            cellList.append(cellVal.GetId())
2968            cellList.append(cellSpin.GetId())
2969            valDict[cellSpin.GetId()] = cellVal
2970        else:               #volume
2971            volVal = wx.TextCtrl(G2frame.dataDisplay,value=(fmt%(controls[12])),style=wx.TE_READONLY)
2972            volVal.SetBackgroundColour(VERY_LIGHT_GREY)
2973            littleSizer.Add(volVal,0,WACV)
2974    mainSizer.Add(littleSizer,0)
2975    if ssopt.get('Use',False):        #super lattice display
2976        indChoice = ['1','2','3','4',]
2977        SpSg = controls[13]
2978        ssChoice = G2spc.ssdict[SpSg]
2979        if ssopt['ssSymb'] not in ssChoice:
2980            ssopt['ssSymb'] = ssChoice[0]
2981        ssSizer = wx.BoxSizer(wx.HORIZONTAL)
2982        ssSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Supersymmetry space group: '+SpSg+' '),0,WACV)
2983        selMG = wx.ComboBox(G2frame.dataDisplay,value=ssopt['ssSymb'],
2984                choices=ssChoice,style=wx.CB_READONLY|wx.CB_DROPDOWN)
2985        selMG.Bind(wx.EVT_COMBOBOX, OnSelMG)
2986        ssSizer.Add(selMG,0,WACV)
2987        ssSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Mod. vector: '),0,WACV)
2988        modS = G2spc.splitSSsym(ssopt['ssSymb'])[0]
2989        ssopt['ModVec'],ifShow = G2spc.SSGModCheck(ssopt['ModVec'],modS)
2990        Indx = {}
2991        for i,[val,show] in enumerate(zip(ssopt['ModVec'],ifShow)):
2992            if show:
2993                valSizer = wx.BoxSizer(wx.HORIZONTAL)
2994                modVal = wx.TextCtrl(G2frame.dataDisplay,value=('%.4f'%(val)),
2995                    size=wx.Size(50,20),style=wx.TE_PROCESS_ENTER)
2996                modVal.Bind(wx.EVT_TEXT_ENTER,OnModVal)       
2997                modVal.Bind(wx.EVT_KILL_FOCUS,OnModVal)
2998                valSizer.Add(modVal,0,WACV)
2999                modSpin = wx.SpinButton(G2frame.dataDisplay,style=wx.SP_VERTICAL,size=wx.Size(20,20))
3000                modSpin.SetValue(0)
3001                modSpin.SetRange(-1,1)
3002                modSpin.Bind(wx.EVT_SPIN, OnMoveMod)
3003                valSizer.Add(modSpin,0,WACV)
3004                ssSizer.Add(valSizer,0,WACV)
3005                Indx[modVal.GetId()] = i
3006                Indx[modSpin.GetId()] = [i,modVal]
3007            else:
3008                modVal = wx.TextCtrl(G2frame.dataDisplay,value=('%.3f'%(val)),
3009                    size=wx.Size(50,20),style=wx.TE_READONLY)
3010                modVal.SetBackgroundColour(VERY_LIGHT_GREY)
3011                ssSizer.Add(modVal,0,WACV)
3012        ssSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Max. M: '),0,WACV)
3013        maxMH = wx.ComboBox(G2frame.dataDisplay,value=str(ssopt['maxH']),
3014            choices=indChoice,style=wx.CB_READONLY|wx.CB_DROPDOWN)
3015        maxMH.Bind(wx.EVT_COMBOBOX, OnMaxMH)
3016        ssSizer.Add(maxMH,0,WACV)
3017        findMV = wx.wx.Button(G2frame.dataDisplay,label="Find mod. vec.?")
3018        findMV.Bind(wx.EVT_BUTTON,OnFindMV)
3019        ssSizer.Add(findMV,0,WACV)
3020        mainSizer.Add(ssSizer,0)
3021
3022    if cells:
3023        mainSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label='\n Indexing Result:'),0,WACV)
3024        rowLabels = []
3025        colLabels = ['M20','X20','use','Bravais','a','b','c','alpha','beta','gamma','Volume','Keep']
3026        Types = [wg.GRID_VALUE_FLOAT+':10,2',wg.GRID_VALUE_NUMBER,wg.GRID_VALUE_BOOL,wg.GRID_VALUE_STRING,]+ \
3027            3*[wg.GRID_VALUE_FLOAT+':10,5',]+3*[wg.GRID_VALUE_FLOAT+':10,3',]+ \
3028            [wg.GRID_VALUE_FLOAT+':10,2',wg.GRID_VALUE_BOOL]
3029        numRows = len(cells)
3030        table = []
3031        for cell in cells:
3032            rowLabels.append('')
3033            row = cell[0:2]+[cell[-2]]+[bravaisSymb[cell[2]]]+cell[3:10]+[cell[11],]
3034            if cell[-2]:
3035                A = G2lat.cell2A(cell[3:9])
3036                G2frame.HKL = G2lat.GenHBravais(dmin,cell[2],A)
3037                for hkl in G2frame.HKL:
3038                    hkl.insert(4,G2lat.Dsp2pos(Inst,hkl[3])+controls[1])
3039                G2frame.HKL = np.array(G2frame.HKL)
3040            table.append(row)
3041        UnitCellsTable = G2G.Table(table,rowLabels=rowLabels,colLabels=colLabels,types=Types)
3042        gridDisplay = G2G.GSGrid(G2frame.dataDisplay)
3043        gridDisplay.SetTable(UnitCellsTable, True)
3044        G2frame.dataFrame.CopyCell.Enable(True)
3045        gridDisplay.Bind(wg.EVT_GRID_CELL_LEFT_CLICK,RefreshUnitCellsGrid)
3046        gridDisplay.Bind(wg.EVT_GRID_LABEL_LEFT_DCLICK,OnSortCells)
3047        gridDisplay.SetMargins(0,0)
3048        gridDisplay.SetRowLabelSize(0)
3049        gridDisplay.AutoSizeColumns(False)
3050        for r in range(gridDisplay.GetNumberRows()):
3051            for c in range(gridDisplay.GetNumberCols()):
3052                if c == 2:
3053                    gridDisplay.SetReadOnly(r,c,isReadOnly=False)
3054                else:
3055                    gridDisplay.SetReadOnly(r,c,isReadOnly=True)
3056        mainSizer.Add(gridDisplay,0,WACV)
3057    mainSizer.Layout()   
3058    G2frame.dataDisplay.SetSizer(mainSizer)
3059    G2frame.dataDisplay.SetAutoLayout(1)
3060    G2frame.dataDisplay.SetupScrolling()
3061    Size = mainSizer.Fit(G2frame.dataFrame)
3062    Size[0] += 25
3063    G2frame.dataDisplay.SetSize(Size)
3064    G2frame.dataFrame.setSizePosLeft(Size)   
3065   
3066################################################################################
3067#####  Reflection list
3068################################################################################           
3069       
3070def UpdateReflectionGrid(G2frame,data,HKLF=False,Name=''):
3071    '''respond to selection of PWDR Reflections data tree item by displaying
3072    a table of reflections in the data window.
3073    '''
3074    def OnPlotHKL(event):
3075        '''Plots a layer of reflections
3076        '''
3077        phaseName = G2frame.RefList
3078        if phaseName not in ['Unknown',]:
3079            pId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Phases')
3080            phaseId =  G2gd.GetPatternTreeItemId(G2frame,pId,phaseName)
3081            General = G2frame.PatternTree.GetItemPyData(phaseId)['General']
3082            Super = General.get('Super',0)
3083            SuperVec = General.get('SuperVec',[])
3084        else:
3085            Super = 0
3086            SuperVec = []       
3087        if 'list' in str(type(data)):   #single crystal data is 2 dict in list
3088            refList = data[1]['RefList']
3089        else:                           #powder data is a dict of dicts; each same structure as SC 2nd dict
3090            refList = np.array(data[phaseName]['RefList'])
3091        FoMax = np.max(refList.T[8+Super])
3092        Hmin = np.array([int(np.min(refList.T[0])),int(np.min(refList.T[1])),int(np.min(refList.T[2]))])
3093        Hmax = np.array([int(np.max(refList.T[0])),int(np.max(refList.T[1])),int(np.max(refList.T[2]))])
3094        controls = {'Type' : 'Fo','ifFc' : True,'HKLmax' : Hmax,'HKLmin' : Hmin,
3095            'FoMax' : FoMax,'Zone' : '001','Layer' : 0,'Scale' : 1.0,'Super':Super,'SuperVec':SuperVec}
3096        G2plt.PlotSngl(G2frame,newPlot=True,Data=controls,hklRef=refList,Title=phaseName)
3097       
3098    def OnPlot3DHKL(event):
3099        '''Plots the reflections in 3D
3100        '''
3101        phaseName = G2frame.RefList
3102        if phaseName not in ['Unknown',]:
3103            pId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Phases')
3104            phaseId =  G2gd.GetPatternTreeItemId(G2frame,pId,phaseName)
3105            General = G2frame.PatternTree.GetItemPyData(phaseId)['General']
3106            Super = General.get('Super',0)
3107            SuperVec = General.get('SuperVec',[])
3108        else:
3109            Super = 0
3110            SuperVec = []       
3111        if 'list' in str(type(data)):   #single crystal data is 2 dict in list
3112            refList = data[1]['RefList']
3113        else:                           #powder data is a dict of dicts; each same structure as SC 2nd dict
3114            refList = np.array(data[phaseName]['RefList'])
3115        FoMax = np.max(refList.T[8+Super])
3116        Hmin = np.array([int(np.min(refList.T[0])),int(np.min(refList.T[1])),int(np.min(refList.T[2]))])
3117        Hmax = np.array([int(np.max(refList.T[0])),int(np.max(refList.T[1])),int(np.max(refList.T[2]))])
3118        Vpoint = [int(np.mean(refList.T[0])),int(np.mean(refList.T[1])),int(np.mean(refList.T[2]))]
3119        controls = {'Type':'Fosq','Iscale':False,'HKLmax':Hmax,'HKLmin':Hmin,
3120            'FoMax' : FoMax,'Scale' : 1.0,'Drawing':{'viewPoint':[Vpoint,[]],'default':Vpoint[:],
3121            'backColor':[0,0,0],'depthFog':False,'Zclip':10.0,'cameraPos':10.,'Zstep':0.05,
3122            'Scale':1.0,'oldxy':[],'viewDir':[1,0,0]},'Super':Super,'SuperVec':SuperVec}
3123        G2plt.Plot3DSngl(G2frame,newPlot=True,Data=controls,hklRef=refList,Title=phaseName)
3124       
3125    def MakeReflectionTable(phaseName):
3126        '''Returns a wx.grid table (G2G.Table) containing a list of all reflections
3127        for a phase.       
3128        '''
3129        if phaseName not in ['Unknown',]:
3130            pId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Phases')
3131            phaseId =  G2gd.GetPatternTreeItemId(G2frame,pId,phaseName)
3132            General = G2frame.PatternTree.GetItemPyData(phaseId)['General']
3133            Super = General.get('Super',0)
3134            SuperVec = General.get('SuperVec',[])
3135        else:
3136            Super = 0
3137            SuperVec = []       
3138        rowLabels = []
3139        if HKLF:
3140            refList = data[1]['RefList']
3141            refs = refList
3142        else:
3143            if len(data) > 1:
3144                G2frame.dataFrame.SelectPhase.Enable(True)
3145            try:            #patch for old reflection lists
3146                if not len(data[phaseName]):
3147                    return None
3148                refList = np.array(data[phaseName]['RefList'])
3149                I100 = refList.T[8+Super]*refList.T[11+Super]
3150            except TypeError:
3151                refList = np.array([refl[:11+Super] for refl in data[phaseName]])
3152                I100 = refList.T[8+Super]*np.array([refl[11+Super] for refl in data[phaseName]])
3153            Imax = np.max(I100)
3154            if Imax:
3155                I100 *= 100.0/Imax
3156            if 'C' in Inst['Type'][0]:
3157                refs = np.vstack((refList.T[:15+Super],I100)).T
3158            elif 'T' in Inst['Type'][0]:
3159                refs = np.vstack((refList.T[:18+Super],I100)).T
3160            G2frame.HKL = np.vstack((refList.T[:6+Super])).T    #build for plots
3161        rowLabels = [str(i) for i in range(len(refs))]
3162        Types = (4+Super)*[wg.GRID_VALUE_LONG,]+4*[wg.GRID_VALUE_FLOAT+':10,4',]+ \
3163            2*[wg.GRID_VALUE_FLOAT+':10,2',]+[wg.GRID_VALUE_FLOAT+':10,3',]+ \
3164            [wg.GRID_VALUE_FLOAT+':10,3',]
3165        if HKLF:
3166            colLabels = ['H','K','L','twin','d','Fosq','sig','Fcsq','FoTsq','FcTsq','phase','ExtC',]
3167            if 'T' in Inst['Type'][0]:
3168                colLabels = ['H','K','L','twin','d','Fosq','sig','Fcsq','FoTsq','FcTsq','phase','ExtC','wave','tbar']
3169                Types += 2*[wg.GRID_VALUE_FLOAT+':10,3',]
3170            if Super:
3171                colLabels.insert(3,'M')
3172        else:
3173            if 'C' in Inst['Type'][0]:
3174                colLabels = ['H','K','L','mul','d','pos','sig','gam','Fosq','Fcsq','phase','Icorr','Prfo','Trans','ExtP','I100']
3175                Types += 4*[wg.GRID_VALUE_FLOAT+':10,3',]
3176            elif 'T' in Inst['Type'][0]:
3177                colLabels = ['H','K','L','mul','d','pos','sig','gam','Fosq','Fcsq','phase','Icorr','alp','bet','wave','Prfo','Abs','Ext','I100']
3178                Types += 7*[wg.GRID_VALUE_FLOAT+':10,3',]
3179            if Super:
3180                colLabels.insert(3,'M')
3181        return G2G.Table(refs,rowLabels=rowLabels,colLabels=colLabels,types=Types)
3182
3183    def ShowReflTable(phaseName):
3184        '''Posts a table of reflections for a phase, creating the table
3185        if needed using MakeReflectionTable
3186        '''
3187        def setBackgroundColors(im,it):
3188            for r in range(G2frame.refTable[phaseName].GetNumberRows()):
3189                if HKLF:
3190                    if float(G2frame.refTable[phaseName].GetCellValue(r,3+im)) <= 0.:
3191                        G2frame.refTable[phaseName].SetCellBackgroundColour(r,3+im,wx.RED)
3192                    Fosq = float(G2frame.refTable[phaseName].GetCellValue(r,5+im))
3193                    Fcsq = float(G2frame.refTable[phaseName].GetCellValue(r,7+im))
3194                    sig = float(G2frame.refTable[phaseName].GetCellValue(r,6+im))
3195                    rat = abs(Fosq-Fcsq)/sig
3196                    if  rat > 10.:
3197                        G2frame.refTable[phaseName].SetCellBackgroundColour(r,7+im,wx.RED)
3198                    elif rat > 3.0:
3199                        G2frame.refTable[phaseName].SetCellBackgroundColour(r,7+im,wx.Colour(255,255,0))
3200#                    else:
3201#                        G2frame.refTable[phaseName].SetCellBackgroundColour(r,7+im,wx.WHITE)
3202                else:   #PWDR
3203                    if float(G2frame.refTable[phaseName].GetCellValue(r,12+im+it)) < 0.:
3204                        G2frame.refTable[phaseName].SetCellBackgroundColour(r,12+im+it,wx.RED)
3205                                                 
3206        G2frame.RefList = phaseName
3207        G2frame.dataFrame.SetLabel('Reflection List for '+phaseName)
3208        if HKLF:
3209            Status.SetStatusText('abs(DF)/sig > 10 red; > 3 yellow; twin < 0 (user rejected) red; twin=0 (sp. gp. absent) red')
3210        else:
3211            Status.SetStatusText('Prfo < 0. in red')
3212        it = 0
3213        if HKLF:
3214            im = data[1].get('Super',0)
3215        else:
3216            if 'T' in data[phaseName].get('Type',''):
3217                it = 3
3218            im = data[phaseName].get('Super',0)
3219        # has this table already been displayed?
3220        if G2frame.refTable[phaseName].GetTable() is None:
3221            PeakTable = MakeReflectionTable(phaseName)
3222            G2frame.refTable[phaseName].SetTable(PeakTable, True)
3223            G2frame.refTable[phaseName].EnableEditing(False)
3224            G2frame.refTable[phaseName].SetMargins(0,0)
3225            G2frame.refTable[phaseName].AutoSizeColumns(False)
3226            setBackgroundColors(im,it)
3227        # raise the tab (needed for 1st use and from OnSelectPhase)
3228        for PageNum in range(G2frame.dataDisplay.GetPageCount()):
3229            if phaseName == G2frame.dataDisplay.GetPageText(PageNum):
3230                G2frame.dataDisplay.SetSelection(PageNum)
3231                break
3232        else:
3233            print phaseName
3234            print phases
3235            raise Exception("how did we not find a phase name?")
3236       
3237    def OnPageChanged(event):
3238        '''Respond to a press on a phase tab by displaying the reflections. This
3239        routine is needed because the reflection table may not have been created yet.
3240        '''
3241        page = event.GetSelection()
3242        phaseName = G2frame.dataDisplay.GetPageText(page)
3243        ShowReflTable(phaseName)
3244
3245    def OnSelectPhase(event):
3246        '''For PWDR, selects a phase with a selection box. Called from menu.
3247        '''
3248        if len(phases) < 2: return
3249        dlg = wx.SingleChoiceDialog(G2frame,'Select','Phase',phases)
3250        try:
3251            if dlg.ShowModal() == wx.ID_OK:
3252                sel = dlg.GetSelection()
3253                ShowReflTable(phases[sel])
3254        finally:
3255            dlg.Destroy()
3256           
3257    if not data:
3258        print 'No phases, no reflections'
3259        return
3260    if HKLF:
3261        G2frame.RefList = 1
3262        phaseName = IsHistogramInAnyPhase(G2frame,Name)
3263        if not phaseName:
3264            phaseName = 'Unknown'
3265        phases = [phaseName]
3266    else:
3267        phaseName = G2frame.RefList
3268        phases = data.keys()
3269    if G2frame.dataDisplay:
3270        G2frame.dataFrame.Clear()
3271    Inst = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Instrument Parameters'))[0]
3272    if HKLF:
3273        G2gd.SetDataMenuBar(G2frame)
3274        G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.ReflMenu)
3275        if not G2frame.dataFrame.GetStatusBar():
3276            Status = G2frame.dataFrame.CreateStatusBar()   
3277        G2frame.Bind(wx.EVT_MENU, OnPlotHKL, id=G2gd.wxID_PWDHKLPLOT)
3278        G2frame.Bind(wx.EVT_MENU, OnPlot3DHKL, id=G2gd.wxID_PWD3DHKLPLOT)
3279        G2frame.dataFrame.SelectPhase.Enable(False)
3280    else:
3281        G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.ReflMenu)
3282        if not G2frame.dataFrame.GetStatusBar():
3283            Status = G2frame.dataFrame.CreateStatusBar()   
3284        G2frame.Bind(wx.EVT_MENU, OnSelectPhase, id=G2gd.wxID_SELECTPHASE)
3285        G2frame.Bind(wx.EVT_MENU, OnPlotHKL, id=G2gd.wxID_PWDHKLPLOT)
3286        G2frame.Bind(wx.EVT_MENU, OnPlot3DHKL, id=G2gd.wxID_PWD3DHKLPLOT)
3287        G2frame.dataFrame.SelectPhase.Enable(False)
3288           
3289    G2frame.dataDisplay = G2G.GSNoteBook(parent=G2frame.dataFrame,size=G2frame.dataFrame.GetClientSize())
3290    G2frame.refTable = {}
3291    for tabnum,phase in enumerate(phases):
3292        G2frame.refTable[phase] = G2G.GSGrid(parent=G2frame.dataDisplay)
3293        G2frame.dataDisplay.AddPage(G2frame.refTable[phase],phase)
3294#    if phaseName not in G2frame.refTable:
3295#        print phaseName
3296#        print phases
3297#        raise Exception("how did we get a invalid phase name?")   
3298    ShowReflTable(phaseName)
3299    G2frame.refTable[phaseName].Fit()
3300    size = G2frame.refTable[phaseName].GetSize()
3301    G2frame.dataFrame.setSizePosLeft([size[0]+32,350])       
3302    G2frame.dataDisplay.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CHANGED, OnPageChanged)
3303   
3304################################################################################
3305#####  SASD Substances
3306################################################################################
3307           
3308def UpdateSubstanceGrid(G2frame,data):
3309    '''respond to selection of SASD Substance data tree item.
3310    '''
3311    import Substances as substFile
3312   
3313    def OnLoadSubstance(event):
3314        names = substFile.Substances.keys()
3315        names.sort()
3316        dlg = wx.SingleChoiceDialog(G2frame, 'Which substance?', 'Select substance', names, wx.CHOICEDLG_STYLE)
3317        try:
3318            if dlg.ShowModal() == wx.ID_OK:
3319                name = names[dlg.GetSelection()]
3320            else:
3321                return
3322        finally:
3323            dlg.Destroy()
3324        data['Substances'][name] = {'Elements':{},'Volume':1.0,'Density':1.0,
3325            'Scatt density':0.0,'XAnom density':0.0,'XAbsorption':0.0}
3326        subst = substFile.Substances[name]
3327        ElList = subst['Elements'].keys()
3328        for El in ElList:
3329            Info = G2elem.GetAtomInfo(El.strip().capitalize())
3330            Info.update(subst['Elements'][El])
3331            data['Substances'][name]['Elements'][El] = Info
3332            if 'Volume' in subst:
3333                data['Substances'][name]['Volume'] = subst['Volume']
3334                data['Substances'][name]['Density'] = \
3335                    G2mth.Vol2Den(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])
3336            elif 'Density' in subst:
3337                data['Substances'][name]['Density'] = subst['Density']
3338                data['Substances'][name]['Volume'] = \
3339                    G2mth.Den2Vol(data['Substances'][name]['Elements'],data['Substances'][name]['Density'])
3340            else:
3341                data['Substances'][name]['Volume'] = G2mth.El2EstVol(data['Substances'][name]['Elements'])
3342                data['Substances'][name]['Density'] = \
3343                    G2mth.Vol2Den(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])
3344            data['Substances'][name]['Scatt density'] = \
3345                G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])[0]
3346            contrst,absorb = G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'],wave)         
3347            data['Substances'][name]['XAnom density'] = contrst
3348            data['Substances'][name]['XAbsorption'] = absorb
3349                         
3350        UpdateSubstanceGrid(G2frame,data)
3351       
3352    def OnCopySubstance(event):
3353        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
3354        histList = GetHistsLikeSelected(G2frame)
3355        if not histList:
3356            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
3357            return
3358        copyList = []
3359        dlg = G2G.G2MultiChoiceDialog(
3360            G2frame.dataFrame, 
3361            'Copy substances from\n'+hst[5:]+' to...',
3362            'Copy substances', histList)
3363        try:
3364            if dlg.ShowModal() == wx.ID_OK:
3365                for i in dlg.GetSelections(): 
3366                    copyList.append(histList[i])
3367        finally:
3368            dlg.Destroy()       
3369        for item in copyList:
3370            Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
3371            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Substances'),
3372                copy.copy(data))
3373   
3374    def OnAddSubstance(event):
3375        dlg = wx.TextEntryDialog(None,'Enter a name for this substance','Substance Name Entry','New substance',
3376            style=wx.OK)
3377        if dlg.ShowModal() == wx.ID_OK:
3378            Name = dlg.GetValue()
3379            data['Substances'][Name] = {'Elements':{},'Volume':1.0,'Density':1.0,
3380                'Scatt density':0.0,'XAnom density':0.,'XAbsorption':0.}
3381        dlg.Destroy()
3382        AddElement(Name)
3383        UpdateSubstanceGrid(G2frame,data)
3384       
3385    def OnDeleteSubstance(event):
3386        TextList = []
3387        for name in data['Substances']:
3388            if name != 'vacuum':
3389                TextList += [name,]
3390        if not TextList:
3391            return
3392        dlg = wx.SingleChoiceDialog(G2frame, 'Which substance?', 'Select substance to delete', TextList, wx.CHOICEDLG_STYLE)
3393        try:
3394            if dlg.ShowModal() == wx.ID_OK:
3395                name = TextList[dlg.GetSelection()]
3396            else:
3397                return
3398        finally:
3399            dlg.Destroy()
3400        del(data['Substances'][name])
3401        UpdateSubstanceGrid(G2frame,data)       
3402               
3403    def OnAddElement(event):       
3404        TextList = []
3405        for name in data['Substances']:
3406            if name != 'vacuum':
3407                TextList += [name,]
3408        if not TextList:
3409            return
3410        dlg = wx.SingleChoiceDialog(G2frame, 'Which substance?', 'Select substance', TextList, wx.CHOICEDLG_STYLE)
3411        try:
3412            if dlg.ShowModal() == wx.ID_OK:
3413                name = TextList[dlg.GetSelection()]
3414            else:
3415                return
3416        finally:
3417            dlg.Destroy()
3418        AddElement(name)
3419        UpdateSubstanceGrid(G2frame,data)
3420       
3421    def AddElement(name):
3422        ElList = data['Substances'][name]['Elements'].keys()
3423        dlg = G2elemGUI.PickElements(G2frame,ElList)
3424        if dlg.ShowModal() == wx.ID_OK:
3425            for El in dlg.Elem:
3426                El = El.strip().capitalize()
3427                Info = G2elem.GetAtomInfo(El)
3428                Info.update({'Num':1})
3429                data['Substances'][name]['Elements'][El] = Info
3430                data['Substances'][name]['Volume'] = G2mth.El2EstVol(data['Substances'][name]['Elements'])
3431                data['Substances'][name]['Density'] = \
3432                    G2mth.Vol2Den(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])
3433                data['Substances'][name]['Scatt density'] = \
3434                    G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])[0]
3435                contrst,absorb = G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'],wave)         
3436                data['Substances'][name]['XAnom density'] = contrst
3437                data['Substances'][name]['XAbsorption'] = absorb
3438        dlg.Destroy()
3439       
3440    def OnDeleteElement(event):
3441        TextList = []
3442        for name in data['Substances']:
3443            if name != 'vacuum':
3444                TextList += [name,]
3445        if not TextList:
3446            return
3447        dlg = wx.SingleChoiceDialog(G2frame, 'Which substance?', 'Select substance', TextList, wx.CHOICEDLG_STYLE)
3448        try:
3449            if dlg.ShowModal() == wx.ID_OK:
3450                name = TextList[dlg.GetSelection()]
3451            else:
3452                return
3453        finally:
3454            dlg.Destroy()
3455        ElList = data['Substances'][name]['Elements'].keys()
3456        if len(ElList):
3457            DE = G2elemGUI.DeleteElement(G2frame,ElList)
3458            if DE.ShowModal() == wx.ID_OK:
3459                El = DE.GetDeleteElement().strip().upper()
3460                del(data['Substances'][name]['Elements'][El])
3461                data['Substances'][name]['Volume'] = G2mth.El2EstVol(data['Substances'][name]['Elements'])
3462                data['Substances'][name]['Density'] = \
3463                    G2mth.Vol2Den(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])
3464                data['Substances'][name]['Scatt density'] = \
3465                    G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])[0]
3466                contrst,absorb = G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'],wave)         
3467                data['Substances'][name]['XAnom density'] = contrst
3468                data['Substances'][name]['XAbsorption'] = absorb
3469        UpdateSubstanceGrid(G2frame,data)
3470               
3471    def SubstSizer():
3472       
3473        def OnValueChange(event):
3474            Obj = event.GetEventObject()
3475            if len(Indx[Obj.GetId()]) == 3:
3476                name,El,keyId = Indx[Obj.GetId()]
3477                try:
3478                    value = max(0,float(Obj.GetValue()))
3479                except ValueError:
3480                    value = 0
3481                    Obj.SetValue('%.2f'%(value))
3482                data['Substances'][name]['Elements'][El][keyId] = value
3483                data['Substances'][name]['Volume'] = G2mth.El2EstVol(data['Substances'][name]['Elements'])
3484                data['Substances'][name]['Density'] = \
3485                    G2mth.Vol2Den(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])
3486            else:
3487                name,keyId = Indx[Obj.GetId()]
3488                try:
3489                    value = max(0,float(Obj.GetValue()))
3490                except ValueError:
3491                    value = 1.0
3492                data['Substances'][name][keyId] = value
3493                if keyId in 'Volume':
3494                    data['Substances'][name]['Density'] = \
3495                        G2mth.Vol2Den(data['Substances'][name]['Elements'],value)
3496                elif keyId in 'Density':
3497                    data['Substances'][name]['Volume'] = \
3498                        G2mth.Den2Vol(data['Substances'][name]['Elements'],value)
3499            data['Substances'][name]['Scatt density'] = \
3500                G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'])[0]
3501            contrst,absorb = G2mth.XScattDen(data['Substances'][name]['Elements'],data['Substances'][name]['Volume'],wave)         
3502            data['Substances'][name]['XAnom density'] = contrst
3503            data['Substances'][name]['XAbsorption'] = absorb
3504            wx.CallAfter(UpdateSubstanceGrid,G2frame,data)
3505       
3506        Indx = {}
3507        substSizer = wx.BoxSizer(wx.VERTICAL)
3508        substSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Substance list: wavelength: %.5fA'%(wave)),
3509            0,WACV)
3510        for name in data['Substances']:
3511            G2G.HorizontalLine(substSizer,G2frame.dataDisplay)   
3512            substSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Data for '+name+':'),
3513                0,WACV)
3514            if name == 'vacuum':
3515                substSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label='        Not applicable'),
3516                    0,WACV)
3517            else:   
3518                elSizer = wx.FlexGridSizer(0,6,5,5)
3519                Substance = data['Substances'][name]
3520                Elems = Substance['Elements']
3521                for El in Elems:    #do elements as pull downs for isotopes for neutrons
3522                    elSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' '+El+': '),
3523                        0,WACV)
3524                    num = wx.TextCtrl(G2frame.dataDisplay,value='%.2f'%(Elems[El]['Num']),style=wx.TE_PROCESS_ENTER)
3525                    Indx[num.GetId()] = [name,El,'Num']
3526                    num.Bind(wx.EVT_TEXT_ENTER,OnValueChange)       
3527                    num.Bind(wx.EVT_KILL_FOCUS,OnValueChange)
3528                    elSizer.Add(num,0,WACV)
3529                substSizer.Add(elSizer,0)
3530                vdsSizer = wx.FlexGridSizer(0,4,5,5)
3531                vdsSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Volume: '),
3532                    0,WACV)
3533                vol = wx.TextCtrl(G2frame.dataDisplay,value='%.3f'%(Substance['Volume']),style=wx.TE_PROCESS_ENTER)
3534                Indx[vol.GetId()] = [name,'Volume']
3535                vol.Bind(wx.EVT_TEXT_ENTER,OnValueChange)       
3536                vol.Bind(wx.EVT_KILL_FOCUS,OnValueChange)
3537                vdsSizer.Add(vol,0,WACV)               
3538                vdsSizer.Add(wx.StaticText(parent=G2frame.dataDisplay,label=' Density: '),
3539                    0,WACV)
3540                den = wx.TextCtrl(G2frame.dataDisplay,value='%.3f'%(Substance['Density']),style=wx.TE_PROCESS_ENTER)
3541                Indx[den.GetId()] = [name,'Density']
3542                den.Bind(wx.EVT_TEXT_ENTER,OnValueChange)       
3543                den.Bind(wx.EVT_KILL_FOCUS,OnValueChange)
3544                vdsSizer.Add(den,0,WACV)
3545                substSizer.Add(vdsSizer,0)
3546                substSizer.Add(wx.StaticText(G2frame.dataDisplay,
3547                    label=' Scattering density  : %.2f *10%scm%s'%(Substance['Scatt density'],Pwr10,Pwrm2)),
3548                    0,WACV)               
3549                substSizer.Add(wx.StaticText(G2frame.dataDisplay,       #allow neutrons here into NAnom density & NAbsorption
3550                    label=' Anomalous density : %.2f *10%scm%s'%(Substance['XAnom density'],Pwr10,Pwrm2)),
3551                    0,WACV)               
3552                substSizer.Add(wx.StaticText(G2frame.dataDisplay,
3553                    label=' X-ray absorption   : %.2f cm%s'%(Substance['XAbsorption'],Pwrm1)),
3554                    0,WACV)               
3555        return substSizer
3556           
3557    Inst = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,G2frame.PatternId, 'Instrument Parameters'))[0]
3558    wave = G2mth.getWave(Inst)
3559    if G2frame.dataDisplay:
3560        G2frame.dataFrame.DestroyChildren()  # is this a ScrolledWindow? If so, bad!
3561    G2gd.SetDataMenuBar(G2frame,G2frame.dataFrame.SubstanceMenu)
3562    if not G2frame.dataFrame.GetStatusBar():
3563        Status = G2frame.dataFrame.CreateStatusBar()
3564    G2frame.dataDisplay = wxscroll.ScrolledPanel(G2frame.dataFrame)
3565    G2frame.dataFrame.SetLabel('Substances')
3566    G2frame.dataFrame.Bind(wx.EVT_MENU, OnLoadSubstance, id=G2gd.wxID_LOADSUBSTANCE)   
3567    G2frame.dataFrame.Bind(wx.EVT_MENU, OnAddSubstance, id=G2gd.wxID_ADDSUBSTANCE)
3568    G2frame.dataFrame.Bind(wx.EVT_MENU, OnCopySubstance, id=G2gd.wxID_COPYSUBSTANCE)
3569    G2frame.dataFrame.Bind(wx.EVT_MENU, OnDeleteSubstance, id=G2gd.wxID_DELETESUBSTANCE)   
3570    G2frame.dataFrame.Bind(wx.EVT_MENU, OnAddElement, id=G2gd.wxID_ELEMENTADD)
3571    G2frame.dataFrame.Bind(wx.EVT_MENU, OnDeleteElement, id=G2gd.wxID_ELEMENTDELETE)
3572    mainSizer = wx.BoxSizer(wx.VERTICAL)
3573    mainSizer.Add(SubstSizer(),0)
3574
3575    mainSizer.Layout()   
3576    G2frame.dataDisplay.SetSizer(mainSizer)
3577    G2frame.dataDisplay.SetAutoLayout(1)
3578    G2frame.dataDisplay.SetupScrolling()
3579    Size = mainSizer.Fit(G2frame.dataFrame)
3580    Size[0] += 25
3581    G2frame.dataDisplay.SetSize(Size)
3582    G2frame.dataFrame.setSizePosLeft(Size)   
3583       
3584################################################################################
3585#####  SASD Models
3586################################################################################           
3587       
3588def UpdateModelsGrid(G2frame,data):
3589    '''respond to selection of SASD Models data tree item.
3590    '''
3591    #patches
3592    if 'Current' not in data:
3593        data['Current'] = 'Size dist.'
3594    if 'logBins' not in data['Size']:
3595        data['Size']['logBins'] = True
3596    if 'MinMaxDiam' in data['Size']:
3597        data['Size']['MinDiam'] = 50.
3598        data['Size']['MaxDiam'] = 10000.
3599        del data['Size']['MinMaxDiam']
3600    if isinstance(data['Size']['MaxEnt']['Sky'],float):
3601        data['Size']['MaxEnt']['Sky'] = -3
3602    if 'Power' not in data['Size']['IPG']:
3603        data['Size']['IPG']['Power'] = -1
3604    if 'Matrix' not in data['Particle']:
3605        data['Particle']['Matrix'] = {'Name':'vacuum','VolFrac':[0.0,False]}
3606    if 'BackFile' not in data:
3607        data['BackFile'] = ''
3608    #end patches
3609   
3610    def RefreshPlots(newPlot=False):
3611        PlotText = G2frame.G2plotNB.nb.GetPageText(G2frame.G2plotNB.nb.GetSelection())
3612        if 'Powder' in PlotText:
3613            G2plt.PlotPatterns(G2frame,plotType='SASD',newPlot=newPlot)
3614        elif 'Size' in PlotText:
3615            G2plt.PlotSASDSizeDist(G2frame)
3616               
3617    def OnAddModel(event):
3618        if data['Current'] == 'Particle fit':
3619            material = 'vacuum'
3620            if len(data['Particle']['Levels']):
3621                material = data['Particle']['Levels'][-1]['Controls']['Material']
3622            data['Particle']['Levels'].append({
3623                'Controls':{'FormFact':'Sphere','DistType':'LogNormal','Material':material,
3624                    'FFargs':{},'SFargs':{},'NumPoints':50,'Cutoff':0.01,'Contrast':0.0,
3625                    'SlitSmear':[0.0,False],'StrFact':'Dilute'},    #last 2 not used - future?
3626                'LogNormal':{'Volume':[0.05,False],'Mean':[1000.,False],'StdDev':[0.5,False],'MinSize':[10.,False],},
3627                'Gaussian':{'Volume':[0.05,False],'Mean':[1000.,False],'StdDev':[300.,False],},
3628                'LSW':{'Volume':[0.05,False],'Mean':[1000.0,False],},
3629                'Schulz-Zimm':{'Volume':[0.05,False],'Mean':[1000.,False],'StdDev':[300.,False],},
3630                'Unified':{'G':[1.e3,False],'Rg':[100,False],'B':[1.e-5,False],'P':[4,False],'Cutoff':[1e-5,False],},
3631                'Porod':{'B':[1.e-4,False],'P':[4,False],'Cutoff':[1e-5,False],},
3632                'Monodisperse':{'Volume':[0.05,False],'Radius':[100,False],},   #OK for spheres
3633                'Bragg':{'PkInt':[100,False],'PkPos':[0.2,False],
3634                    'PkSig':[10,False],'PkGam':[10,False],},        #reasonable 31A peak
3635                })
3636            G2sasd.ModelFxn(Profile,ProfDict,Limits,Sample,data)
3637            RefreshPlots(True)
3638                   
3639        wx.CallAfter(UpdateModelsGrid,G2frame,data)
3640       
3641    def OnCopyModel(event):
3642        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
3643        histList = GetHistsLikeSelected(G2frame)
3644        if not histList:
3645            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
3646            return
3647        copyList = []
3648        dlg = G2G.G2MultiChoiceDialog(
3649            G2frame.dataFrame, 
3650            'Copy models from\n'+hst[5:]+' to...',
3651            'Copy models', histList)
3652        try:
3653            if dlg.ShowModal() == wx.ID_OK:
3654                for i in dlg.GetSelections(): 
3655                    copyList.append(histList[i])
3656        finally:
3657            dlg.Destroy()       
3658        for item in copyList:
3659            Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
3660            newdata = copy.deepcopy(data)
3661            G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Models'),newdata)
3662            if newdata['BackFile']:
3663                Profile = G2frame.PatternTree.GetItemPyData(Id)[1]
3664                BackId = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,newdata['BackFile'])
3665                BackSample = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,BackId, 'Sample Parameters'))
3666                Profile[5] = BackSample['Scale'][0]*G2frame.PatternTree.GetItemPyData(BackId)[1][1]
3667        RefreshPlots(True)
3668               
3669    def OnCopyFlags(event):
3670        thisModel = copy.deepcopy(data)
3671        hst = G2frame.PatternTree.GetItemText(G2frame.PatternId)
3672        histList = GetHistsLikeSelected(G2frame)
3673        if not histList:
3674            G2frame.ErrorDialog('No match','No histograms match '+hst,G2frame.dataFrame)
3675            return
3676        dlg = G2G.G2MultiChoiceDialog(
3677            G2frame.dataFrame, 
3678            'Copy sample ref. flags from\n'+str(hst[5:])+' to...',
3679            'Copy sample flags', histList)
3680        distChoice = ['LogNormal','Gaussian','LSW','Schulz-Zimm','Bragg','Unified',
3681            'Porod','Monodisperse',]
3682        parmOrder = ['Volume','Radius','Mean','StdDev','G','Rg','B','P',
3683            'Cutoff','PkInt','PkPos','PkSig','PkGam','VolFr','Dist',]
3684        try:
3685            if dlg.ShowModal() == wx.ID_OK:
3686                result = dlg.GetSelections()
3687                for i in result: 
3688                    item = histList[i]
3689                    Id = G2gd.GetPatternTreeItemId(G2frame,G2frame.root,item)
3690                    newModel = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id,'Models'))
3691                    newModel['Back'][1] = copy.copy(thisModel['Back'][1])
3692                    for ilev,level in enumerate(newModel['Particle']['Levels']):
3693                        for form in level:
3694                            if form in distChoice:
3695                                thisForm = thisModel['Particle']['Levels'][ilev][form]                               
3696                                for item in parmOrder:
3697                                    if item in thisForm:
3698                                       level[form][item][1] = copy.copy(thisForm[item][1])
3699                            elif form == 'Controls':
3700                                thisForm = thisModel['Particle']['Levels'][ilev][form]['SFargs']
3701                                for item in parmOrder:
3702                                    if item in thisForm:
3703                                        level[form]['SFargs'][item][1] = copy.copy(thisForm[item][1])
3704        finally:
3705            dlg.Destroy()
3706               
3707    def OnFitModelAll(event):
3708        choices = G2gd.GetPatternTreeDataNames(G2frame,['SASD',])
3709        sel = []
3710        dlg = G2G.G2MultiChoiceDialog(G2frame.dataFrame, 'Sequential SASD refinement',
3711             'Select dataset to include',choices)
3712        dlg.SetSelections(sel)
3713        names = []
3714        if dlg.ShowModal() == wx.ID_OK:
3715            for sel in dlg.GetSelections():
3716                names.append(choices[sel])
3717        dlg.Destroy()
3718        SeqResult = {'histNames':names}
3719        Reverse = False
3720        CopyForward = False
3721        choice = ['Reverse sequence','Copy from prev.']
3722        dlg = wx.MultiChoiceDialog(G2frame.dataFrame,'Sequential controls','Select controls',choice)
3723        if dlg.ShowModal() == wx.ID_OK:
3724            for sel in dlg.GetSelections():
3725                if sel:
3726                    CopyForward = True
3727                else:
3728                    Reverse = True
3729        dlg.Destroy()
3730        dlg = wx.ProgressDialog('SASD Sequential fit','Data set name = '+names[0],len(names), 
3731            style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE|wx.PD_REMAINING_TIME|wx.PD_CAN_ABORT)
3732        wx.BeginBusyCursor()
3733        if Reverse:
3734            names.reverse()
3735        try:
3736            for i,name in enumerate(names):
3737                print ' Sequential fit for ',name
3738                GoOn = dlg.Update(i,newmsg='Data set name = '+name)[0]
3739                if not GoOn:
3740                    break
3741                Id =  G2gd.GetPatternTreeItemId(G2frame,G2frame.root,name)
3742                if i and CopyForward:
3743                    G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Models'),JModel)
3744                IProfDict,IProfile = G2frame.PatternTree.GetItemPyData(Id)[:2]
3745                IModel = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Models'))
3746                ISample = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Sample Parameters'))
3747                ILimits = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Limits'))
3748                IfOK,result,varyList,sig,Rvals,covMatrix,parmDict,Msg = G2sasd.ModelFit(IProfile,IProfDict,ILimits,ISample,IModel)
3749                JModel = copy.deepcopy(IModel)
3750                if not IfOK:
3751                    G2frame.ErrorDialog('Failed sequential refinement for data '+name,
3752                        ' Msg: '+Msg+'\nYou need to rethink your selection of parameters\n'+    \
3753                        ' Model restored to previous version for'+name)
3754                    SeqResult['histNames'] = names[:i]
3755                    dlg.Destroy()
3756                    break
3757                else:
3758                    G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,Id, 'Models'),copy.deepcopy(IModel))
3759               
3760                G2sasd.ModelFxn(IProfile,IProfDict,ILimits,ISample,IModel)
3761                SeqResult[name] = {'variables':result[0],'varyList':varyList,'sig':sig,'Rvals':Rvals,
3762                    'covMatrix':covMatrix,'title':name,'parmDict':parmDict}
3763            else:
3764                dlg.Destroy()
3765                print ' ***** Small angle sequential refinement successful *****'
3766        finally:
3767            wx.EndBusyCursor()   
3768        Id =  G2gd.GetPatternTreeItemId(G2frame,G2frame.root,'Sequential results')
3769        if Id:
3770            G2frame.PatternTree.SetItemPyData(Id,SeqResult)
3771        else:
3772            Id = G2frame.PatternTree.AppendItem(parent=G2frame.root,text='Sequential results')
3773            G2frame.PatternTree.SetItemPyData(Id,SeqResult)
3774        G2frame.PatternTree.SelectItem(Id)
3775       
3776    def OnFitModel(event):
3777        if data['Current'] == 'Size dist.':
3778            if not any(Sample['Contrast']):
3779                G2frame.ErrorDialog('No contrast; your sample is a vacuum!',
3780                    'You need to define a scattering substance!\n'+    \
3781                    ' Do Substances and then Sample parameters')
3782                return
3783            G2sasd.SizeDistribution(Profile,ProfDict,Limits,Sample,data)
3784            G2plt.PlotSASDSizeDist(G2frame)
3785            RefreshPlots(True)
3786           
3787        elif data['Current'] == 'Particle fit':
3788            SaveState()
3789            Results = G2sasd.ModelFit(Profile,ProfDict,Limits,Sample,data)
3790            if not Results[0]:
3791                    G2frame.ErrorDialog('Failed refinement',
3792                        ' Msg: '+Results[-1]+'\nYou need to rethink your selection of parameters\n'+    \
3793                        ' Model restored to previous version')
3794            G2sasd.ModelFxn(Profile,ProfDict,Limits,Sample,data)
3795            RefreshPlots(True)
3796            wx.CallAfter(UpdateModelsGrid,G2frame,data)
3797           
3798    def OnUnDo(event):
3799        DoUnDo()
3800        data = G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,
3801            G2frame.PatternId,'Models'))
3802        G2frame.dataFrame.SasdUndo.Enable(False)
3803        UpdateModelsGrid(G2frame,data)
3804        G2sasd.ModelFxn(Profile,ProfDict,Limits,Sample,data)
3805        RefreshPlots(True)
3806
3807    def DoUnDo():
3808        print 'Undo last refinement'
3809        file = open(G2frame.undosasd,'rb')
3810        PatternId = G2frame.PatternId
3811        G2frame.PatternTree.SetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId, 'Models'),cPickle.load(file))
3812        print ' Models recovered'
3813        file.close()
3814       
3815    def SaveState():
3816        G2frame.undosasd = os.path.join(G2frame.dirname,'GSASIIsasd.save')
3817        file = open(G2frame.undosasd,'wb')
3818        PatternId = G2frame.PatternId
3819        for item in ['Models']:
3820            cPickle.dump(G2frame.PatternTree.GetItemPyData(G2gd.GetPatternTreeItemId(G2frame,PatternId,item)),file,1)
3821        file.close()
3822        G2frame.dataFrame.SasdUndo.Enable(True)
3823       
3824    def OnSelectFit(event):
3825        data['Current'] = fitSel.GetValue()
3826        wx.CallAfter(UpdateModelsGrid,G2frame,data)
3827       
3828    def OnCheckBox(event):
3829        Obj = event.GetEventObject()
3830        item,ind = Indx[Obj.GetId()]
3831        item[ind] = Obj.GetValue()
3832       
3833    def OnIntVal(event):
3834        Obj = event.GetEventObject()
3835        item,ind,minVal = Indx[Obj.GetId()]
3836        try:
3837            value = int(Obj.GetValue())
3838            if value <= minVal:
3839                raise ValueError
3840        except ValueError:
3841            value = item[ind]
3842        Obj.SetValue(str(value))
3843        item[ind] = value
3844
3845    def SizeSizer():
3846       
3847        def OnShape(event):
3848            data['Size']['Shape'][0] = partsh.GetValue()
3849            wx.CallAfter(UpdateModelsGrid,G2frame,data)
3850           
3851        def OnMethod(event):
3852            data['Size']['Method'] = method.GetValue()
3853            wx.CallAfter(UpdateModelsGrid,G2frame,data)
3854           
3855        def OnPartVal(event):
3856            try:
3857                val = max(0.0,float(partprm.GetValue()))
3858            except ValueError:
3859                val = 1
3860            data['Size']['Shape'][1] = val
3861            partprm.SetValue('%.3f'%(val))
3862           
3863        sizeSizer = wx.BoxSizer(wx.VERTICAL)
3864        sizeSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Size distribution parameters: '),0,WACV)
3865        binSizer = wx.FlexGridSizer(0,7,5,5)
3866        binSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' No. size bins: '),0,WACV)
3867        bins = ['50','100','150','200']
3868        nbins = wx.ComboBox(G2frame.dataDisplay,value=str(data['Size']['Nbins']),choices=bins,
3869            style=wx.CB_READONLY|wx.CB_DROPDOWN)
3870        Indx[nbins.GetId()] = [data['Size'],'Nbins',0]
3871        nbins.Bind(wx.EVT_COMBOBOX,OnIntVal)       
3872        binSizer.Add(nbins,0,WACV)
3873        binSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Min diam.: '),0,WACV)
3874        minDias = ['10','25','50','100','150','200']
3875        mindiam = wx.ComboBox(G2frame.dataDisplay,value=str(data['Size']['MinDiam']),choices=minDias,
3876            style=wx.CB_DROPDOWN)
3877        mindiam.Bind(wx.EVT_LEAVE_WINDOW,OnIntVal)
3878        mindiam.Bind(wx.EVT_TEXT_ENTER,OnIntVal)       
3879        mindiam.Bind(wx.EVT_KILL_FOCUS,OnIntVal)
3880        Indx[mindiam.GetId()] = [data['Size'],'MinDiam',0]
3881        binSizer.Add(mindiam,0,WACV)
3882        binSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Max diam.: '),0,WACV)
3883        maxDias = [str(1000*(i+1)) for i in range(10)]
3884        maxdiam = wx.ComboBox(G2frame.dataDisplay,value=str(data['Size']['MaxDiam']),choices=maxDias,
3885            style=wx.CB_DROPDOWN)
3886        maxdiam.Bind(wx.EVT_LEAVE_WINDOW,OnIntVal)
3887        maxdiam.Bind(wx.EVT_TEXT_ENTER,OnIntVal)       
3888        maxdiam.Bind(wx.EVT_KILL_FOCUS,OnIntVal)
3889        Indx[maxdiam.GetId()] = [data['Size'],'MaxDiam',0]
3890        binSizer.Add(maxdiam,0,WACV)
3891        logbins = wx.CheckBox(G2frame.dataDisplay,label='Log bins?')
3892        Indx[logbins.GetId()] = [data['Size'],'logBins']
3893        logbins.SetValue(data['Size']['logBins'])
3894        logbins.Bind(wx.EVT_CHECKBOX, OnCheckBox)
3895        binSizer.Add(logbins,0,WACV)
3896        sizeSizer.Add(binSizer,0)
3897        sizeSizer.Add((5,5),0)
3898        partSizer = wx.BoxSizer(wx.HORIZONTAL)
3899        partSizer.Add(wx.StaticText(G2frame.dataDisplay,label='Particle description: '),0,WACV)
3900        shapes = {'Spheroid':' Aspect ratio: ','Cylinder':' Diameter ','Cylinder AR':' Aspect ratio: ',
3901            'Unified sphere':'','Unified rod':' Diameter: ','Unified rod AR':' Aspect ratio: ',
3902            'Unified disk':' Thickness: '}
3903        partsh = wx.ComboBox(G2frame.dataDisplay,value=str(data['Size']['Shape'][0]),choices=shapes.keys(),
3904            style=wx.CB_READONLY|wx.CB_DROPDOWN)
3905        partsh.Bind(wx.EVT_COMBOBOX,OnShape)       
3906        partSizer.Add(partsh,0,WACV)
3907        if data['Size']['Shape'][0] not in ['Unified sphere',]:
3908            partSizer.Add(wx.StaticText(G2frame.dataDisplay,label=shapes[data['Size']['Shape'][0]]),0,WACV)
3909            partprm = wx.TextCtrl(G2frame.dataDisplay,value='%.3f'%(data['Size']['Shape'][1]),
3910                style=wx.TE_PROCESS_ENTER)
3911            partprm.Bind(wx.EVT_TEXT_ENTER,OnPartVal)       
3912            partprm.Bind(wx.EVT_KILL_FOCUS,OnPartVal)
3913            partSizer.Add(partprm,0,WACV)
3914        sizeSizer.Add(partSizer,0)
3915        sizeSizer.Add((5,5),0)
3916        fitSizer = wx.BoxSizer(wx.HORIZONTAL)
3917        methods = ['MaxEnt','IPG',]
3918        fitSizer.Add(wx.StaticText(G2frame.dataDisplay,label='Fitting method: '),0,WACV)
3919        method = wx.ComboBox(G2frame.dataDisplay,value=data['Size']['Method'],choices=methods,
3920            style=wx.CB_READONLY|wx.CB_DROPDOWN)
3921        method.Bind(wx.EVT_COMBOBOX,OnMethod)
3922        fitSizer.Add(method,0,WACV)
3923        iters = ['10','25','50','100','150','200']       
3924        fitSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' No. iterations: '),0,WACV)
3925        Method = data['Size']['Method']
3926        iter = wx.ComboBox(G2frame.dataDisplay,value=str(data['Size'][Method]['Niter']),choices=iters,
3927            style=wx.CB_READONLY|wx.CB_DROPDOWN)
3928        Indx[iter.GetId()] = [data['Size'][Method],'Niter',0]
3929        iter.Bind(wx.EVT_COMBOBOX,OnIntVal)
3930        fitSizer.Add(iter,0,WACV)
3931        if 'MaxEnt' in data['Size']['Method']:
3932            fitSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Log floor factor: '),0,WACV)
3933            floors = [str(-i) for i in range(9)]
3934            floor = wx.ComboBox(G2frame.dataDisplay,value=str(data['Size']['MaxEnt']['Sky']),choices=floors,
3935                style=wx.CB_READONLY|wx.CB_DROPDOWN)
3936            Indx[floor.GetId()] = [data['Size']['MaxEnt'],'Sky',-10]
3937            floor.Bind(wx.EVT_COMBOBOX,OnIntVal)
3938            fitSizer.Add(floor,0,WACV)
3939        elif 'IPG' in data['Size']['Method']:
3940            fitSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Q power weight (-1 for sigma): '),0,WACV)
3941            choices = ['-1','0','1','2','3','4']
3942            power = wx.ComboBox(G2frame.dataDisplay,value=str(data['Size']['IPG']['Power']),choices=choices,
3943                style=wx.CB_READONLY|wx.CB_DROPDOWN)
3944            Indx[power.GetId()] = [data['Size']['IPG'],'Power',-2]
3945            power.Bind(wx.EVT_COMBOBOX,OnIntVal)
3946            fitSizer.Add(power,0,WACV)
3947        sizeSizer.Add(fitSizer,0)
3948
3949        return sizeSizer
3950       
3951    def PartSizer():
3952       
3953        FormFactors = {'Sphere':{},'Spheroid':{'Aspect ratio':[1.0,False]},
3954            'Cylinder':{'Length':[100.,False]},'Cylinder diam':{'Diameter':[100.,False]},
3955            'Cylinder AR':{'Aspect ratio':[1.0,False]},'Unified sphere':{},
3956            'Unified rod':{'Length':[100.,False]},'Unified rod AR':{'Aspect ratio':[1.0,False]},
3957            'Unified disk':{'Thickness':[100.,False]},
3958            'Unified tube':{'Length':[100.,False],'Thickness':[10.,False]},}
3959               
3960        StructureFactors = {'Dilute':{},'Hard sphere':{'VolFr':[0.1,False],'Dist':[100.,False]},
3961            'Sticky hard sphere':{'VolFr':[0.1,False],'Dist':[100.,False],'epis':[0.05,False],'Sticky':[0.2,False]},
3962            'Square well':{'VolFr':[0.1,False],'Dist':[100.,False],'Depth':[0.1,False],'Width':[1.,False]},
3963            'InterPrecipitate':{'VolFr':[0.1,False],'Dist':[100.,False]},}
3964               
3965        ffDistChoices =  ['Sphere','Spheroid','Cylinder','Cylinder diam',
3966            'Cylinder AR','Unified sphere','Unified rod','Unified rod AR',
3967            'Unified disk','Unified tube',]
3968               
3969        ffMonoChoices = ['Sphere','Spheroid','Cylinder','Cylinder AR',]
3970       
3971        sfChoices = ['Dilute','Hard sphere','Sticky hard sphere','Square well','InterPrecipitate',]
3972           
3973        slMult = 1000.
3974                 
3975        def OnValue(event):
3976            Obj = event.GetEventObject()
3977            item,key,sldrObj = Indx[Obj.GetId()]
3978            try:
3979                value = float(Obj.GetValue())
3980                if value <= 0.:
3981                    raise ValueError
3982            except ValueError:
3983                value = item[key][0]
3984            item[key][0] = value
3985            Obj.SetValue('%.3g'%(value))
3986            if key in ['P','epis','Sticky','Depth','Width','VolFr','Dist']:
3987                sldrObj.SetValue(slMult*value)
3988            else:
3989                logv = np.log10(value)
3990                valMinMax = [logv-1,logv+1]
3991                sldrObj.SetRange(slMult*valMinMax[0],slMult*valMinMax[1])
3992                sldrObj.SetValue(slMult*logv)
3993            G2sasd.ModelFxn(Profile,ProfDict,Limits,Sample,data)
3994            RefreshPlots()
3995           
3996        def OnSelect(event):
3997            Obj = event.GetEventObject()
3998            item,key = Indx[Obj.GetId()]
3999            item[key] = Obj.GetValue()
4000            if 'Refine' not in Obj.GetLabel():
4001                if 'FormFact' in key :
4002                    item['FFargs'] = FormFactors[Obj.GetValue()]
4003                elif 'StrFact' in key:
4004                    item['SFargs'] = StructureFactors[Obj.GetValue()]
4005                wx.CallAfter(UpdateModelsGrid,G2frame,data)
4006                G2sasd.ModelFxn(Profile,ProfDict,Limits,Sample,data)
4007                RefreshPlots()
4008               
4009        def OnDelLevel(event):
4010            Obj = event.GetEventObject()
4011            item = Indx[Obj.GetId()]
4012            del data['Particle']['Levels'][item]
4013            wx.CallAfter(UpdateModelsGrid,G2frame,data)
4014            G2sasd.ModelFxn(Profile,ProfDict,Limits,Sample,data)
4015            RefreshPlots()
4016           
4017        def OnParmSlider(event):
4018            Obj = event.GetEventObject()
4019            item,key,pvObj = Indx[Obj.GetId()]
4020            slide = Obj.GetValue()
4021            if key in ['P','epis','Sticky','Depth','Width','VolFr','Dist']:
4022                value = float(slide/slMult)
4023            else:
4024                value = 10.**float(slide/slMult)
4025            item[key][0] = value
4026            pvObj.SetValue('%.3g'%(item[key][0]))
4027            G2sasd.ModelFxn(Profile,ProfDict,Limits,Sample,data)
4028            RefreshPlots()
4029           
4030        def SizeSizer():
4031            sizeSizer = wx.FlexGridSizer(0,4,5,5)
4032            sizeSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Distribution: '),0,WACV)
4033            Distchoice = ['LogNormal','Gaussian','LSW','Schulz-Zimm','Bragg','Unified','Porod','Monodisperse',]
4034            distChoice = wx.ComboBox(G2frame.dataDisplay,value=level['Controls']['DistType'],choices=Distchoice,
4035                style=wx.CB_READONLY|wx.CB_DROPDOWN)
4036            Indx[distChoice.GetId()] = [level['Controls'],'DistType']
4037            distChoice.Bind(wx.EVT_COMBOBOX,OnSelect)
4038            sizeSizer.Add(distChoice,0,WACV)    #put structure factor choices here
4039            if level['Controls']['DistType'] not in ['Bragg','Unified','Porod',]:
4040                sizeSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Form Factor: '),0,WACV)
4041                if 'Mono' in level['Controls']['DistType']:
4042                    ffChoice = wx.ComboBox(G2frame.dataDisplay,value=level['Controls']['FormFact'],choices=ffMonoChoices,
4043                        style=wx.CB_READONLY|wx.CB_DROPDOWN)
4044                else:
4045                    ffChoice = wx.ComboBox(G2frame.dataDisplay,value=level['Controls']['FormFact'],choices=ffDistChoices,
4046                        style=wx.CB_READONLY|wx.CB_DROPDOWN)
4047                Indx[ffChoice.GetId()] = [level['Controls'],'FormFact']
4048                ffChoice.Bind(wx.EVT_COMBOBOX,OnSelect)
4049                sizeSizer.Add(ffChoice,0,WACV)
4050               
4051                sizeSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Material: '),0,WACV)
4052                matSel = wx.ComboBox(G2frame.dataDisplay,value=level['Controls']['Material'],
4053                    choices=Substances['Substances'].keys(),style=wx.CB_READONLY|wx.CB_DROPDOWN)
4054                Indx[matSel.GetId()] = [level['Controls'],'Material']
4055                matSel.Bind(wx.EVT_COMBOBOX,OnSelect)       
4056                sizeSizer.Add(matSel,0,WACV) #do neutron test here?
4057                rho = Substances['Substances'][level['Controls']['Material']].get('XAnom density',0.0)
4058                level['Controls']['Contrast'] = contrast = (rho-rhoMat)**2                 
4059                sizeSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Resonant X-ray contrast: '),0,WACV)
4060                sizeSizer.Add(wx.StaticText(G2frame.dataDisplay,label=%.2f 10%scm%s'%(contrast,Pwr20,Pwrm4)),0,WACV)
4061                if 'Mono' not in level['Controls']['DistType']:
4062                    sizeSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Num. radii: '),0,WACV)
4063                    radii = ['25','50','75','100','200']
4064                    nRadii = wx.ComboBox(G2frame.dataDisplay,value=str(level['Controls']['NumPoints']),choices=radii,
4065                        style=wx.CB_READONLY|wx.CB_DROPDOWN)
4066                    Indx[nRadii.GetId()] = [level['Controls'],'NumPoints']
4067                    nRadii.Bind(wx.EVT_COMBOBOX,OnSelect)
4068                    sizeSizer.Add(nRadii,0,WACV)
4069                    sizeSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' R dist. cutoff: '),0,WACV)
4070                    rCutoff = G2G.ValidatedTxtCtrl(G2frame.dataDisplay,level['Controls'],'Cutoff',
4071                        min=0.001,max=0.1,typeHint=float)
4072                    sizeSizer.Add(rCutoff,0,WACV)
4073            elif level['Controls']['DistType']  in ['Unified',]:
4074                Parms = level['Unified']
4075                Best = G2sasd.Bestimate(Parms['G'][0],Parms['Rg'][0],Parms['P'][0])
4076                sizeSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Estimated Dist B: %12.4g'%(Best)),0,WACV)
4077            return sizeSizer
4078           
4079        def ParmSizer():
4080            parmSizer = wx.FlexGridSizer(0,3,5,5)
4081            parmSizer.AddGrowableCol(2,1)
4082            parmSizer.SetFlexibleDirection(wx.HORIZONTAL)
4083            Parms = level[level['Controls']['DistType']]
4084            FFargs = level['Controls']['FFargs']
4085            SFargs = level['Controls'].get('SFargs',{})
4086            parmOrder = ['Volume','Radius','Mean','StdDev','MinSize','G','Rg','B','P','Cutoff',
4087                'PkInt','PkPos','PkSig','PkGam',]
4088            for parm in parmOrder:
4089                if parm in Parms:
4090                    if parm == 'MinSize':
4091                        parmSizer.Add(wx.StaticText(G2frame.dataDisplay,label=' Dist '+parm),0,wx.ALIGN_CENTER)
4092                    else:
4093                        parmVar = wx.CheckBox(G2frame.dataDisplay,label='Refine? Dist '+parm) 
4094                        parmVar.SetValue(Parms[parm][1])
4095                        parmVar.Bind(wx.EVT_CHECKBOX, OnSelect)
4096                        parmSizer.Add(parmVar,0,WACV)
4097                        Indx[parmVar.GetId()] = [Parms[parm],1]
4098                    parmValue = wx.TextCtrl(G2frame.dataDisplay,value='%.3g'%(Parms[parm][0]),
4099                        style=wx.TE_PROCESS_ENTER)
4100                    parmValue.Bind(wx.EVT_TEXT_ENTER,OnValue)       
4101                    parmValue.Bind(wx.EVT_KILL_FOCUS,OnValue)
4102                    parmSizer.Add(parmValue,0,WACV)
4103                    if parm == 'P':
4104                        value = Parms[parm][0]
4105                        valMinMax = [0.1,4.2]
4106                    else:
4107                        value = np.log10(Parms[parm][0])
4108                        valMinMax = [value-1,value+1]
4109                    parmSldr = wx.Slider(G2frame.dataDisplay,minValue=slMult*valMinMax[0],
4110                        maxValue=slMult*valMinMax[1],value=slMult*value)
4111                    Indx[parmValue.GetId()] = [Parms,parm,parmSldr]
4112                    Indx[parmSldr.GetId()] = [Parms,parm,parmValue]
4113                    parmSldr.Bind(wx.EVT_SLIDER,OnParmSlider)
4114                    parmSizer.Add(parmSldr,1,wx.EXPAND)
4115            if level['Controls']['DistType'] not in ['Bragg']:
4116                parmOrder = ['Aspect ratio','Length','Diameter','Thickness','VolFr','Dist','epis','Sticky','Depth','Width']
4117                fTypes = ['FF ','SF ']
4118                for iarg,Args in enumerate([FFargs,SFargs]):
4119                    for parm in parmOrder: