1 | # -*- coding: utf-8 -*- |
---|
2 | ########### SVN repository information ################### |
---|
3 | # $Date: 2021-06-15 18:27:03 +0000 (Tue, 15 Jun 2021) $ |
---|
4 | # $Author: toby $ |
---|
5 | # $Revision: 4959 $ |
---|
6 | # $URL: trunk/GSASIIfpaGUI.py $ |
---|
7 | # $Id: GSASIIfpaGUI.py 4959 2021-06-15 18:27:03Z toby $ |
---|
8 | ########### SVN repository information ################### |
---|
9 | ''' |
---|
10 | *GSASIIfpaGUI: Fundamental Parameters Routines* |
---|
11 | =============================================== |
---|
12 | |
---|
13 | This module contains routines for getting Fundamental Parameters |
---|
14 | Approach (FPA) input, setting up for running the NIST XRD Fundamental |
---|
15 | Parameters Code, plotting the convolutors and computing a set of peaks |
---|
16 | generated by that code. |
---|
17 | |
---|
18 | ''' |
---|
19 | from __future__ import division, print_function |
---|
20 | import os.path |
---|
21 | import numpy as np |
---|
22 | import copy |
---|
23 | |
---|
24 | import wx |
---|
25 | import wx.lib.scrolledpanel as wxscroll |
---|
26 | |
---|
27 | import NIST_profile as FP |
---|
28 | |
---|
29 | import GSASIIpath |
---|
30 | import GSASIIctrlGUI as G2G |
---|
31 | import GSASIIdataGUI as G2gd |
---|
32 | import GSASIIplot as G2plt |
---|
33 | import GSASIImath as G2mth |
---|
34 | import GSASIIpwd as G2pwd |
---|
35 | WACV = wx.ALIGN_CENTER_VERTICAL |
---|
36 | |
---|
37 | simParms = {} |
---|
38 | '''Parameters to set range for pattern simulation |
---|
39 | ''' |
---|
40 | |
---|
41 | parmDict = {} |
---|
42 | '''Parameter dict used for reading Topas-style values. These are |
---|
43 | converted to SI units and placed into :data:`NISTparms` |
---|
44 | ''' |
---|
45 | |
---|
46 | NISTparms = {} |
---|
47 | '''Parameters in a nested dict, with an entry for each concolutor. Entries in |
---|
48 | those dicts have values in SI units (of course). NISTparms can be |
---|
49 | can be input directly or can be from created from :data:`parmDict` |
---|
50 | by :func:`XferFPAsettings` |
---|
51 | ''' |
---|
52 | |
---|
53 | BraggBrentanoParms = [ |
---|
54 | ('divergence', 0.5, 'Bragg-Brentano divergence angle (degrees)'), |
---|
55 | ('soller_angle', 2.0, 'Soller slit axial divergence (degrees)'), |
---|
56 | ('Rs', 220, 'Diffractometer radius (mm)'), |
---|
57 | ('filament_length', 12., 'X-ray tube line focus length (mm)'), |
---|
58 | ('sample_length', 12., 'Illuminated sample length in axial direction (mm)'), |
---|
59 | ('receiving_slit_length', 12., 'Length of receiving slit in axial direction (mm)'), |
---|
60 | ('LAC_cm', 0.,'Linear absorption coef. adjusted for packing density (cm-1)'), |
---|
61 | ('sample_thickness', 1., 'Depth of sample (mm)'), |
---|
62 | ('convolution_steps', 8, 'Number of Fourier-space bins per two-theta step'), |
---|
63 | ('source_width', 0.04,'Tube filament width, in projection at takeoff angle (mm)'), |
---|
64 | ('tube-tails_L-tail', -1.,'Left-side tube tails width, in projection (mm)'), |
---|
65 | ('tube-tails_R-tail', 1.,'Right-side tube tails width, in projection (mm)'), |
---|
66 | ('tube-tails_rel-I', 0.001,'Tube tails fractional intensity (no units)'), |
---|
67 | ] |
---|
68 | '''FPA dict entries used in :func:`FillParmSizer`. Tuple contains |
---|
69 | a dict key, a default value and a description. These are the parameters |
---|
70 | needed for all Bragg Brentano instruments |
---|
71 | ''' |
---|
72 | |
---|
73 | BBPointDetector = [ |
---|
74 | ('receiving_slit_width', 0.2, 'Width of receiving slit (mm)'),] |
---|
75 | '''Additional FPA dict entries used in :func:`FillParmSizer` |
---|
76 | needed for Bragg Brentano instruments with point detectors. |
---|
77 | ''' |
---|
78 | |
---|
79 | BBPSDDetector = [ |
---|
80 | ('lpsd_th2_angular_range', 3.0, 'Angular range observed by PSD (degrees 2Theta)'), |
---|
81 | ('lpsd_equitorial_divergence', 0.1, 'Equatorial divergence of the primary beam (degrees)'),] |
---|
82 | '''Additional FPA dict entries used in :func:`FillParmSizer` |
---|
83 | needed for Bragg Brentano instruments with linear (1-D) PSD detectors. |
---|
84 | ''' |
---|
85 | |
---|
86 | IBmonoParms = [ |
---|
87 | ('src_mono_mm',119,'Distance from xray line source to monochromator crystal (mm)'), |
---|
88 | ('focus_mono_mm',217,'Distance from monochromator crystal to focus slit (mm)'), |
---|
89 | ('passband_mistune',-0.145,'Offset from the tuning of the IBM to the center of the reference line of the spectrum, in units of its bandwidth'), |
---|
90 | ('mono_src_proj_mn',51,'Projection width of line-focus xray source on the monochromator along beam direction (microns), sets bandwidth'), |
---|
91 | ('passband_shoulder',.087,'Width of transition region from flat top to tails, in units of the bandwidth'), |
---|
92 | ('two_theta_mono',27.27,'The full diffraction angle of the IBM crystal, e.g. double 2theta-Bragg for the mono (deg)'), |
---|
93 | ('mono_slit_attenuation',0.03,'Attenuation of Cu K alpha2 lines due to focal slit'), |
---|
94 | ] |
---|
95 | '''Additional FPA dict entries used in :func:`FillParmSizer`, needed for Incident Beam Monochromator |
---|
96 | ''' |
---|
97 | |
---|
98 | Citation = '''MH Mendenhall, K Mullen && JP Cline (2015), J. Res. of NIST, 120, p223. DOI: 10.6028/jres.120.014 |
---|
99 | |
---|
100 | For Incident Beam Mono model, also cite: MH Mendenhall, D. Black && JP Cline, J. Appl. Cryst. (2019), 52, p1087. DOI: 10.1107/S1600576719010951 |
---|
101 | ''' |
---|
102 | |
---|
103 | IBmono = False |
---|
104 | '''set to True if an incident beam monochromator is in use |
---|
105 | ''' |
---|
106 | DetMode = 'BBpoint' |
---|
107 | '''The type of detector, either 'BBpoint' for Bragg-Brentano point detector or |
---|
108 | or 'BBPSD' (linear) position sensitive detector |
---|
109 | ''' |
---|
110 | |
---|
111 | def SetCu2Wave(): |
---|
112 | '''Set the parameters to the two-line Cu K alpha 1+2 spectrum |
---|
113 | ''' |
---|
114 | parmDict['wave'] = {i:v for i,v in enumerate((1.5405925, 1.5443873))} |
---|
115 | parmDict['int'] = {i:v for i,v in enumerate((0.653817, 0.346183))} |
---|
116 | parmDict['lwidth'] = {i:v for i,v in enumerate((0.501844,0.626579))} |
---|
117 | |
---|
118 | def SetCu6wave(): |
---|
119 | '''Set the emission parameters to the NIST six-line Cu K alpha spectrum |
---|
120 | ''' |
---|
121 | # values from Marcus Mendenhall from atan_windowed_FP_profile.py |
---|
122 | parmDict['wave'] = {i:v for i,v in enumerate((1.5405925, 1.5443873, 1.5446782, 1.5410769, 1.53471, 1.53382, ))} |
---|
123 | parmDict['int'] = {i:v for i,v in enumerate((0.58384351, 0.2284605 , 0.11258773, 0.07077796, 0.0043303, 0.00208613, ))} |
---|
124 | parmDict['lwidth'] = {i:v for i,v in enumerate((0.436, 0.487, 0.63, 0.558, 2.93, 2.93,))} |
---|
125 | |
---|
126 | def SetMonoWave(): |
---|
127 | '''Eliminates the short-wavelength line from the six-line Cu K |
---|
128 | alpha spectrum when incident beam mono; resets it to 6 if no mono |
---|
129 | ''' |
---|
130 | if IBmono and len(parmDict['wave']) == 6: |
---|
131 | for key in 'wave','int','lwidth': |
---|
132 | if 5 in parmDict[key]: del parmDict[key][5] |
---|
133 | if 4 in parmDict[key]: del parmDict[key][4] |
---|
134 | if (not IBmono) and len(parmDict['wave']) == 4: |
---|
135 | SetCu6wave() |
---|
136 | |
---|
137 | def writeNIST(filename): |
---|
138 | '''Write the NIST FPA terms into a JSON-like file that can be reloaded |
---|
139 | in _onReadFPA |
---|
140 | ''' |
---|
141 | if not filename: return |
---|
142 | |
---|
143 | fp = open(filename,'w') |
---|
144 | fp.write('# parameters to be used in the NIST XRD Fundamental Parameters program\n') |
---|
145 | fp.write('{\n') |
---|
146 | for key in sorted(NISTparms): |
---|
147 | fp.write(" '"+key+"' : "+str(NISTparms[key])+",") |
---|
148 | if not key: fp.write(' # global parameters') |
---|
149 | fp.write('\n') |
---|
150 | fp.write('}\n') |
---|
151 | fp.close() |
---|
152 | |
---|
153 | #SetCu2Wave() # use these as default |
---|
154 | SetCu6wave() # use these as default |
---|
155 | SetMonoWave() |
---|
156 | |
---|
157 | def FillParmSizer(): |
---|
158 | '''Create a list of input items for the parameter section of the |
---|
159 | input window, sets default values when not set and displays them |
---|
160 | in the scrolledpanel prmPnl. |
---|
161 | ''' |
---|
162 | prmSizer = prmPnl.GetSizer() |
---|
163 | prmSizer.Clear(True) |
---|
164 | if IBmono: |
---|
165 | itemList = [i for i in BraggBrentanoParms if not i[0].startswith('tube-tails')] |
---|
166 | else: |
---|
167 | itemList = copy.deepcopy(BraggBrentanoParms) |
---|
168 | if DetMode == 'BBpoint': |
---|
169 | itemList += BBPointDetector |
---|
170 | elif DetMode == 'BBPSD': |
---|
171 | itemList += BBPSDDetector |
---|
172 | else: |
---|
173 | raise Exception('Unknown DetMode in FillParmSizer: '+DetMode) |
---|
174 | if IBmono: |
---|
175 | itemList += IBmonoParms |
---|
176 | text = wx.StaticText(prmPnl,wx.ID_ANY,'label',style=wx.ALIGN_CENTER, |
---|
177 | size=(170,-1)) # make just a bit bigger than largest item in column |
---|
178 | text.SetBackgroundColour(wx.WHITE) |
---|
179 | prmSizer.Add(text,0,wx.EXPAND) |
---|
180 | text = wx.StaticText(prmPnl,wx.ID_ANY,'value',style=wx.ALIGN_CENTER) |
---|
181 | text.SetBackgroundColour(wx.WHITE) |
---|
182 | prmSizer.Add(text,0,wx.EXPAND) |
---|
183 | text = wx.StaticText(prmPnl,wx.ID_ANY,'explanation',style=wx.ALIGN_CENTER) |
---|
184 | text.SetBackgroundColour(wx.WHITE) |
---|
185 | prmSizer.Add(text,0,wx.EXPAND) |
---|
186 | for lbl,defVal,text in itemList: |
---|
187 | prmSizer.Add(wx.StaticText(prmPnl,wx.ID_ANY,lbl),1,wx.ALIGN_RIGHT|WACV,1) |
---|
188 | if lbl not in parmDict: parmDict[lbl] = defVal |
---|
189 | ctrl = G2G.ValidatedTxtCtrl(prmPnl,parmDict,lbl,size=(70,-1)) |
---|
190 | prmSizer.Add(ctrl,1,wx.ALL|WACV,1) |
---|
191 | txt = wx.StaticText(prmPnl,wx.ID_ANY,text,size=(400,-1)) |
---|
192 | txt.Wrap(380) |
---|
193 | prmSizer.Add(txt) |
---|
194 | px1,py = prmSizer.GetSize() |
---|
195 | prmSizer.Layout() |
---|
196 | FPdlg = prmPnl.GetParent() |
---|
197 | FPdlg.SendSizeEvent() |
---|
198 | |
---|
199 | def MakeTopasFPASizer(G2frame,FPdlg,SetButtonStatus): |
---|
200 | '''Create a GUI with parameters for the NIST XRD Fundamental Parameters Code. |
---|
201 | Parameter input is modeled after Topas input parameters. |
---|
202 | |
---|
203 | :param wx.Frame G2frame: main GSAS-II window |
---|
204 | :param wx.Window FPdlg: Frame or Dialog where GUI will appear |
---|
205 | :param SetButtonStatus: a callback function to call to see what buttons in |
---|
206 | this windows can be enabled. Called with done=True to trigger closing |
---|
207 | the parent window as well. |
---|
208 | :returns: a sizer with the GUI controls |
---|
209 | ''' |
---|
210 | def _onOK(event): |
---|
211 | XferFPAsettings(parmDict) |
---|
212 | SetButtonStatus(done=True) # done=True triggers the simulation |
---|
213 | FPdlg.Destroy() |
---|
214 | def _onClose(event): |
---|
215 | SetButtonStatus() |
---|
216 | FPdlg.Destroy() |
---|
217 | def _onAddWave(event): |
---|
218 | newkey = max(parmDict['wave'].keys())+1 |
---|
219 | for key,defVal in zip( |
---|
220 | ('wave','int','lwidth'), |
---|
221 | (0.0, 1.0, 0.1), |
---|
222 | ): |
---|
223 | parmDict[key][newkey] = defVal |
---|
224 | wx.CallAfter(MakeTopasFPASizer,G2frame,FPdlg,SetButtonStatus) |
---|
225 | def _onRemWave(event): |
---|
226 | lastkey = max(parmDict['wave'].keys()) |
---|
227 | for key in ('wave','int','lwidth'): |
---|
228 | if lastkey in parmDict[key]: |
---|
229 | del parmDict[key][lastkey] |
---|
230 | wx.CallAfter(MakeTopasFPASizer,G2frame,FPdlg,SetButtonStatus) |
---|
231 | def _onSetCu6wave(event): |
---|
232 | SetCu6wave() |
---|
233 | SetMonoWave() |
---|
234 | wx.CallAfter(MakeTopasFPASizer,G2frame,FPdlg,SetButtonStatus) |
---|
235 | def _onSetCu2Wave(event): |
---|
236 | SetCu2Wave() |
---|
237 | wx.CallAfter(MakeTopasFPASizer,G2frame,FPdlg,SetButtonStatus) |
---|
238 | def _onSetDetBtn(event): |
---|
239 | global DetMode |
---|
240 | if detBtn1.GetValue(): |
---|
241 | DetMode = 'BBpoint' |
---|
242 | wx.CallAfter(FillParmSizer) |
---|
243 | else: |
---|
244 | DetMode = 'BBPSD' |
---|
245 | wx.CallAfter(FillParmSizer) |
---|
246 | def _onSetMonoBtn(event): |
---|
247 | global IBmono |
---|
248 | IBmono = not monoBtn1.GetValue() |
---|
249 | SetMonoWave() |
---|
250 | #wx.CallAfter(FillParmSizer) |
---|
251 | wx.CallAfter(MakeTopasFPASizer,G2frame,FPdlg,SetButtonStatus) |
---|
252 | def PlotTopasFPA(event): |
---|
253 | XferFPAsettings(parmDict) |
---|
254 | ttArr = np.arange(max(0.5, |
---|
255 | simParms['plotpos']-simParms['calcwid']), |
---|
256 | simParms['plotpos']+simParms['calcwid'], |
---|
257 | simParms['step']) |
---|
258 | intArr = np.zeros_like(ttArr) |
---|
259 | NISTpk = setupFPAcalc() |
---|
260 | try: |
---|
261 | center_bin_idx,peakObj = doFPAcalc( |
---|
262 | NISTpk,ttArr,simParms['plotpos'],simParms['calcwid'], |
---|
263 | simParms['step']) |
---|
264 | except Exception as err: |
---|
265 | msg = "Error computing convolution, revise input" |
---|
266 | print(msg) |
---|
267 | print(err) |
---|
268 | return |
---|
269 | G2plt.PlotFPAconvolutors(G2frame,NISTpk) |
---|
270 | pkPts = len(peakObj.peak) |
---|
271 | pkMax = peakObj.peak.max() |
---|
272 | startInd = center_bin_idx-(pkPts//2) #this should be the aligned start of the new data |
---|
273 | # scale peak so max I=10,000 and add into intensity array |
---|
274 | if startInd < 0: |
---|
275 | intArr[:startInd+pkPts] += 10000 * peakObj.peak[-startInd:]/pkMax |
---|
276 | elif startInd > len(intArr): |
---|
277 | return |
---|
278 | elif startInd+pkPts >= len(intArr): |
---|
279 | offset = pkPts - len( intArr[startInd:] ) |
---|
280 | intArr[startInd:startInd+pkPts-offset] += 10000 * peakObj.peak[:-offset]/pkMax |
---|
281 | else: |
---|
282 | intArr[startInd:startInd+pkPts] += 10000 * peakObj.peak/pkMax |
---|
283 | G2plt.PlotXY(G2frame, [(ttArr, intArr)], |
---|
284 | labelX=r'$2\theta, deg$', |
---|
285 | labelY=r'Intensity (arbitrary)', |
---|
286 | Title='FPA peak', newPlot=True, lines=True) |
---|
287 | def _onSaveFPA(event): |
---|
288 | XferFPAsettings(parmDict) |
---|
289 | filename = G2G.askSaveFile(G2frame,'','.NISTfpa', |
---|
290 | 'dict of NIST FPA values',FPdlg) |
---|
291 | writeNIST(filename) |
---|
292 | |
---|
293 | if FPdlg.GetSizer(): FPdlg.GetSizer().Clear(True) |
---|
294 | MainSizer = wx.BoxSizer(wx.VERTICAL) |
---|
295 | MainSizer.Add((-1,5)) |
---|
296 | waveSizer = wx.FlexGridSizer(cols=len(parmDict['wave'])+1,hgap=3,vgap=5) |
---|
297 | for lbl,prm,defVal in zip( |
---|
298 | (u'Wavelength (\u212b)','Rel. Intensity',u'Lorentz Width\n(\u212b/1000)'), |
---|
299 | ('wave','int','lwidth'), |
---|
300 | (0.0, 1.0, 0.1), |
---|
301 | ): |
---|
302 | text = wx.StaticText(FPdlg,wx.ID_ANY,lbl,style=wx.ALIGN_CENTER) |
---|
303 | text.SetBackgroundColour(wx.WHITE) |
---|
304 | waveSizer.Add(text,0,wx.EXPAND) |
---|
305 | if prm not in parmDict: parmDict[prm] = {} |
---|
306 | for i in parmDict['wave'].keys(): |
---|
307 | if i not in parmDict[prm]: parmDict[prm][i] = defVal |
---|
308 | if prm == 'wave': |
---|
309 | ctrl = G2G.ValidatedTxtCtrl(FPdlg,parmDict[prm],i,size=(90,-1),nDig=(10,6)) |
---|
310 | else: |
---|
311 | ctrl = G2G.ValidatedTxtCtrl(FPdlg,parmDict[prm],i,size=(90,-1),nDig=(10,3)) |
---|
312 | waveSizer.Add(ctrl,1,WACV,1) |
---|
313 | MainSizer.Add(waveSizer) |
---|
314 | MainSizer.Add((-1,5)) |
---|
315 | btnsizer = wx.BoxSizer(wx.HORIZONTAL) |
---|
316 | btn = wx.Button(FPdlg, wx.ID_ANY,'Add wave') |
---|
317 | btnsizer.Add(btn) |
---|
318 | btn.Bind(wx.EVT_BUTTON,_onAddWave) |
---|
319 | btn = wx.Button(FPdlg, wx.ID_ANY,'Remove wave') |
---|
320 | btnsizer.Add(btn) |
---|
321 | btn.Bind(wx.EVT_BUTTON,_onRemWave) |
---|
322 | btn = wx.Button(FPdlg, wx.ID_ANY,'CuKa1+2') |
---|
323 | btnsizer.Add(btn) |
---|
324 | btn.Bind(wx.EVT_BUTTON,_onSetCu2Wave) |
---|
325 | btn = wx.Button(FPdlg, wx.ID_ANY,'NIST CuKa') |
---|
326 | btnsizer.Add(btn) |
---|
327 | btn.Bind(wx.EVT_BUTTON,_onSetCu6wave) |
---|
328 | MainSizer.Add(btnsizer, 0, wx.ALIGN_CENTER, 0) |
---|
329 | MainSizer.Add((-1,5)) |
---|
330 | |
---|
331 | btnsizer = wx.GridBagSizer( 2, 5) |
---|
332 | btnsizer.Add( wx.StaticText(FPdlg, wx.ID_ANY, 'Detector type'), |
---|
333 | (0,0), (2,1), wx.ALIGN_CENTER | wx.ALL, 5) |
---|
334 | detBtn1 = wx.RadioButton(FPdlg,wx.ID_ANY,'Point',style=wx.RB_GROUP) |
---|
335 | detBtn1.SetValue(DetMode == 'BBpoint') |
---|
336 | btnsizer.Add(detBtn1, (0,1)) |
---|
337 | detBtn1.Bind(wx.EVT_RADIOBUTTON,_onSetDetBtn) |
---|
338 | detBtn2 = wx.RadioButton(FPdlg,wx.ID_ANY,'PSD') |
---|
339 | detBtn2.SetValue(not DetMode == 'BBpoint') |
---|
340 | btnsizer.Add(detBtn2, (1,1)) |
---|
341 | detBtn2.Bind(wx.EVT_RADIOBUTTON,_onSetDetBtn) |
---|
342 | btnsizer.Add( (40,-1), (0,2), (1,1), wx.ALIGN_CENTER | wx.ALL, 5) |
---|
343 | btnsizer.Add( wx.StaticText(FPdlg, wx.ID_ANY, 'Incident Beam Mono'), |
---|
344 | (0,3), (2,1), wx.ALIGN_CENTER | wx.ALL, 5) |
---|
345 | monoBtn1 = wx.RadioButton(FPdlg,wx.ID_ANY,'No',style=wx.RB_GROUP) |
---|
346 | monoBtn1.SetValue(not IBmono) |
---|
347 | btnsizer.Add(monoBtn1, (0,4)) |
---|
348 | monoBtn1.Bind(wx.EVT_RADIOBUTTON,_onSetMonoBtn) |
---|
349 | monoBtn2 = wx.RadioButton(FPdlg,wx.ID_ANY,'Yes') |
---|
350 | monoBtn2.SetValue(IBmono) |
---|
351 | btnsizer.Add(monoBtn2, (1,4)) |
---|
352 | monoBtn2.Bind(wx.EVT_RADIOBUTTON,_onSetMonoBtn) |
---|
353 | MainSizer.Add(btnsizer, 0, wx.ALIGN_CENTER, 0) |
---|
354 | |
---|
355 | global prmPnl |
---|
356 | prmPnl = wxscroll.ScrolledPanel(FPdlg, wx.ID_ANY, #size=(200,200), |
---|
357 | style = wx.TAB_TRAVERSAL|wx.SUNKEN_BORDER) |
---|
358 | prmSizer = wx.FlexGridSizer(cols=3,hgap=3,vgap=5) |
---|
359 | prmPnl.SetSizer(prmSizer) |
---|
360 | FillParmSizer() |
---|
361 | MainSizer.Add(prmPnl,1,wx.EXPAND,1) |
---|
362 | prmPnl.SetAutoLayout(1) |
---|
363 | prmPnl.SetupScrolling() |
---|
364 | |
---|
365 | MainSizer.Add((-1,4)) |
---|
366 | btnsizer = wx.BoxSizer(wx.HORIZONTAL) |
---|
367 | btn = wx.Button(FPdlg, wx.ID_ANY, 'Plot peak') |
---|
368 | btnsizer.Add(btn) |
---|
369 | btn.Bind(wx.EVT_BUTTON,PlotTopasFPA) |
---|
370 | btnsizer.Add(wx.StaticText(FPdlg,wx.ID_ANY,' at ')) |
---|
371 | if 'plotpos' not in simParms: simParms['plotpos'] = simParms['minTT'] |
---|
372 | ctrl = G2G.ValidatedTxtCtrl(FPdlg,simParms,'plotpos',size=(70,-1)) |
---|
373 | btnsizer.Add(ctrl) |
---|
374 | btnsizer.Add(wx.StaticText(FPdlg,wx.ID_ANY,' deg. ')) |
---|
375 | saveBtn = wx.Button(FPdlg, wx.ID_ANY,'Save FPA dict') |
---|
376 | btnsizer.Add(saveBtn) |
---|
377 | saveBtn.Bind(wx.EVT_BUTTON,_onSaveFPA) |
---|
378 | MainSizer.Add(btnsizer, 0, wx.ALIGN_CENTER, 0) |
---|
379 | MainSizer.Add((-1,4)) |
---|
380 | btnsizer = wx.BoxSizer(wx.HORIZONTAL) |
---|
381 | OKbtn = wx.Button(FPdlg, wx.ID_OK) |
---|
382 | OKbtn.SetDefault() |
---|
383 | btnsizer.Add(OKbtn) |
---|
384 | Cbtn = wx.Button(FPdlg, wx.ID_CLOSE,"Cancel") |
---|
385 | btnsizer.Add(Cbtn) |
---|
386 | MainSizer.Add(btnsizer, 0, wx.ALIGN_CENTER, 0) |
---|
387 | MainSizer.Add((-1,4)) |
---|
388 | # bindings for close of window |
---|
389 | OKbtn.Bind(wx.EVT_BUTTON,_onOK) |
---|
390 | Cbtn.Bind(wx.EVT_BUTTON,_onClose) |
---|
391 | FPdlg.SetSizer(MainSizer) |
---|
392 | MainSizer.Layout() |
---|
393 | MainSizer.Fit(FPdlg) |
---|
394 | # control window size |
---|
395 | px,py = prmSizer.GetSize() |
---|
396 | dx,dy = FPdlg.GetSize() |
---|
397 | FPdlg.SetMinSize((-1,-1)) |
---|
398 | FPdlg.SetMaxSize((-1,-1)) |
---|
399 | FPdlg.SetMinSize((dx,dy+200)) # leave a min of 200 points for scroll panel |
---|
400 | FPdlg.SetMaxSize((max(dx,700),850)) |
---|
401 | FPdlg.SetSize((max(dx,px+20),min(750,dy+py+30))) # 20 for scroll bar, 30 for a bit of room at bottom |
---|
402 | |
---|
403 | def XferFPAsettings(InpParms): |
---|
404 | '''convert Topas-type parameters to SI units for NIST and place in a dict sorted |
---|
405 | according to use in each convoluter |
---|
406 | |
---|
407 | :param dict InpParms: a dict with Topas-like parameters, as set in |
---|
408 | :func:`MakeTopasFPASizer` |
---|
409 | :returns: a nested dict with global parameters and those for each convolution |
---|
410 | ''' |
---|
411 | # cleanup old stuff |
---|
412 | for key in "tube_tails","absorption","si_psd","displacement","receiver_slit": |
---|
413 | if key in NISTparms: |
---|
414 | del NISTparms[key] |
---|
415 | |
---|
416 | keys = list(InpParms['wave'].keys()) |
---|
417 | source_wavelengths_m = 1.e-10 * np.array([InpParms['wave'][i] for i in keys]) |
---|
418 | la = [InpParms['int'][i] for i in keys] |
---|
419 | |
---|
420 | if IBmono: # kludge: apply mono_slit_attenuation since it is not part of NIST FPA code |
---|
421 | norm = [InpParms['mono_slit_attenuation'] if |
---|
422 | (1.5443 < InpParms['wave'][i] < 1.5447) else 1. |
---|
423 | for i in keys] |
---|
424 | source_intensities = norm * np.array(la)/max(la) |
---|
425 | else: |
---|
426 | source_intensities = np.array(la)/max(la) |
---|
427 | source_lor_widths_m = 1.e-10 * 1.e-3 * np.array([InpParms['lwidth'][i] for i in keys]) |
---|
428 | source_gauss_widths_m = 1.e-10 * 1.e-3 * np.array([0.001 for i in keys]) |
---|
429 | |
---|
430 | NISTparms["emission"] = {'emiss_wavelengths' : source_wavelengths_m, |
---|
431 | 'emiss_intensities' : source_intensities, |
---|
432 | 'emiss_gauss_widths' : source_gauss_widths_m, |
---|
433 | 'emiss_lor_widths' : source_lor_widths_m, |
---|
434 | 'crystallite_size_gauss' : 1.e-9 * InpParms.get('Size_G',1e6), |
---|
435 | 'crystallite_size_lor' : 1.e-9 * InpParms.get('Size_L',1e6)} |
---|
436 | if IBmono: |
---|
437 | NISTparms["emission"]['a_mono'] = InpParms['src_mono_mm'] * 10**-3 |
---|
438 | NISTparms["emission"]['b_mono'] = InpParms['focus_mono_mm'] * 10**-3 |
---|
439 | NISTparms["emission"]['ibm_source_width'] = InpParms['mono_src_proj_mn'] * 10**-6 |
---|
440 | for i in ('passband_mistune','passband_shoulder','two_theta_mono'): |
---|
441 | NISTparms["emission"][i] = InpParms[i] |
---|
442 | elif InpParms.get('source_width', 0) > 0 and InpParms.get( |
---|
443 | 'tube-tails_rel-I',0) > 0: |
---|
444 | NISTparms["tube_tails"] = { |
---|
445 | 'main_width' : 1e-3 * InpParms.get('source_width', 0.), |
---|
446 | 'tail_left' : -1e-3 * InpParms.get('tube-tails_L-tail',0.), |
---|
447 | 'tail_right' : 1e-3 * InpParms.get('tube-tails_R-tail',0.), |
---|
448 | 'tail_intens' : InpParms.get('tube-tails_rel-I',0.),} |
---|
449 | |
---|
450 | if InpParms['filament_length'] == InpParms['receiving_slit_length']: # workaround: |
---|
451 | InpParms['receiving_slit_length'] *= 1.00001 # avoid bug when slit lengths are identical |
---|
452 | NISTparms["axial"] = { |
---|
453 | 'axDiv':"full", 'slit_length_source' : 1e-3*InpParms['filament_length'], |
---|
454 | 'slit_length_target' : 1e-3*InpParms['receiving_slit_length'], |
---|
455 | 'length_sample' : 1e-3 * InpParms['sample_length'], |
---|
456 | 'n_integral_points' : 10, |
---|
457 | 'angI_deg' : InpParms['soller_angle'], |
---|
458 | 'angD_deg': InpParms['soller_angle'] |
---|
459 | } |
---|
460 | if InpParms.get('LAC_cm',0) > 0: |
---|
461 | NISTparms["absorption"] = { |
---|
462 | 'absorption_coefficient': InpParms['LAC_cm']*100, #like LaB6, in m^(-1) |
---|
463 | 'sample_thickness': 1e-3 * InpParms['sample_thickness'], |
---|
464 | } |
---|
465 | |
---|
466 | if InpParms.get('lpsd_equitorial_divergence',0) > 0 and InpParms.get( |
---|
467 | 'lpsd_th2_angular_range',0) > 0 and DetMode == 'BBPSD': |
---|
468 | PSDdetector_length_mm=np.arcsin(np.pi*InpParms['lpsd_th2_angular_range']/180. |
---|
469 | )*InpParms['Rs'] # mm |
---|
470 | NISTparms["si_psd"] = { |
---|
471 | 'equatorial_divergence_deg': InpParms['lpsd_equitorial_divergence'], |
---|
472 | 'si_psd_window_bounds': (0.,PSDdetector_length_mm/1000.) |
---|
473 | } |
---|
474 | |
---|
475 | if InpParms.get('Specimen_Displacement'): |
---|
476 | NISTparms["displacement"] = {'specimen_displacement': 1e-3 * InpParms['Specimen_Displacement']} |
---|
477 | |
---|
478 | if InpParms.get('receiving_slit_width'): |
---|
479 | NISTparms["receiver_slit"] = {'slit_width':1e-3*InpParms['receiving_slit_width']} |
---|
480 | |
---|
481 | # set Global parameters |
---|
482 | max_wavelength = source_wavelengths_m[np.argmax(source_intensities)] |
---|
483 | NISTparms[""] = { |
---|
484 | 'equatorial_divergence_deg' : InpParms['divergence'], |
---|
485 | 'dominant_wavelength' : max_wavelength, |
---|
486 | 'diffractometer_radius' : 1e-3* InpParms['Rs'], |
---|
487 | 'oversampling' : InpParms['convolution_steps'], |
---|
488 | } |
---|
489 | |
---|
490 | def setupFPAcalc(): |
---|
491 | '''Create a peak profile object using the NIST XRD Fundamental |
---|
492 | Parameters Code. |
---|
493 | |
---|
494 | :returns: a profile object that can provide information on |
---|
495 | each convolution or compute the composite peak shape. |
---|
496 | ''' |
---|
497 | if IBmono: |
---|
498 | p=FP.FP_windowed(anglemode="twotheta", |
---|
499 | output_gaussian_smoother_bins_sigma=1.0, |
---|
500 | oversampling=NISTparms.get('oversampling',10)) |
---|
501 | else: |
---|
502 | p=FP.FP_profile(anglemode="twotheta", |
---|
503 | output_gaussian_smoother_bins_sigma=1.0, |
---|
504 | oversampling=NISTparms.get('oversampling',10)) |
---|
505 | |
---|
506 | p.debug_cache=False |
---|
507 | #set parameters for each convolver |
---|
508 | for key in NISTparms: |
---|
509 | if key: |
---|
510 | p.set_parameters(convolver=key,**NISTparms[key]) |
---|
511 | else: |
---|
512 | p.set_parameters(**NISTparms[key]) |
---|
513 | return p |
---|
514 | |
---|
515 | def doFPAcalc(NISTpk,ttArr,twotheta,calcwid,step): |
---|
516 | '''Compute a single peak using a NIST profile object |
---|
517 | |
---|
518 | :param object NISTpk: a peak profile computational object from the |
---|
519 | NIST XRD Fundamental Parameters Code, typically established from |
---|
520 | a call to :func:`SetupFPAcalc` |
---|
521 | :param np.Array ttArr: an evenly-spaced grid of two-theta points (degrees) |
---|
522 | :param float twotheta: nominal center of peak (degrees) |
---|
523 | :param float calcwid: width to perform convolution (degrees) |
---|
524 | :param float step: step size |
---|
525 | ''' |
---|
526 | # find closest point to twotheta (may be outside limits of the array) |
---|
527 | center_bin_idx=min(ttArr.searchsorted(twotheta),len(ttArr)-1) |
---|
528 | NISTpk.set_optimized_window(twotheta_exact_bin_spacing_deg=step, |
---|
529 | twotheta_window_center_deg=ttArr[center_bin_idx], |
---|
530 | twotheta_approx_window_fullwidth_deg=calcwid, |
---|
531 | ) |
---|
532 | NISTpk.set_parameters(twotheta0_deg=twotheta) |
---|
533 | return center_bin_idx,NISTpk.compute_line_profile() |
---|
534 | |
---|
535 | def MakeSimSizer(G2frame, dlg): |
---|
536 | '''Create a GUI to get simulation with parameters for Fundamental |
---|
537 | Parameters fitting. |
---|
538 | |
---|
539 | :param wx.Window dlg: Frame or Dialog where GUI will appear |
---|
540 | |
---|
541 | :returns: a sizer with the GUI controls |
---|
542 | |
---|
543 | ''' |
---|
544 | def _onOK(event): |
---|
545 | msg = '' |
---|
546 | if simParms['minTT']-simParms['calcwid']/1.5 < 0.1: |
---|
547 | msg += 'First peak minus half the calc width is too low' |
---|
548 | if simParms['maxTT']+simParms['calcwid']/1.5 > 175: |
---|
549 | if msg: msg += '\n' |
---|
550 | msg += 'Last peak plus half the calc width is too high' |
---|
551 | if simParms['npeaks'] < 8: |
---|
552 | if msg: msg += '\n' |
---|
553 | msg += 'At least 8 peaks are needed' |
---|
554 | if msg: |
---|
555 | G2G.G2MessageBox(dlg,msg,'Bad input, try again') |
---|
556 | return |
---|
557 | # compute "obs" pattern |
---|
558 | ttArr = np.arange(max(0.5, |
---|
559 | simParms['minTT']-simParms['calcwid']/1.5), |
---|
560 | simParms['maxTT']+simParms['calcwid']/1.5, |
---|
561 | simParms['step']) |
---|
562 | intArr = np.zeros_like(ttArr) |
---|
563 | peaklist = np.linspace(simParms['minTT'],simParms['maxTT'], |
---|
564 | simParms['npeaks'],endpoint=True) |
---|
565 | peakSpacing = (peaklist[-1]-peaklist[0])/(len(peaklist)-1) |
---|
566 | NISTpk = setupFPAcalc() |
---|
567 | minPtsHM = len(intArr) # initialize points above half-max |
---|
568 | maxPtsHM = 0 |
---|
569 | for num,twoth_peak in enumerate(peaklist): |
---|
570 | try: |
---|
571 | center_bin_idx,peakObj = doFPAcalc( |
---|
572 | NISTpk,ttArr,twoth_peak,simParms['calcwid'], |
---|
573 | simParms['step']) |
---|
574 | except Exception as err: |
---|
575 | if msg: msg += '\n' |
---|
576 | msg = "Error computing convolution, revise input. Error =\n"+str(err) |
---|
577 | continue |
---|
578 | if num == 0: G2plt.PlotFPAconvolutors(G2frame,NISTpk) |
---|
579 | pkMax = peakObj.peak.max() |
---|
580 | pkPts = len(peakObj.peak) |
---|
581 | minPtsHM = min(minPtsHM,sum(peakObj.peak >= 0.5*pkMax)) # points above half-max |
---|
582 | maxPtsHM = max(maxPtsHM,sum(peakObj.peak >= 0.5*pkMax)) # points above half-max |
---|
583 | startInd = center_bin_idx-(pkPts//2) #this should be the aligned start of the new data |
---|
584 | # scale peak so max I=10,000 and add into intensity array |
---|
585 | if startInd < 0: |
---|
586 | intArr[:startInd+pkPts] += 10000 * peakObj.peak[-startInd:]/pkMax |
---|
587 | elif startInd > len(intArr): |
---|
588 | break |
---|
589 | elif startInd+pkPts >= len(intArr): |
---|
590 | offset = pkPts - len( intArr[startInd:] ) |
---|
591 | intArr[startInd:startInd+pkPts-offset] += 10000 * peakObj.peak[:-offset]/pkMax |
---|
592 | else: |
---|
593 | intArr[startInd:startInd+pkPts] += 10000 * peakObj.peak/pkMax |
---|
594 | # check if peaks are too closely spaced |
---|
595 | if maxPtsHM*simParms['step'] > peakSpacing/4: |
---|
596 | if msg: msg += '\n' |
---|
597 | msg += 'Maximum FWHM ({}) is too large compared to the peak spacing ({}). Decrease number of peaks or increase data range.'.format( |
---|
598 | maxPtsHM*simParms['step'], peakSpacing) |
---|
599 | # check if too few points across Hmax |
---|
600 | if minPtsHM < 10: |
---|
601 | if msg: msg += '\n' |
---|
602 | msg += 'There are only {} points above the half-max. 10 are needed. Dropping step size.'.format(minPtsHM) |
---|
603 | simParms['step'] *= 0.5 |
---|
604 | if msg: |
---|
605 | G2G.G2MessageBox(dlg,msg,'Bad input, try again') |
---|
606 | wx.CallAfter(MakeSimSizer,G2frame, dlg) |
---|
607 | return |
---|
608 | # pattern has been computed successfully |
---|
609 | dlg.Destroy() |
---|
610 | wx.CallAfter(FitFPApeaks,ttArr, intArr, peaklist, maxPtsHM) # do peakfit outside event callback |
---|
611 | |
---|
612 | def FitFPApeaks(ttArr, intArr, peaklist, maxPtsHM): |
---|
613 | '''Perform a peak fit to the FP simulated pattern |
---|
614 | ''' |
---|
615 | pgbar = wx.ProgressDialog('FPA Simulation','Starting FPA simulation',100, |
---|
616 | parent=G2frame, |
---|
617 | style = wx.PD_ELAPSED_TIME|wx.PD_AUTO_HIDE #|wx.PD_CAN_ABORT |
---|
618 | ) |
---|
619 | pgbar.Raise() |
---|
620 | wx.BeginBusyCursor() |
---|
621 | # pick out one or two most intense wavelengths |
---|
622 | ints = list(NISTparms['emission']['emiss_intensities']) |
---|
623 | Lam1 = NISTparms['emission']['emiss_wavelengths'][np.argmax(ints)]*1e10 |
---|
624 | if 'two_theta_mono' in NISTparms['emission']: # is there an IBM? |
---|
625 | Lam2 = None # Yes, ~monochromatic |
---|
626 | else: # get lambda 2 |
---|
627 | ints[np.argmax(ints)] = -1 |
---|
628 | Lam2 = NISTparms['emission']['emiss_wavelengths'][np.argmax(ints)]*1e10 |
---|
629 | histId = G2frame.AddSimulatedPowder(ttArr,intArr, |
---|
630 | 'NIST Fundamental Parameters simulation', |
---|
631 | Lam1,Lam2) |
---|
632 | controls = G2frame.GPXtree.GetItemPyData( |
---|
633 | G2gd.GetGPXtreeItemId(G2frame,G2frame.root,'Controls')) |
---|
634 | controldat = controls.get('data', |
---|
635 | {'deriv type':'analytic','min dM/M':0.001,}) #fil |
---|
636 | Parms,Parms2 = G2frame.GPXtree.GetItemPyData( |
---|
637 | G2gd.GetGPXtreeItemId(G2frame,histId,'Instrument Parameters')) |
---|
638 | peakData = G2frame.GPXtree.GetItemPyData( |
---|
639 | G2gd.GetGPXtreeItemId(G2frame,histId,'Peak List')) |
---|
640 | # set background to 0 with one term = 0; disable refinement |
---|
641 | bkg1,bkg2 = bkg = G2frame.GPXtree.GetItemPyData( |
---|
642 | G2gd.GetGPXtreeItemId(G2frame,histId,'Background')) |
---|
643 | bkg1[1]=False |
---|
644 | bkg1[2]=0 |
---|
645 | bkg1[3]=0.0 |
---|
646 | limits = G2frame.GPXtree.GetItemPyData( |
---|
647 | G2gd.GetGPXtreeItemId(G2frame,histId,'Limits')) |
---|
648 | # approximate asym correction |
---|
649 | try: |
---|
650 | Parms['SH/L'][1] = 0.25 * ( |
---|
651 | NISTparms['axial']['length_sample']+ |
---|
652 | NISTparms['axial']['slit_length_source'] |
---|
653 | ) / NISTparms['']['diffractometer_radius'] |
---|
654 | except: |
---|
655 | pass |
---|
656 | pgbar.Update(5,newmsg='Creating peak list') |
---|
657 | pgbar.Raise() |
---|
658 | for pos in peaklist: |
---|
659 | i = ttArr.searchsorted(pos) |
---|
660 | area = sum(intArr[max(0,i-maxPtsHM):min(len(intArr),i+maxPtsHM)]) |
---|
661 | peakData['peaks'].append(G2mth.setPeakparms(Parms,Parms2,pos,area)) |
---|
662 | pgbar.Update(10,newmsg='Refining peak positions') |
---|
663 | histData = G2frame.GPXtree.GetItemPyData(histId) |
---|
664 | # refine peak positions only |
---|
665 | bxye = np.zeros(len(histData[1][1])) |
---|
666 | peakData['sigDict'] = G2pwd.DoPeakFit('LSQ',peakData['peaks'], |
---|
667 | bkg,limits[1],Parms,Parms2,histData[1],bxye,[],False,controldat)[0] |
---|
668 | pgbar.Update(20,newmsg='Refining peak positions && areas') |
---|
669 | # refine peak areas as well |
---|
670 | for pk in peakData['peaks']: |
---|
671 | pk[1] = True |
---|
672 | peakData['sigDict'] = G2pwd.DoPeakFit('LSQ',peakData['peaks'], |
---|
673 | bkg,limits[1],Parms,Parms2,histData[1],bxye,[],False,controldat)[0] |
---|
674 | pgbar.Update(40,newmsg='Refining profile function') |
---|
675 | # refine profile function |
---|
676 | for p in ('U', 'V', 'W', 'X', 'Y'): |
---|
677 | Parms[p][2] = True |
---|
678 | peakData['sigDict'] = G2pwd.DoPeakFit('LSQ',peakData['peaks'], |
---|
679 | bkg,limits[1],Parms,Parms2,histData[1],bxye,[],False,controldat)[0] |
---|
680 | pgbar.Update(70,newmsg='Refining profile function && asymmetry') |
---|
681 | # add in asymmetry |
---|
682 | Parms['SH/L'][2] = True |
---|
683 | peakData['sigDict'] = G2pwd.DoPeakFit('LSQ',peakData['peaks'], |
---|
684 | bkg,limits[1],Parms,Parms2,histData[1],bxye,[],False,controldat)[0] |
---|
685 | pgbar.Update(100,newmsg='Done') |
---|
686 | # reset "initial" profile |
---|
687 | for p in Parms: |
---|
688 | if len(Parms[p]) == 3: |
---|
689 | Parms[p][0] = Parms[p][1] |
---|
690 | Parms[p][2] = False |
---|
691 | pgbar.Destroy() |
---|
692 | wx.EndBusyCursor() |
---|
693 | # save Iparms |
---|
694 | pth = G2G.GetExportPath(G2frame) |
---|
695 | fldlg = wx.FileDialog(G2frame, 'Set name to save GSAS-II instrument parameters file', pth, '', |
---|
696 | 'instrument parameter files (*.instprm)|*.instprm',wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT) |
---|
697 | try: |
---|
698 | if fldlg.ShowModal() == wx.ID_OK: |
---|
699 | filename = fldlg.GetPath() |
---|
700 | # make sure extension is .instprm |
---|
701 | filename = os.path.splitext(filename)[0]+'.instprm' |
---|
702 | File = open(filename,'w') |
---|
703 | File.write("#GSAS-II instrument parameter file; do not add/delete items!\n") |
---|
704 | for item in Parms: |
---|
705 | File.write(item+':'+str(Parms[item][1])+'\n') |
---|
706 | File.close() |
---|
707 | print ('Instrument parameters saved to: '+filename) |
---|
708 | finally: |
---|
709 | fldlg.Destroy() |
---|
710 | #GSASIIpath.IPyBreak() |
---|
711 | |
---|
712 | def _onClose(event): |
---|
713 | dlg.Destroy() |
---|
714 | def SetButtonStatus(done=False): |
---|
715 | OKbtn.Enable(bool(NISTparms)) |
---|
716 | #saveBtn.Enable(bool(NISTparms)) |
---|
717 | if done: _onOK(None) |
---|
718 | def _onSetFPA(event): |
---|
719 | # Create a non-modal dialog for Topas-style FP input. |
---|
720 | FPdlg = wx.Dialog(dlg,wx.ID_ANY,'FPA parameters', |
---|
721 | style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER) |
---|
722 | MakeTopasFPASizer(G2frame,FPdlg,SetButtonStatus) |
---|
723 | FPdlg.CenterOnParent() |
---|
724 | FPdlg.Raise() |
---|
725 | FPdlg.Show() |
---|
726 | def _onSaveFPA(event): |
---|
727 | filename = G2G.askSaveFile(G2frame,'','.NISTfpa', |
---|
728 | 'dict of NIST FPA values',dlg) |
---|
729 | writeNIST(filename) |
---|
730 | |
---|
731 | def _onReadFPA(event): |
---|
732 | filename = G2G.GetImportFile(G2frame, |
---|
733 | message='Read file with dict of values for NIST Fundamental Parameters', |
---|
734 | parent=dlg, |
---|
735 | wildcard='dict of NIST FPA values|*.NISTfpa') |
---|
736 | if not filename: return |
---|
737 | if not filename[0]: return |
---|
738 | try: |
---|
739 | txt = open(filename[0],'r').read() |
---|
740 | NISTparms.clear() |
---|
741 | d = eval(txt) |
---|
742 | NISTparms.update(d) |
---|
743 | except Exception as err: |
---|
744 | G2G.G2MessageBox(dlg, |
---|
745 | u'Error reading file {}:{}\n'.format(filename,err), |
---|
746 | 'Bad dict input') |
---|
747 | #GSASIIpath.IPyBreak() |
---|
748 | SetButtonStatus() |
---|
749 | |
---|
750 | if dlg.GetSizer(): dlg.GetSizer().Clear(True) |
---|
751 | MainSizer = wx.BoxSizer(wx.VERTICAL) |
---|
752 | MainSizer.Add(wx.StaticText(dlg,wx.ID_ANY, |
---|
753 | 'Fit Profile Parameters to Peaks from Fundamental Parameters', |
---|
754 | style=wx.ALIGN_CENTER),0,wx.EXPAND) |
---|
755 | MainSizer.Add((-1,5)) |
---|
756 | prmSizer = wx.FlexGridSizer(cols=2,hgap=3,vgap=5) |
---|
757 | text = wx.StaticText(dlg,wx.ID_ANY,'value',style=wx.ALIGN_CENTER) |
---|
758 | text.SetBackgroundColour(wx.WHITE) |
---|
759 | prmSizer.Add(text,0,wx.EXPAND) |
---|
760 | text = wx.StaticText(dlg,wx.ID_ANY,'explanation',style=wx.ALIGN_CENTER) |
---|
761 | text.SetBackgroundColour(wx.WHITE) |
---|
762 | prmSizer.Add(text,0,wx.EXPAND) |
---|
763 | for key,defVal,text in ( |
---|
764 | ('minTT',3.,'Location of first peak in 2theta (deg)'), |
---|
765 | ('maxTT',123.,'Location of last peak in 2theta (deg)'), |
---|
766 | ('step',0.01,'Pattern step size (deg 2theta)'), |
---|
767 | ('npeaks',13,'Number of peaks'), |
---|
768 | ('calcwid',2.,'Range to compute each peak (deg 2theta)'), |
---|
769 | ): |
---|
770 | if key not in simParms: simParms[key] = defVal |
---|
771 | ctrl = G2G.ValidatedTxtCtrl(dlg,simParms,key,size=(70,-1)) |
---|
772 | prmSizer.Add(ctrl,1,wx.ALL|WACV,1) |
---|
773 | txt = wx.StaticText(dlg,wx.ID_ANY,text,size=(300,-1)) |
---|
774 | txt.Wrap(280) |
---|
775 | prmSizer.Add(txt) |
---|
776 | MainSizer.Add(prmSizer) |
---|
777 | |
---|
778 | btnsizer = wx.BoxSizer(wx.HORIZONTAL) |
---|
779 | btn = wx.Button(dlg, wx.ID_ANY,'Input FP vals') |
---|
780 | btnsizer.Add(btn) |
---|
781 | btn.Bind(wx.EVT_BUTTON,_onSetFPA) |
---|
782 | #saveBtn = wx.Button(dlg, wx.ID_ANY,'Save FPA dict') |
---|
783 | #btnsizer.Add(saveBtn) |
---|
784 | #saveBtn.Bind(wx.EVT_BUTTON,_onSaveFPA) |
---|
785 | readBtn = wx.Button(dlg, wx.ID_ANY,'Read FPA dict') |
---|
786 | btnsizer.Add(readBtn) |
---|
787 | readBtn.Bind(wx.EVT_BUTTON,_onReadFPA) |
---|
788 | MainSizer.Add(btnsizer, 0, wx.ALIGN_CENTER, 0) |
---|
789 | MainSizer.Add((-1,4),1,wx.EXPAND,1) |
---|
790 | txt = wx.StaticText(dlg,wx.ID_ANY,'If you use this, please cite: '+Citation,size=(350,-1)) |
---|
791 | txt.Wrap(340) |
---|
792 | MainSizer.Add(txt,0,wx.ALIGN_CENTER) |
---|
793 | btnsizer = wx.BoxSizer(wx.HORIZONTAL) |
---|
794 | OKbtn = wx.Button(dlg, wx.ID_OK) |
---|
795 | OKbtn.SetDefault() |
---|
796 | btnsizer.Add(OKbtn) |
---|
797 | Cbtn = wx.Button(dlg, wx.ID_CLOSE,"Cancel") |
---|
798 | btnsizer.Add(Cbtn) |
---|
799 | MainSizer.Add(btnsizer, 0, wx.ALIGN_CENTER, 0) |
---|
800 | MainSizer.Add((-1,4),1,wx.EXPAND,1) |
---|
801 | # bindings for close of window |
---|
802 | OKbtn.Bind(wx.EVT_BUTTON,_onOK) |
---|
803 | Cbtn.Bind(wx.EVT_BUTTON,_onClose) |
---|
804 | SetButtonStatus() |
---|
805 | dlg.SetSizer(MainSizer) |
---|
806 | MainSizer.Layout() |
---|
807 | MainSizer.Fit(dlg) |
---|
808 | dlg.SetMinSize(dlg.GetSize()) |
---|
809 | dlg.SendSizeEvent() |
---|
810 | dlg.Raise() |
---|
811 | |
---|
812 | def GetFPAInput(G2frame): |
---|
813 | dlg = wx.Dialog(G2frame,wx.ID_ANY,'FPA input', |
---|
814 | style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER) |
---|
815 | MakeSimSizer(G2frame,dlg) |
---|
816 | dlg.CenterOnParent() |
---|
817 | dlg.Show() |
---|
818 | return |
---|
819 | |
---|
820 | if __name__ == "__main__": |
---|
821 | app = wx.PySimpleApp() |
---|
822 | GSASIIpath.InvokeDebugOpts() |
---|
823 | frm = wx.Frame(None) # create a frame |
---|
824 | frm.Show(True) |
---|
825 | frm.TutorialImportDir = '/tmp' |
---|
826 | |
---|
827 | GetFPAInput(frm) |
---|
828 | |
---|
829 | app.MainLoop() |
---|