source: trunk/GSASIIpwdGUI.py @ 2506

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

some work on automatic mag constraints
move a dlg.Destroy() in OnSeqPeakFit? & OnIndexPeaks? - get rid of orphan wait cursor & progress dialog
more work on mag moment derivs - still wrong! Other derivs now all OK

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