source: trunk/GSASIIpwdGUI.py @ 2336

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

two fixes for PDF plots

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