Coverage for /Users/Newville/Codes/xraylarch/larch/wxlib/xrfdisplay_fitpeaks.py: 9%

1080 statements  

« prev     ^ index     » next       coverage.py v7.3.2, created at 2023-11-09 10:08 -0600

1#!/usr/bin/env python 

2""" 

3fitting GUI for XRF display 

4""" 

5import os 

6import sys 

7import time 

8import copy 

9from functools import partial 

10from threading import Thread 

11 

12import json 

13import numpy as np 

14import wx 

15import wx.lib.agw.pycollapsiblepane as CP 

16import wx.lib.scrolledpanel as scrolled 

17import wx.dataview as dv 

18DVSTYLE = dv.DV_SINGLE|dv.DV_VERT_RULES|dv.DV_ROW_LINES 

19 

20from peakutils import peak 

21 

22from lmfit import Parameter, Minimizer 

23 

24from wxutils import (SimpleText, FloatCtrl, FloatSpin, Choice, Font, pack, 

25 Button, Check, HLine, GridPanel, RowPanel, CEN, LEFT, 

26 RIGHT, FileSave, GUIColors, FRAMESTYLE, BitmapButton, 

27 SetTip, GridPanel, Popup, FloatSpinWithPin, get_icon, 

28 fix_filename, flatnotebook, PeriodicTablePanel) 

29 

30from . import FONTSIZE, FONTSIZE_FW 

31from xraydb import (material_mu, xray_edge, materials, add_material, 

32 atomic_number, atomic_symbol, xray_line) 

33# from .notebooks import flatnotebook 

34# from .periodictable import PeriodicTablePanel 

35from .parameter import ParameterPanel 

36 

37from larch import Group 

38 

39from ..xrf import xrf_background, MCA, FanoFactors 

40from ..utils import json_dump, json_load, gformat 

41from ..utils.jsonutils import encode4js, decode4js 

42from ..utils.physical_constants import E_MASS 

43from ..site_config import user_larchdir 

44from .xrfdisplay_utils import (XRFGROUP, mcaname, XRFRESULTS_GROUP, 

45 MAKE_XRFRESULTS_GROUP) 

46 

47def read_filterdata(flist, _larch): 

48 """ read filters data""" 

49 materials = _larch.symtable.get_symbol('_xray._materials') 

50 out = {} 

51 out['None'] = ('', 0) 

52 for name in flist: 

53 if name in materials: 

54 out[name] = materials[name] 

55 return out 

56 

57def VarChoice(p, default=0, size=(75, -1)): 

58 if default in (False, 'False', 'Fix', 'No'): 

59 default = 0 

60 else: 

61 default = 1 

62 return Choice(p, choices=['Fix', 'Vary'], 

63 size=size, default=default) 

64 

65NFILTERS = 4 

66MIN_CORREL = 0.10 

67 

68tooltips = {'ptable': 'Select Elements to include in model', 

69 'cen': 'centroid of peak', 

70 'step': 'size of step extending to low energy side of peak, fraction of peak height', 

71 'gamma': 'gamma (lorentzian-like weight) of Voigt function', 

72 'tail': 'intensity of tail function at low energy side of peak', 

73 'beta': 'width of tail function at low energy side of peak', 

74 'sigma': 'scale sigma from Energy/Noise by this amount', 

75 } 

76 

77CompositionUnits = ('ng/mm^2', 'wt %', 'ppm') 

78 

79Detector_Materials = ['Si', 'Ge'] 

80EFano_Text = 'Peak Widths: sigma = sqrt(E_Fano * Energy + Noise**2) ' 

81Geom_Text = 'Angles in degrees: 90=normal to surface, 0=grazing surface' 

82Energy_Text = 'All energies in keV' 

83 

84 

85FitTols = ['1.e-2', '3.e-3', '1.e-3', '3.e-4', '1.e-4', '3.e-5', '1.e-5', 

86 '3.e-6', '1.e-6', '3.e-7', '1.e-7'] 

87FitSteps = ['1.e-2', '3.e-3', '1.e-3', '3.e-4', '1.e-4', '3.e-5', '1.e-5', 

88 '3.e-6', '1.e-6', '3.e-7', '1.e-7'] 

89 

90FitMaxNFevs = ['200', '500', '1000', '1500', '2000', '3000', '5000', '10000'] 

91 

92xrfmod_setup = """### XRF Model: {mca_label:s} @ {datetime:s} 

93# mca data group for fit: 

94{XRFGROUP}.workmca = {mcagroup} 

95 

96# setup XRF Model: 

97_xrfmodel = xrf_model(xray_energy={en_xray:.2f}, count_time={count_time:.5f}, 

98 energy_min={en_min:.2f}, energy_max={en_max:.2f}) 

99 

100_xrfmodel.set_detector(thickness={det_thk:.5f}, material='{det_mat:s}', 

101 cal_offset={cal_offset:.5f}, cal_slope={cal_slope:.5f}, 

102 vary_cal_offset={cal_vary!r}, vary_cal_slope={cal_vary!r}, 

103 peak_step={peak_step:.5f}, vary_peak_step={peak_step_vary:s}, 

104 peak_tail={peak_tail:.5f}, vary_peak_tail={peak_tail_vary:s}, 

105 peak_beta={peak_beta:.5f}, vary_peak_beta={peak_beta_vary:s}, 

106 peak_gamma={peak_gamma:.5f}, vary_peak_gamma={peak_gamma_vary:s}, 

107 noise={det_noise:.5f}, vary_noise={det_noise_vary:s})""" 

108 

109xrfmod_scattpeak = """ 

110# add scatter peak 

111_xrfmodel.add_scatter_peak(name='{peakname:s}', center={_cen:.2f}, 

112 amplitude=1e5, step={_step:.5f}, tail={_tail:.5f}, beta={_beta:.5f}, 

113 sigmax={_sigma:.5f}, vary_center={vcen:s}, vary_step={vstep:s}, 

114 vary_tail={vtail:s}, vary_beta={vbeta:s}, vary_sigmax={vsigma:s})""" 

115 

116xrfmod_fitscript = """ 

117# run XRF fit, save results 

118_xrffitresult = _xrfmodel.fit_spectrum({XRFGROUP}.workmca, energy_min={emin:.2f}, energy_max={emax:.2f}, 

119 fit_toler={fit_toler:.6g}, fit_step={fit_step:.6g}, max_nfev={max_nfev:d}) 

120_xrfresults.insert(0, _xrffitresult) 

121######## 

122""" 

123 

124xrfmod_filter = "_xrfmodel.add_filter('{name:s}', {thick:.5f}, vary_thickness={vary:s})" 

125xrfmod_matrix = "_xrfmodel.set_matrix('{name:s}', {thick:.5f}, density={density:.5f})" 

126xrfmod_pileup = "_xrfmodel.add_pileup(scale={scale:.3f}, vary={vary:s})" 

127xrfmod_escape = "_xrfmodel.add_escape(scale={scale:.3f}, vary={vary:s})" 

128 

129xrfmod_savejs = "_xrfresults[{nfit:d}].save('{filename:s}')" 

130 

131xrfmod_elems = """ 

132# add elements 

133for atsym in {elemlist:s}: 

134 _xrfmodel.add_element(atsym) 

135#endfor 

136del atsym""" 

137 

138Filter_Lengths = ['microns', 'mm', 'cm'] 

139Filter_Materials = ['None', 'air', 'nitrogen', 'helium', 'kapton', 

140 'beryllium', 'aluminum', 'mylar', 'pmma'] 

141 

142 

143DEF_CONFIG = { "mca_name": "", "escape_use": True, "escape_amp": 0.25, 

144 "pileup_use": True, "pileup_amp": 0.1, "escape_amp_vary": 

145 True, "pileup_amp_vary": True, "cal_slope": 0.01, 

146 "cal_offset": 0, "cal_vary": True, "det_mat": "Si", "det_thk": 

147 0.4, "det_noise_vary": True, 

148 "en_xray": 30, "en_min": 2.5, "en_max": 30, 

149 "flux_in": 1e9, "det_noise": 0.035, "angle_in": 45.0, 

150 "angle_out": 45.0, "det_dist": 50.0, "det_area": 50.0, 

151 "elements": [16, 17, 18, 20, 22, 24, 25, 26, 28, 29, 30], 

152 "filter1_mat": "beryllium", "filter1_thk": 0.025, "filter1_var": False, 

153 "filter2_mat": "air", "filter2_thk": 50.0, "filter2_var": False, 

154 "filter3_mat": "kapton", "filter3_thk": 0.0, "filter3_var": False, 

155 "filter4_mat": "aluminum", "filter4_thk": 0.0, "filter4_var": False, 

156 "matrix_mat": "", "matrix_thk": 0.0, "matrix_den": 1.0, 

157 "peak_step": 0.025, "peak_gamma": 0.05, "peak_tail": 0.1, 

158 "peak_beta": 0.5, "peak_step_vary": False, "peak_tail_vary": False, 

159 "peak_gamma_vary": False, "peak_beta_vary": False, 

160 "elastic_use": True, "elastic_cen_vary": False, "elastic_step_vary": False, 

161 "elastic_beta_vary": False, "elastic_tail_vary": False, 

162 "elastic_sigma_vary": False, "elastic_cen": 30, 

163 "elastic_step": 0.025, "elastic_tail": 0.1, 

164 "elastic_beta": 0.5, "elastic_sigma": 1.0, 

165 "compton1_use": True, "compton1_cen_vary": True, 

166 "compton1_step_vary": True, "compton1_beta_vary": False, 

167 "compton1_tail_vary": False, "compton1_sigma_vary": False, 

168 "compton1_cen": 12.1875, "compton1_step": 0.025, "compton1_tail": 0.25, 

169 "compton1_beta": 2.0, "compton1_sigma": 1.5, 

170 "compton2_use": True, "compton2_cen_vary": True, "compton2_step_vary": False, 

171 "compton2_beta_vary": False, "compton2_tail_vary": False, 

172 "compton2_sigma_vary": False, "compton2_cen": 11.875, 

173 "compton2_step": 0.025, "compton2_tail": 0.25, "compton2_beta": 2.5, 

174 "compton2_sigma": 2.0, "count_time": 120.0, 

175 } 

176 

177class FitSpectraFrame(wx.Frame): 

178 """Frame for Spectral Analysis""" 

179 

180 def __init__(self, parent, size=(750, 850)): 

181 self.parent = parent 

182 self._larch = parent.larch 

183 symtable = self._larch.symtable 

184 # fetch current spectra from parent 

185 if not symtable.has_group(XRFRESULTS_GROUP): 

186 self._larch.eval(MAKE_XRFRESULTS_GROUP) 

187 

188 self.xrfresults = symtable.get_symbol(XRFRESULTS_GROUP) 

189 xrfgroup = symtable.get_group(XRFGROUP) 

190 mcagroup = getattr(xrfgroup, '_mca') 

191 self.mca = getattr(xrfgroup, mcagroup) 

192 self.mcagroup = f'{XRFGROUP}.{mcagroup}' 

193 

194 self.config = DEF_CONFIG 

195 

196 opts = getattr(xrfgroup, 'fitconfig', None) 

197 if opts is None: 

198 xrf_conffile = os.path.join(user_larchdir, 'xrf_fitconfig.json') 

199 if os.path.exists(xrf_conffile): 

200 opts = json_load(xrf_conffile) 

201 if opts is not None: 

202 self.config.update(opts) 

203 

204 efactor = 1.0 if max(self.mca.energy) < 250. else 1000.0 

205 

206 if self.mca.incident_energy is None: 

207 self.mca.incident_energy = 20.0 

208 if self.mca.incident_energy > 250: 

209 self.mca.incident_energy /= 1000.0 

210 

211 self.nfit = 0 

212 self.colors = GUIColors() 

213 wx.Frame.__init__(self, parent, -1, 'Fit XRF Spectra', 

214 size=size, style=wx.DEFAULT_FRAME_STYLE) 

215 

216 self.font_fixedwidth = wx.Font(FONTSIZE_FW, wx.MODERN, wx.NORMAL, wx.NORMAL) # fixed width 

217 

218 

219 self.wids = {} 

220 self.owids = {} 

221 

222 pan = GridPanel(self) 

223 self.mca_label = self.mca.label 

224 self.wids['mca_name'] = SimpleText(pan, self.mca_label, size=(300, -1), style=LEFT) 

225 self.wids['btn_calc'] = Button(pan, 'Calculate Model', size=(150, -1), 

226 action=self.onShowModel) 

227 self.wids['btn_fit'] = Button(pan, 'Fit Model', size=(150, -1), 

228 action=self.onFitModel) 

229 

230 pan.AddText(" XRF Spectrum: ", colour='#880000') 

231 pan.Add(self.wids['mca_name'], dcol=3) 

232 pan.Add(self.wids['btn_calc'], newrow=True) 

233 pan.Add(self.wids['btn_fit']) 

234 

235 self.panels = {} 

236 self.panels['Beam & Detector'] = self.beamdet_page 

237 self.panels['Filters & Matrix'] = self.materials_page 

238 self.panels['Elements & Peaks'] = self.elempeaks_page 

239 self.panels['Fit Results'] = self.fitresult_page 

240 self.panels['Composition'] = self.composition_page 

241 

242 self.nb = flatnotebook(pan, self.panels, on_change=self.onNBChanged) 

243 pan.Add((5, 5), newrow=True) 

244 pan.Add(self.nb, dcol=5, drow=10, newrow=True) 

245 pan.pack() 

246 

247 self.Show() 

248 self.Raise() 

249 

250 def onNBChanged(self, event=None): 

251 pagelabel = self.nb._pages.GetPageText(event.GetSelection()).strip() 

252 if pagelabel.startswith('Composition'): 

253 self.UpdateCompositionPage() 

254 

255 def elempeaks_page(self, **kws): 

256 "elements and peaks parameters" 

257 mca = self.parent.mca 

258 wids = self.wids 

259 p = GridPanel(self) 

260 self.selected_elems = [] 

261 self.ptable = PeriodicTablePanel(p, multi_select=True, fontsize=11, 

262 size=(360, 180), 

263 tooltip_msg=tooltips['ptable'], 

264 onselect=self.onElemSelect) 

265 cnf = self.config 

266 for name, xmax, xinc in (('step', 1, 0.005), 

267 ('gamma', 10, 0.01), 

268 ('beta', 10, 0.01), 

269 ('tail', 1.0, 0.05)): 

270 fname = 'peak_%s' % name 

271 vname = 'peak_%s_vary' % name 

272 wids[fname] = FloatSpin(p, value=cnf[fname], digits=3, 

273 min_val=0, max_val=xmax, 

274 increment=xinc, tooltip=tooltips[name]) 

275 wids[vname] = VarChoice(p, default=cnf[vname]) 

276 

277 btn_from_peaks = Button(p, 'Guess Peaks', size=(150, -1), 

278 action=self.onElems_GuessPeaks) 

279 # tooltip='Guess elements from peak locations') 

280 btn_from_rois = Button(p, 'Use ROIS as Peaks', size=(150, -1), 

281 action=self.onElems_FromROIS) 

282 btn_clear_elems = Button(p, 'Clear All Peaks', size=(150, -1), 

283 action=self.onElems_Clear) 

284 wx.CallAfter(self.onElems_GuessPeaks) 

285 

286 p.AddText('Elements to model:', colour='#880000', dcol=2) 

287 p.Add((2, 2), newrow=True) 

288 p.Add(self.ptable, dcol=5, drow=5) 

289 irow = p.irow 

290 

291 p.Add(btn_from_peaks, icol=6, dcol=2, irow=irow) 

292 p.Add(btn_from_rois, icol=6, dcol=2, irow=irow+1) 

293 p.Add(btn_clear_elems, icol=6, dcol=2, irow=irow+2) 

294 p.irow += 5 

295 

296 p.Add((2, 2), newrow=True) 

297 p.AddText(' Step: ') 

298 p.Add(wids['peak_step']) 

299 p.Add(wids['peak_step_vary']) 

300 

301 p.AddText(' Gamma : ') 

302 p.Add(wids['peak_gamma']) 

303 p.Add(wids['peak_gamma_vary']) 

304 

305 p.Add((2, 2), newrow=True) 

306 p.AddText(' Beta: ') 

307 p.Add(wids['peak_beta']) 

308 p.Add(wids['peak_beta_vary']) 

309 

310 p.AddText(' Tail: ') 

311 p.Add(wids['peak_tail']) 

312 p.Add(wids['peak_tail_vary']) 

313 p.Add((2, 2), newrow=True) 

314 p.Add(HLine(p, size=(650, 3)), dcol=8) 

315 p.Add((2, 2), newrow=True) 

316 

317 opts = dict(size=(100, -1), min_val=0, digits=4, increment=0.010) 

318 for name, escale in (('elastic', 0), ('compton1', 1), ('compton2', 2)): 

319 en = self.mca.incident_energy 

320 for i in range(escale): 

321 en = en * (1 - 1/(1 + (E_MASS*0.001)/en)) # Compton shift at 90 deg 

322 

323 wids[f'{name:s}_use'] = Check(p, label='Include', default=cnf[f'{name:s}_use']) 

324 p.Add((2, 2), newrow=True) 

325 p.AddText(" %s Peak:" % name.title(), colour='#880000') 

326 p.Add(wids[f'{name:s}_use'], dcol=2) 

327 

328 for att, title, xmax, xinc, newrow in (('cen', ' Energy (kev): ', 9e12, 0.01, True), 

329 ('step', ' Step: ', 1, 0.005, False), 

330 ('sigma', ' Sigma Scale:', 10, 0.05, True), 

331 ('beta', ' Beta: ', 10, 0.01, False), 

332 ('tail', ' Tail: ', 10, 0.01, True)): 

333 label = f'{name:s}_{att:s}' 

334 val = en if att == 'cen' else cnf[label] 

335 wids[f'{label:s}_vary'] = VarChoice(p, default=cnf[f'{label:s}_vary']) 

336 

337 wids[label] = FloatSpin(p, value=val, digits=3, min_val=0, 

338 max_val=xmax, increment=xinc, 

339 tooltip=tooltips[att]) 

340 

341 p.AddText(title) 

342 p.Add(wids[label]) 

343 p.Add(wids[f'{label:s}_vary']) 

344 if newrow: 

345 p.Add((2, 2), newrow=True) 

346 

347 p.Add(HLine(p, size=(650, 3)), dcol=7) 

348 

349 p.pack() 

350 return p 

351 

352 def beamdet_page(self, **kws): 

353 "beam / detector settings" 

354 mca = self.mca 

355 en_min = 2.0 

356 en_max = self.mca.incident_energy 

357 

358 cal_offset = getattr(mca, 'offset', 0) 

359 cal_slope = getattr(mca, 'slope', 0.010) 

360 det_noise = getattr(mca, 'det_noise', 0.035) 

361 escape_amp = getattr(mca, 'escape_amp', 0.10) 

362 

363 if not hasattr(self.mca, 'pileup_scale'): 

364 self.mca.predict_pileup() 

365 pileup_amp = max(0.001, getattr(mca, 'pileup_scale', 0.05)) 

366 

367 wids = self.wids 

368 pdet = GridPanel(self, itemstyle=LEFT) 

369 

370 def addLine(pan): 

371 pan.Add(HLine(pan, size=(650, 3)), dcol=6, newrow=True) 

372 

373 

374 wids['escape_use'] = Check(pdet, label='Include Escape in Fit', 

375 default=True, action=self.onUsePileupEscape) 

376 wids['escape_amp'] = FloatSpin(pdet, value=escape_amp, 

377 min_val=0, max_val=100, digits=3, 

378 increment=0.01, size=(100, -1)) 

379 

380 wids['pileup_use'] = Check(pdet, label='Include Pileup in Fit', 

381 default=True, 

382 action=self.onUsePileupEscape) 

383 wids['pileup_amp'] = FloatSpin(pdet, value=pileup_amp, 

384 min_val=0, max_val=100, digits=3, 

385 increment=0.01, size=(100, -1)) 

386 

387 wids['escape_amp_vary'] = VarChoice(pdet, default=True) 

388 wids['pileup_amp_vary'] = VarChoice(pdet, default=(pileup_amp>0.002)) 

389 

390 

391 wids['cal_slope'] = FloatSpin(pdet, value=cal_slope, 

392 min_val=0, max_val=100, 

393 digits=4, increment=0.01, size=(100, -1)) 

394 wids['cal_offset'] = FloatSpin(pdet, value=cal_offset, 

395 min_val=-500, max_val=500, 

396 digits=4, increment=0.01, size=(100, -1)) 

397 

398 wids['cal_vary'] = Check(pdet, label='Vary Calibration in Fit', default=True) 

399 

400 wids['det_mat'] = Choice(pdet, choices=Detector_Materials, 

401 size=(70, -1), default=0, 

402 action=self.onDetMaterial) 

403 

404 wids['det_thk'] = FloatSpin(pdet, value=0.400, size=(100, -1), 

405 increment=0.010, min_val=0, max_val=10, 

406 digits=4) 

407 

408 wids['det_noise_vary'] = VarChoice(pdet, default=1) 

409 

410 opts = dict(size=(100, -1), min_val=0, max_val=500, digits=3, 

411 increment=0.10) 

412 wids['en_xray'] = FloatSpin(pdet, value=self.mca.incident_energy, 

413 action=self.onSetXrayEnergy, **opts) 

414 wids['en_min'] = FloatSpin(pdet, value=en_min, **opts) 

415 wids['en_max'] = FloatSpin(pdet, value=en_max, **opts) 

416 wids['flux_in'] = FloatCtrl(pdet, value=5.e10, gformat=True, 

417 minval=0, size=(100, -1)) 

418 

419 opts.update({'increment': 0.005}) 

420 wids['det_noise'] = FloatSpin(pdet, value=det_noise, **opts) 

421 wids['det_efano'] = SimpleText(pdet, size=(200, -1), 

422 label='E_Fano= %.4e' % FanoFactors['Si']) 

423 

424 opts.update(digits=1, max_val=90, min_val=0, increment=1) 

425 wids['angle_in'] = FloatSpin(pdet, value=45, **opts) 

426 wids['angle_out'] = FloatSpin(pdet, value=45, **opts) 

427 

428 opts.update(digits=1, max_val=5e9, min_val=0, increment=1) 

429 wids['det_dist'] = FloatSpin(pdet, value=50, **opts) 

430 wids['det_area'] = FloatSpin(pdet, value=50, **opts) 

431 

432 for notyet in ('angle_in', 'angle_out', 'det_dist', 'det_area', 

433 'flux_in'): 

434 wids[notyet].Disable() 

435 

436 wids['fit_toler'] = Choice(pdet, choices=FitTols, size=(90, -1)) 

437 wids['fit_toler'].SetStringSelection('1.e-4') 

438 wids['fit_step'] = Choice(pdet, choices=FitSteps, size=(90, -1)) 

439 wids['fit_step'].SetStringSelection('1.e-4') 

440 wids['fit_maxnfev'] = Choice(pdet, choices=FitMaxNFevs, size=(90, -1)) 

441 wids['fit_maxnfev'].SetStringSelection('1000') 

442 

443 pdet.AddText(' Beam Energy, Fit Range :', colour='#880000', dcol=2) 

444 pdet.AddText(' X-ray Energy (keV): ', newrow=True) 

445 pdet.Add(wids['en_xray']) 

446 pdet.AddText('Incident Flux (Hz): ', newrow=False) 

447 pdet.Add(wids['flux_in']) 

448 pdet.AddText(' Fit Energy Min (keV): ', newrow=True) 

449 pdet.Add(wids['en_min']) 

450 pdet.AddText('Fit Energy Max (keV): ') 

451 pdet.Add(wids['en_max']) 

452 pdet.AddText(' Fit Step Size: ', newrow=True) 

453 pdet.Add(wids['fit_step']) 

454 pdet.AddText('Fit Tolerance: ') 

455 pdet.Add(wids['fit_toler']) 

456 pdet.AddText(' Fit Max Evaluations: ', newrow=True) 

457 pdet.Add(wids['fit_maxnfev']) 

458 

459 

460 addLine(pdet) 

461 pdet.AddText(' Energy Calibration :', colour='#880000', dcol=1, newrow=True) 

462 pdet.Add(wids['cal_vary'], dcol=2) 

463 pdet.AddText(' Offset (keV): ', newrow=True) 

464 pdet.Add(wids['cal_offset']) 

465 pdet.AddText('Slope (keV/bin): ') 

466 pdet.Add(wids['cal_slope']) 

467 

468 addLine(pdet) 

469 pdet.AddText(' Detector Material:', colour='#880000', dcol=1, newrow=True) 

470 pdet.AddText(EFano_Text, dcol=3) 

471 pdet.AddText(' Material: ', newrow=True) 

472 pdet.Add(wids['det_mat']) 

473 pdet.Add(wids['det_efano'], dcol=2) 

474 pdet.AddText(' Thickness (mm): ', newrow=True) 

475 pdet.Add(wids['det_thk']) 

476 pdet.AddText(' Noise (keV): ', newrow=True) 

477 pdet.Add(wids['det_noise']) 

478 pdet.Add(wids['det_noise_vary'], dcol=2) 

479 

480 

481 addLine(pdet) 

482 pdet.AddText(' Escape && Pileup:', colour='#880000', dcol=2, newrow=True) 

483 pdet.AddText(' Escape Scale:', newrow=True) 

484 pdet.Add(wids['escape_amp']) 

485 pdet.Add(wids['escape_amp_vary']) 

486 pdet.Add(wids['escape_use'], dcol=3) 

487 

488 pdet.AddText(' Pileup Scale:', newrow=True) 

489 pdet.Add(wids['pileup_amp']) 

490 pdet.Add(wids['pileup_amp_vary']) 

491 pdet.Add(wids['pileup_use'], dcol=3) 

492 

493 addLine(pdet) 

494 pdet.AddText(' Geometry:', colour='#880000', dcol=1, newrow=True) 

495 pdet.AddText(Geom_Text, dcol=3) 

496 pdet.AddText(' Incident Angle (deg):', newrow=True) 

497 pdet.Add(wids['angle_in']) 

498 pdet.AddText(' Exit Angle (deg):', newrow=False) 

499 pdet.Add(wids['angle_out']) 

500 pdet.AddText(' Detector Distance (mm): ', newrow=True) 

501 pdet.Add(wids['det_dist']) 

502 pdet.AddText(' Detector Area (mm^2): ', newrow=False) 

503 pdet.Add(wids['det_area']) 

504 

505 

506 addLine(pdet) 

507 pdet.pack() 

508 return pdet 

509 

510 def materials_page(self, **kws): 

511 "filters and matrix settings" 

512 wids = self.wids 

513 pan = GridPanel(self, itemstyle=LEFT) 

514 

515 pan.AddText(' Filters :', colour='#880000', dcol=2) # , newrow=True) 

516 pan.AddManyText((' Filter #', 'Material', 'Thickness (mm)', 

517 'Vary Thickness'), style=LEFT, newrow=True) 

518 opts = dict(size=(125, -1), min_val=0, digits=5, increment=0.005) 

519 

520 for i in range(NFILTERS): 

521 t = 'filter%d' % (i+1) 

522 wids['%s_mat'%t] = Choice(pan, choices=Filter_Materials, default=0, 

523 size=(150, -1), 

524 action=partial(self.onFilterMaterial, index=i+1)) 

525 wids['%s_thk'%t] = FloatSpin(pan, value=0.0, **opts) 

526 wids['%s_var'%t] = VarChoice(pan, default=0) 

527 if i == 0: # first selection 

528 wids['%s_mat'%t].SetStringSelection('beryllium') 

529 wids['%s_thk'%t].SetValue(0.0250) 

530 elif i == 1: # second selection 

531 wids['%s_mat'%t].SetStringSelection('air') 

532 wids['%s_thk'%t].SetValue(50.00) 

533 elif i == 2: # third selection 

534 wids['%s_mat'%t].SetStringSelection('kapton') 

535 wids['%s_thk'%t].SetValue(0.00) 

536 elif i == 3: # third selection 

537 wids['%s_mat'%t].SetStringSelection('aluminum') 

538 wids['%s_thk'%t].SetValue(0.00) 

539 

540 pan.AddText(' %i' % (i+1), newrow=True) 

541 pan.Add(wids['%s_mat' % t]) 

542 pan.Add(wids['%s_thk' % t]) 

543 pan.Add(wids['%s_var' % t]) 

544 

545 pan.Add(HLine(pan, size=(650, 3)), dcol=6, newrow=True) 

546 

547 pan.AddText(' Matrix:', colour='#880000', newrow=True) 

548 pan.AddText(' NOTE: thin film limit only', dcol=3) 

549 

550 wids['matrix_mat'] = wx.TextCtrl(pan, value='', size=(275, -1)) 

551 wids['matrix_thk'] = FloatSpin(pan, value=0.0, **opts) 

552 wids['matrix_den'] = FloatSpin(pan, value=1.0, **opts) 

553 wids['matrix_btn'] = Button(pan, 'Use Material', size=(175, -1), 

554 action=self.onUseCurrentMaterialAsFilter) 

555 wids['matrix_btn'].Disable() 

556 pan.AddText(' Material/Formula:', dcol=1, newrow=True) 

557 pan.Add(wids['matrix_mat'], dcol=2) 

558 pan.Add(wids['matrix_btn'], dcol=3) 

559 pan.AddText(' Thickness (mm):', newrow=True) 

560 pan.Add(wids['matrix_thk']) 

561 pan.AddText(' Density (gr/cm^3):', newrow=False) 

562 pan.Add(wids['matrix_den']) 

563 

564 pan.Add(HLine(pan, size=(650, 3)), dcol=6, newrow=True) 

565 

566 # Materials 

567 pan.AddText(' Known Materials:', colour='#880000', dcol=4, newrow=True) 

568 

569 mview = self.owids['materials'] = dv.DataViewListCtrl(pan, style=DVSTYLE) 

570 mview.Bind(dv.EVT_DATAVIEW_SELECTION_CHANGED, self.onSelectMaterial) 

571 self.selected_material = '' 

572 

573 mview.AppendTextColumn('Name', width=150) 

574 mview.AppendTextColumn('Formula', width=325) 

575 mview.AppendTextColumn('density', width=90) 

576 mview.AppendToggleColumn('Filter?', width=75) 

577 for col in range(4): 

578 this = mview.Columns[col] 

579 align = wx.ALIGN_LEFT 

580 this.Sortable = True 

581 this.Alignment = this.Renderer.Alignment = align 

582 

583 mview.SetMinSize((725, 170)) 

584 mview.DeleteAllItems() 

585 self.materials_data = {} 

586 for name, data in materials._read_materials_db().items(): 

587 # print("DATA " , name, data) 

588 formula, density = data.formula, data.density 

589 self.materials_data[name] = (formula, density) 

590 mview.AppendItem((name, formula, "%9.6f"%density, 

591 name in Filter_Materials)) 

592 pan.Add(mview, dcol=5, newrow=True) 

593 

594 pan.AddText(' Add Material:', colour='#880000', newrow=True) 

595 pan.Add(Button(pan, 'Add', size=(175, -1), 

596 action=self.onAddMaterial)) 

597 pan.Add((10, 10)) 

598 bx = Button(pan, 'Update Filter List', size=(175, -1), 

599 action=self.onUpdateFilterList) 

600 pan.Add(bx) 

601 

602 self.owids['newmat_name'] = wx.TextCtrl(pan, value='', size=(175, -1)) 

603 self.owids['newmat_dens'] = FloatSpin(pan, value=1.0, **opts) 

604 self.owids['newmat_form'] = wx.TextCtrl(pan, value='', size=(400, -1)) 

605 

606 

607 for notyet in ('matrix_mat', 'matrix_thk', 'matrix_den', 

608 'matrix_btn'): 

609 wids[notyet].Disable() 

610 

611 pan.AddText(' Name:', newrow=True) 

612 pan.Add(self.owids['newmat_name']) 

613 pan.AddText(' Density (gr/cm^3):', newrow=False) 

614 pan.Add(self.owids['newmat_dens']) 

615 pan.AddText(' Formula:', newrow=True) 

616 pan.Add(self.owids['newmat_form'], dcol=3) 

617 pan.pack() 

618 return pan 

619 

620 def fitresult_page(self, **kws): 

621 sizer = wx.GridBagSizer(10, 5) 

622 panel = scrolled.ScrolledPanel(self) 

623 # title row 

624 wids = self.owids 

625 title = SimpleText(panel, 'Fit Results', font=Font(FONTSIZE+1), 

626 colour=self.colors.title, style=LEFT) 

627 

628 wids['data_title'] = SimpleText(panel, '< > ', font=Font(FONTSIZE+1), 

629 colour=self.colors.title, style=LEFT) 

630 

631 wids['fitlabel_lab'] = SimpleText(panel, 'Fit Label:') 

632 wids['fitlabel_txt'] = wx.TextCtrl(panel, -1, ' ', size=(150, -1)) 

633 wids['fitlabel_btn'] = Button(panel, 'Set Label', size=(150, -1), 

634 action=self.onChangeFitLabel) 

635 

636 opts = dict(default=False, size=(175, -1), action=self.onPlot) 

637 wids['plot_comps'] = Check(panel, label='Show Components?', **opts) 

638 self.plot_choice = Button(panel, 'Plot', 

639 size=(150, -1), action=self.onPlot) 

640 

641 self.save_result = Button(panel, 'Save Model', 

642 size=(150, -1), action=self.onSaveFitResult) 

643 SetTip(self.save_result, 'save model and result to be loaded later') 

644 

645 self.export_fit = Button(panel, 'Export Fit', 

646 size=(150, -1), action=self.onExportFitResult) 

647 SetTip(self.export_fit, 'save arrays and results to text file') 

648 

649 irow = 0 

650 sizer.Add(title, (irow, 0), (1, 1), LEFT) 

651 sizer.Add(wids['data_title'], (irow, 1), (1, 3), LEFT) 

652 

653 irow += 1 

654 sizer.Add(self.save_result, (irow, 0), (1, 1), LEFT) 

655 sizer.Add(self.export_fit, (irow, 1), (1, 1), LEFT) 

656 sizer.Add(self.plot_choice, (irow, 2), (1, 1), LEFT) 

657 sizer.Add(wids['plot_comps'], (irow, 3), (1, 1), LEFT) 

658 

659 irow += 1 

660 sizer.Add(wids['fitlabel_lab'], (irow, 0), (1, 1), LEFT) 

661 sizer.Add(wids['fitlabel_txt'], (irow, 1), (1, 1), LEFT) 

662 sizer.Add(wids['fitlabel_btn'], (irow, 2), (1, 2), LEFT) 

663 

664 

665 irow += 1 

666 sizer.Add(HLine(panel, size=(650, 3)), (irow, 0), (1, 5), LEFT) 

667 

668 irow += 1 

669 title = SimpleText(panel, '[[Fit Statistics]]', font=Font(FONTSIZE+1), 

670 colour=self.colors.title, style=LEFT) 

671 sizer.Add(title, (irow, 0), (1, 4), LEFT) 

672 

673 sview = wids['stats'] = dv.DataViewListCtrl(panel, style=DVSTYLE) 

674 sview.SetFont(self.font_fixedwidth) 

675 sview.Bind(dv.EVT_DATAVIEW_SELECTION_CHANGED, self.onSelectFit) 

676 sview.AppendTextColumn('Fit Label', width=120) 

677 sview.AppendTextColumn('N_vary', width=80) 

678 sview.AppendTextColumn('N_eval', width=80) 

679 sview.AppendTextColumn('\u03c7\u00B2', width=130) 

680 sview.AppendTextColumn('\u03c7\u00B2_reduced', width=130) 

681 sview.AppendTextColumn('Akaike Info', width=130) 

682 

683 for col in range(sview.ColumnCount): 

684 this = sview.Columns[col] 

685 isort, align = True, wx.ALIGN_RIGHT 

686 if col == 0: 

687 align = wx.ALIGN_LEFT 

688 this.Sortable = isort 

689 this.Alignment = this.Renderer.Alignment = align 

690 sview.SetMinSize((725, 150)) 

691 

692 irow += 1 

693 sizer.Add(sview, (irow, 0), (1, 5), LEFT) 

694 

695 irow += 1 

696 sizer.Add(HLine(panel, size=(650, 3)), (irow, 0), (1, 5), LEFT) 

697 

698 irow += 1 

699 title = SimpleText(panel, '[[Variables]]', font=Font(FONTSIZE+1), 

700 colour=self.colors.title, style=LEFT) 

701 sizer.Add(title, (irow, 0), (1, 1), LEFT) 

702 

703 pview = wids['params'] = dv.DataViewListCtrl(panel, style=DVSTYLE) 

704 pview.SetFont(self.font_fixedwidth) 

705 wids['paramsdata'] = [] 

706 pview.AppendTextColumn('Parameter', width=150) 

707 pview.AppendTextColumn('Refined Value', width=130) 

708 pview.AppendTextColumn('Standard Error', width=130) 

709 pview.AppendTextColumn('% Uncertainty', width=130) 

710 pview.AppendTextColumn('Initial Value', width=130) 

711 

712 for col in range(4): 

713 this = pview.Columns[col] 

714 align = wx.ALIGN_LEFT 

715 if col > 0: 

716 align = wx.ALIGN_RIGHT 

717 this.Sortable = False 

718 this.Alignment = this.Renderer.Alignment = align 

719 

720 pview.SetMinSize((725, 200)) 

721 pview.Bind(dv.EVT_DATAVIEW_SELECTION_CHANGED, self.onSelectParameter) 

722 

723 irow += 1 

724 sizer.Add(pview, (irow, 0), (1, 5), LEFT) 

725 

726 irow += 1 

727 sizer.Add(HLine(panel, size=(650, 3)), (irow, 0), (1, 5), LEFT) 

728 

729 irow += 1 

730 title = SimpleText(panel, '[[Correlations]]', font=Font(FONTSIZE+1), 

731 colour=self.colors.title, style=LEFT) 

732 

733 wids['all_correl'] = Button(panel, 'Show All', 

734 size=(100, -1), action=self.onAllCorrel) 

735 

736 wids['min_correl'] = FloatSpin(panel, value=MIN_CORREL, 

737 min_val=0, size=(100, -1), 

738 digits=3, increment=0.1) 

739 

740 ctitle = SimpleText(panel, 'minimum correlation: ') 

741 sizer.Add(title, (irow, 0), (1, 1), LEFT) 

742 sizer.Add(ctitle, (irow, 1), (1, 1), LEFT) 

743 sizer.Add(wids['min_correl'], (irow, 2), (1, 1), LEFT) 

744 sizer.Add(wids['all_correl'], (irow, 3), (1, 1), LEFT) 

745 

746 cview = wids['correl'] = dv.DataViewListCtrl(panel, style=DVSTYLE) 

747 cview.SetFont(self.font_fixedwidth) 

748 cview.AppendTextColumn('Parameter 1', width=150) 

749 cview.AppendTextColumn('Parameter 2', width=150) 

750 cview.AppendTextColumn('Correlation', width=150) 

751 

752 for col in (0, 1, 2): 

753 this = cview.Columns[col] 

754 this.Sortable = False 

755 align = wx.ALIGN_LEFT 

756 if col == 2: 

757 align = wx.ALIGN_RIGHT 

758 this.Alignment = this.Renderer.Alignment = align 

759 cview.SetMinSize((725, 125)) 

760 

761 irow += 1 

762 sizer.Add(cview, (irow, 0), (1, 5), LEFT) 

763 pack(panel, sizer) 

764 panel.SetMinSize((725, 750)) 

765 panel.SetupScrolling() 

766 return panel 

767 

768 def composition_page(self, **kws): 

769 sizer = wx.GridBagSizer(10, 5) 

770 panel = scrolled.ScrolledPanel(self) 

771 wids = self.owids 

772 title = SimpleText(panel, 'Composition Results', font=Font(FONTSIZE+1), 

773 colour=self.colors.title, style=LEFT) 

774 wids['data_title2'] = SimpleText(panel, '< > ', font=Font(FONTSIZE+1), 

775 colour=self.colors.title, style=LEFT) 

776 

777 cview = wids['composition'] = dv.DataViewListCtrl(panel, style=DVSTYLE) 

778 cview.SetFont(self.font_fixedwidth) 

779 cview.AppendTextColumn(' Z ', width=50) 

780 cview.AppendTextColumn(' Element ', width=100) 

781 cview.AppendTextColumn(' Amplitude', width=170) 

782 cview.AppendTextColumn(' Concentration', width=170) 

783 cview.AppendTextColumn(' Uncertainty', width=180) 

784 

785 for col in range(5): 

786 this = cview.Columns[col] 

787 align = wx.ALIGN_RIGHT 

788 if col == 1: 

789 align = wx.ALIGN_LEFT 

790 this.Sortable = True 

791 this.Alignment = this.Renderer.Alignment = align 

792 

793 cview.SetMinSize((725, 500)) 

794 wids['comp_fitlabel'] = Choice(panel, choices=[''], size=(175, -1), 

795 action=self.onCompSelectFit) 

796 

797 self.compscale_lock = 0.0 

798 wids['comp_elemchoice'] = Choice(panel, choices=[''], size=(100, -1)) 

799 # action=self.onCompSetElemAbundance) 

800 wids['comp_elemscale'] = FloatSpin(panel, value=1.0, digits=5, min_val=0, 

801 increment=0.01, 

802 action=self.onCompSetElemAbundance) 

803 wids['comp_units'] = Choice(panel, choices=CompositionUnits, size=(100, -1)) 

804 wids['comp_scale'] = FloatCtrl(panel, value=0, size=(200, -1), precision=5, 

805 minval=0, action=self.onCompSetScale) 

806 

807 wids['comp_save'] = Button(panel, 'Save This Concentration Data', 

808 size=(200, -1), action=self.onCompSave) 

809 

810 irow = 0 

811 sizer.Add(title, (irow, 0), (1, 2), LEFT) 

812 sizer.Add(wids['data_title2'], (irow, 2), (1, 5), LEFT) 

813 irow += 1 

814 sizer.Add(SimpleText(panel, 'Fit Label:'), (irow, 0), (1, 1), LEFT) 

815 sizer.Add(wids['comp_fitlabel'], (irow, 1), (1, 5), LEFT) 

816 

817 irow += 1 

818 sizer.Add(SimpleText(panel, 'Scale Element:'), (irow, 0), (1, 1), LEFT) 

819 sizer.Add(wids['comp_elemchoice'], (irow, 1), (1, 1), LEFT) 

820 sizer.Add(SimpleText(panel, ' to:'), (irow, 2), (1, 1), LEFT) 

821 sizer.Add(wids['comp_elemscale'], (irow, 3), (1, 1), LEFT) 

822 sizer.Add(wids['comp_units'], (irow, 4), (1, 1), LEFT) 

823 

824 irow += 1 

825 sizer.Add(SimpleText(panel, 'Scaling Factor:'), (irow, 0), (1, 1), LEFT) 

826 sizer.Add(wids['comp_scale'], (irow, 1), (1, 3), LEFT) 

827 

828 irow += 1 

829 sizer.Add(wids['composition'], (irow, 0), (3, 6), LEFT) 

830 

831 irow += 3 

832 sizer.Add(wids['comp_save'], (irow, 0), (1, 3), LEFT) 

833 

834 pack(panel, sizer) 

835 panel.SetMinSize((725, 750)) 

836 panel.SetupScrolling() 

837 return panel 

838 

839 def onCompSetScale(self, event=None, value=None): 

840 if len(self.xrfresults) < 1 or (time.time() - self.compscale_lock) < 0.25: 

841 return 

842 self.compscale_lock = time.time() 

843 owids = self.owids 

844 result = self.get_fitresult(nfit=owids['comp_fitlabel'].GetSelection()) 

845 cur_elem = owids['comp_elemchoice'].GetStringSelection() 

846 conc_vals = {} 

847 for elem in result.comps.keys(): 

848 parname = 'amp_%s' % elem.lower() 

849 if parname in result.params: 

850 par = result.params[parname] 

851 conc_vals[elem] = [par.value, par.stderr] 

852 

853 try: 

854 scale = self.owids['comp_scale'].GetValue() 

855 except: 

856 return 

857 

858 owids['comp_elemscale'].SetValue(conc_vals[cur_elem][0]*scale) 

859 owids['composition'].DeleteAllItems() 

860 result.concentration_results = conc_vals 

861 result.concentration_scale = scale 

862 

863 for elem, dat in conc_vals.items(): 

864 zat = "%d" % atomic_number(elem) 

865 val, serr = dat 

866 rval = "%15.4f" % val 

867 sval = "%15.4f" % (val*scale) 

868 uval = "%15.4f" % (serr*scale) 

869 try: 

870 uval = uval + ' ({:.2%})'.format(abs(serr/val)) 

871 except ZeroDivisionError: 

872 pass 

873 owids['composition'].AppendItem((zat, elem, rval, sval, uval)) 

874 

875 def onCompSetElemAbundance(self, event=None, value=None): 

876 if len(self.xrfresults) < 1 or (time.time() - self.compscale_lock) < 0.25: 

877 return 

878 self.compscale_lock = time.time() 

879 owids = self.owids 

880 result = self.get_fitresult(nfit=owids['comp_fitlabel'].GetSelection()) 

881 cur_elem = owids['comp_elemchoice'].GetStringSelection() 

882 conc_vals = {} 

883 for elem in result.comps.keys(): 

884 parname = 'amp_%s' % elem.lower() 

885 if parname in result.params: 

886 par = result.params[parname] 

887 conc_vals[elem] = [par.value, par.stderr] 

888 

889 result.concentration_results = conc_vals 

890 elem_value = owids['comp_elemscale'].GetValue() 

891 

892 scale = elem_value/conc_vals[cur_elem][0] 

893 result.concentration_scale = scale 

894 owids['comp_scale'].SetValue(scale) 

895 owids['composition'].DeleteAllItems() 

896 for elem, dat in conc_vals.items(): 

897 zat = "%d" % atomic_number(elem) 

898 val, serr = dat 

899 rval = "%15.4f" % val 

900 sval = "%15.4f" % (val*scale) 

901 uval = "%15.4f" % (serr*scale) 

902 try: 

903 uval = uval + ' ({:.2%})'.format(abs(serr/val)) 

904 except ZeroDivisionError: 

905 pass 

906 owids['composition'].AppendItem((zat, elem, rval, sval, uval)) 

907 

908 

909 def onCompSave(self, event=None): 

910 result = self.get_fitresult(nfit=self.owids['comp_fitlabel'].GetSelection()) 

911 scale = result.concentration_scale 

912 deffile = self.mca.label + '_' + result.label 

913 deffile = fix_filename(deffile.replace('.', '_')) + '_xrf.csv' 

914 wcards = "CSV (*.csv)|*.csv|All files (*.*)|*.*" 

915 sfile = FileSave(self, 'Save Concentration Results', 

916 default_file=deffile, 

917 wildcard=wcards) 

918 if sfile is not None: 

919 buff = ["# results for MCA labeled: %s" % self.mca.label, 

920 "# fit label: %s" % result.label, 

921 "# concentration units: %s" % self.owids['comp_units'].GetStringSelection(), 

922 "# count time: %s" % result.count_time, 

923 "# scale: %s" % result.concentration_scale, 

924 "# Fit Report:" ] 

925 for l in result.fit_report.split('\n'): 

926 buff.append("# %s" % l) 

927 buff.append("###########") 

928 buff.append("#Element Concentration Uncertainty Raw_Amplitude") 

929 for elem, dat in result.concentration_results.items(): 

930 eout = (elem + ' '*4)[:4] 

931 val, serr = dat 

932 rval = "%15.4f" % val 

933 sval = "%15.4f" % (val*scale) 

934 uval = "%15.4f" % (serr*scale) 

935 buff.append(" ".join([eout, sval, uval, rval])) 

936 buff.append('') 

937 with open(sfile, 'w', encoding=sys.getdefaultencoding()) as fh: 

938 fh.write('\n'.join(buff)) 

939 

940 def onCompSelectFit(self, event=None): 

941 result = self.get_fitresult(nfit=self.owids['comp_fitlabel'].GetSelection()) 

942 cur_elem = self.owids['comp_elemchoice'].GetStringSelection() 

943 self.owids['comp_elemchoice'].Clear() 

944 elems = [el['symbol'] for el in result.elements] 

945 self.owids['comp_elemchoice'].SetChoices(elems) 

946 if len(cur_elem) > 0: 

947 self.owids['comp_elemchoice'].SetStringSelection(cur_elem) 

948 else: 

949 self.owids['comp_elemchoice'].SetSelection(0) 

950 self.onCompSetElemAbundance() 

951 

952 def UpdateCompositionPage(self, event=None): 

953 self.xrfresults = self._larch.symtable.get_symbol(XRFRESULTS_GROUP) 

954 if len(self.xrfresults) > 0: 

955 result = self.get_fitresult() 

956 fitlab = self.owids['comp_fitlabel'] 

957 fitlab.Clear() 

958 fitlab.SetChoices([a.label for a in self.xrfresults]) 

959 fitlab.SetStringSelection(result.label) 

960 self.onCompSelectFit() 

961 

962 def onElems_Clear(self, event=None): 

963 self.ptable.on_clear_all() 

964 

965 def onElems_GuessPeaks(self, event=None): 

966 mca = self.mca 

967 _indices = peak.indexes(mca.counts*1.0, min_dist=5, thres=0.025) 

968 peak_energies = mca.energy[_indices] 

969 

970 elrange = range(10, 92) 

971 atsyms = [atomic_symbol(i) for i in elrange] 

972 kalphas = [0.001*xray_line(i, 'Ka').energy for i in elrange] 

973 kbetas = [0.001*xray_line(i, 'Kb').energy for i in elrange] 

974 self.ptable.on_clear_all() 

975 elems = [] 

976 for iz, en in enumerate(peak_energies): 

977 for i, ex in enumerate(kalphas): 

978 if abs(en - ex) < 0.025: 

979 elems.append(atsyms[i]) 

980 peak_energies[iz] = -ex 

981 

982 for iz, en in enumerate(peak_energies): 

983 if en > 0: 

984 for i, ex in enumerate(kbetas): 

985 if abs(en - ex) < 0.025: 

986 if atsyms[i] not in elems: 

987 elems.append(atsyms[i]) 

988 peak_energies[iz] = -ex 

989 

990 en = self.wids['en_xray'].GetValue() 

991 emin = self.wids['en_min'].GetValue() 

992 for elem in elems: 

993 kedge = 0.001*xray_edge(elem, 'K').energy 

994 l3edge = 0.001*xray_edge(elem, 'L3').energy 

995 l2edge = 0.001*xray_edge(elem, 'L3').energy 

996 if ((kedge < en and kedge > emin) or 

997 (l3edge < en and l3edge > emin) or 

998 (l2edge < en and l2edge > emin)): 

999 if elem not in self.ptable.selected: 

1000 self.ptable.onclick(label=elem) 

1001 

1002 def onElems_FromROIS(self, event=None): 

1003 for roi in self.mca.rois: 

1004 words = roi.name.split() 

1005 elem = words[0].title() 

1006 if (elem in self.ptable.syms and 

1007 elem not in self.ptable.selected): 

1008 self.ptable.onclick(label=elem) 

1009 self.onSetXrayEnergy() 

1010 

1011 def onSetXrayEnergy(self, event=None): 

1012 en = self.wids['en_xray'].GetValue() 

1013 self.wids['en_max'].SetValue(en) 

1014 self.wids['elastic_cen'].SetValue(en) 

1015 self.wids['compton1_cen'].SetValue(en*0.975) 

1016 self.wids['compton2_cen'].SetValue(en*0.950) 

1017 emin = self.wids['en_min'].GetValue() * 1.25 

1018 

1019 self.ptable.on_clear_all() 

1020 for roi in self.mca.rois: 

1021 words = roi.name.split() 

1022 elem = words[0].title() 

1023 kedge = l3edge = l2edge = 0.0 

1024 try: 

1025 kedge = 0.001*xray_edge(elem, 'K').energy 

1026 l3edge = 0.001*xray_edge(elem, 'L3').energy 

1027 l2edge = 0.001*xray_edge(elem, 'L3').energy 

1028 except: 

1029 pass 

1030 if ((kedge < en and kedge > emin) or 

1031 (l3edge < en and l3edge > emin) or 

1032 (l2edge < en and l2edge > emin)): 

1033 if elem not in self.ptable.selected: 

1034 self.ptable.onclick(label=elem) 

1035 

1036 def onDetMaterial(self, event=None): 

1037 dmat = self.wids['det_mat'].GetStringSelection() 

1038 if dmat not in FanoFactors: 

1039 dmat = 'Si' 

1040 self.wids['det_efano'].SetLabel('E_Fano= %.4e' % FanoFactors[dmat]) 

1041 

1042 def onFilterMaterial(self, evt=None, index=1): 

1043 name = evt.GetString() 

1044 den = self.materials_data.get(name, (None, 1.0))[1] 

1045 t = 'filter%d' % (index) 

1046 thick = self.wids['%s_thk'%t] 

1047 if den < 0.1 and thick.GetValue() < 0.1: 

1048 thick.SetValue(10.0) 

1049 thick.SetIncrement(0.5) 

1050 elif den > 0.1 and thick.GetValue() < 1.e-5: 

1051 thick.SetValue(0.0250) 

1052 thick.SetIncrement(0.005) 

1053 

1054 def onUseCurrentMaterialAsFilter(self, evt=None): 

1055 name = self.selected_material 

1056 density = self.materials_data.get(name, (None, 1.0))[1] 

1057 self.wids['matrix_den'].SetValue(density) 

1058 self.wids['matrix_mat'].SetValue(name) 

1059 

1060 def onSelectMaterial(self, evt=None): 

1061 if self.owids['materials'] is None: 

1062 return 

1063 item = self.owids['materials'].GetSelectedRow() 

1064 name = None 

1065 if item > -1: 

1066 name = list(self.materials_data.keys())[item] 

1067 self.selected_material = name 

1068 

1069 self.wids['matrix_btn'].Enable(name is not None) 

1070 if name is not None: 

1071 self.wids['matrix_btn'].SetLabel('Use %s' % name) 

1072 

1073 def onUpdateFilterList(self, evt=None): 

1074 flist = ['None'] 

1075 for i in range(len(self.materials_data)): 

1076 if self.owids['materials'].GetToggleValue(i, 3): # is filter 

1077 flist.append(self.owids['materials'].GetTextValue(i, 0)) 

1078 

1079 for i in range(NFILTERS): 

1080 t = 'filter%d' % (i+1) 

1081 choice = self.wids['%s_mat'%t] 

1082 cur = choice.GetStringSelection() 

1083 choice.Clear() 

1084 choice.SetChoices(flist) 

1085 if cur in flist: 

1086 choice.SetStringSelection(cur) 

1087 else: 

1088 choice.SetSelection(0) 

1089 

1090 def onAddMaterial(self, evt=None): 

1091 name = self.owids['newmat_name'].GetValue() 

1092 formula = self.owids['newmat_form'].GetValue() 

1093 density = self.owids['newmat_dens'].GetValue() 

1094 add = len(name) > 0 and len(formula)>0 

1095 if add and name in self.materials_data: 

1096 add = (Popup(self, 

1097 "Overwrite definition of '%s'?" % name, 

1098 'Re-define material?', 

1099 style=wx.OK|wx.CANCEL)==wx.ID_OK) 

1100 if add: 

1101 irow = list(self.materials_data.keys()).index(name) 

1102 self.owids['materials'].DeleteItem(irow) 

1103 if add: 

1104 add_material(name, formula, density) 

1105 self.materials_data[name] = (formula, density) 

1106 self.selected_material = name 

1107 self.owids['materials'].AppendItem((name, formula, 

1108 "%9.6f"%density, 

1109 False)) 

1110 

1111 def onElemSelect(self, event=None, elem=None): 

1112 self.ptable.tsym.SetLabel('') 

1113 self.ptable.title.SetLabel('%d elements selected' % 

1114 len(self.ptable.selected)) 

1115 

1116 def onUsePileupEscape(self, event=None): 

1117 puse = self.wids['pileup_use'].IsChecked() 

1118 self.wids['pileup_amp'].Enable(puse) 

1119 self.wids['pileup_amp_vary'].Enable(puse) 

1120 

1121 puse = self.wids['escape_use'].IsChecked() 

1122 self.wids['escape_amp'].Enable(puse) 

1123 self.wids['escape_amp_vary'].Enable(puse) 

1124 

1125 

1126 def onUsePeak(self, event=None, name=None, value=None): 

1127 if value is None and event is not None: 

1128 value = event.IsChecked() 

1129 if name is None: 

1130 return 

1131 for a in ('cen', 'step', 'tail', 'sigma', 'beta'): 

1132 self.wids['%s_%s'%(name, a)].Enable(value) 

1133 varwid = self.wids.get('%s_%s_vary'%(name, a), None) 

1134 if varwid is not None: 

1135 varwid.Enable(value) 

1136 

1137 def build_model(self, match_amplitudes=True): 

1138 """build xrf_model from form settings""" 

1139 vars = {'Vary':'True', 'Fix': 'False', 'True':True, 'False': False} 

1140 opts = {} 

1141 for key, wid in self.wids.items(): 

1142 val = None 

1143 if hasattr(wid, 'GetValue'): 

1144 val = wid.GetValue() 

1145 elif hasattr(wid, 'IsChecked'): 

1146 val = wid.IsChecked() 

1147 elif isinstance(wid, Choice): 

1148 val = wid.GetStringSelection() 

1149 elif hasattr(wid, 'GetStringSelection'): 

1150 val = wid.GetStringSelection() 

1151 elif hasattr(wid, 'GetLabel'): 

1152 val = wid.GetLabel() 

1153 if isinstance(val, str) and val.title() in vars: 

1154 val = vars[val.title()] 

1155 opts[key] = val 

1156 opts['count_time'] = getattr(self.mca, 'real_time', 1.0) 

1157 if opts['count_time'] is None: 

1158 opts['count_time'] = 1.0 

1159 opts['datetime'] = time.ctime() 

1160 opts['mca_label'] = self.mca_label 

1161 opts['mcagroup'] = self.mcagroup 

1162 opts['XRFGROUP'] = XRFGROUP 

1163 script = [xrfmod_setup.format(**opts)] 

1164 

1165 for peakname in ('Elastic', 'Compton1', 'Compton2'): 

1166 t = peakname.lower() 

1167 if opts['%s_use'% t]: 

1168 d = {'peakname': t} 

1169 d['_cen'] = opts['%s_cen'%t] 

1170 d['vcen'] = opts['%s_cen_vary'%t] 

1171 d['_step'] = opts['%s_step'%t] 

1172 d['vstep'] = opts['%s_step_vary'%t] 

1173 d['_tail'] = opts['%s_tail'%t] 

1174 d['vtail'] = opts['%s_tail_vary'%t] 

1175 d['_beta'] = opts['%s_beta'%t] 

1176 d['vbeta'] = opts['%s_beta_vary'%t] 

1177 d['_sigma'] = opts['%s_sigma'%t] 

1178 d['vsigma'] = opts['%s_sigma_vary'%t] 

1179 script.append(xrfmod_scattpeak.format(**d)) 

1180 

1181 for i in range(NFILTERS): 

1182 t = 'filter%d' % (i+1) 

1183 f_mat = opts['%s_mat'%t] 

1184 if f_mat not in (None, 'None') and int(1e6*opts['%s_thk'%t]) > 1: 

1185 script.append(xrfmod_filter.format(name=f_mat, 

1186 thick=opts['%s_thk'%t], 

1187 vary=opts['%s_var'%t])) 

1188 

1189 m_mat = opts['matrix_mat'].strip() 

1190 if len(m_mat) > 0 and int(1e6*opts['matrix_thk']) > 1: 

1191 script.append(xrfmod_matrix.format(name=m_mat, 

1192 thick=opts['matrix_thk'], 

1193 density=opts['matrix_den'])) 

1194 

1195 if opts['pileup_use'] in ('True', True): 

1196 script.append(xrfmod_pileup.format(scale=opts['pileup_amp'], 

1197 vary=opts['pileup_amp_vary'])) 

1198 

1199 if opts['escape_use'] in ('True', True): 

1200 script.append(xrfmod_escape.format(scale=opts['escape_amp'], 

1201 vary=opts['escape_amp_vary'])) 

1202 

1203 # sort elements selected on Periodic Table by Z 

1204 elemz = [] 

1205 for elem in self.ptable.selected: 

1206 elemz.append( 1 + self.ptable.syms.index(elem)) 

1207 elemz.sort() 

1208 opts['elements'] = elemz 

1209 

1210 xrfgroup = self._larch.symtable.get_group(XRFGROUP) 

1211 setattr(xrfgroup, 'fitconfig', opts) 

1212 json_dump(opts, os.path.join(user_larchdir, 'xrf_fitconfig.json')) 

1213 

1214 

1215 syms = ["'%s'" % self.ptable.syms[iz-1] for iz in elemz] 

1216 syms = '[%s]' % (', '.join(syms)) 

1217 script.append(xrfmod_elems.format(elemlist=syms)) 

1218 

1219 script.append("# set initial estimate of xrf intensity") 

1220 script.append("{XRFGROUP}.workmca.xrf_init = _xrfmodel.calc_spectrum({XRFGROUP}.workmca.energy)") 

1221 script = '\n'.join(script) 

1222 self.model_script = script.format(group=self.mcagroup, XRFGROUP=XRFGROUP) 

1223 

1224 self._larch.eval(self.model_script) 

1225 

1226 cmds = [] 

1227 self._larch.symtable.get_symbol('_xrfmodel') 

1228 self.xrfmod = self._larch.symtable.get_symbol('_xrfmodel') 

1229 floor = 1.e-12*max(self.mca.counts) 

1230 if match_amplitudes: 

1231 total = 0.0 * self.mca.counts 

1232 for name, parr in self.xrfmod.comps.items(): 

1233 nam = name.lower() 

1234 try: 

1235 imax = np.where(parr > 0.99*parr.max())[0][0] 

1236 except: # probably means all counts are zero 

1237 imax = int(len(parr)/2.0) 

1238 scale = self.mca.counts[imax] / (parr[imax]+1.00) 

1239 ampname = 'amp_%s' % nam 

1240 if nam in ('elastic', 'compton1', 'compton2', 'compton', 

1241 'background', 'pileup', 'escape'): 

1242 ampname = f'{nam}_amp' 

1243 if nam in ('background', 'pileup', 'escape'): 

1244 scale = 1.0 

1245 if nam in ('compton2',): 

1246 scale /= 5.0 

1247 

1248 paramval = self.xrfmod.params[ampname].value 

1249 s = f"_xrfmodel.params['{ampname}'].value = {paramval*scale:.5f}" 

1250 cmds.append(s) 

1251 parr *= scale 

1252 parr[np.where(parr<floor)] = floor 

1253 total += parr 

1254 self.xrfmod.current_model = total 

1255 script = '\n'.join(cmds) 

1256 self._larch.eval(script) 

1257 self.model_script = f"{self.model_script}\n{script}" 

1258 

1259 s = f"{XRFGROUP}.workmca.xrf_init = _xrfmodel.calc_spectrum({XRFGROUP}.workmca.energy)" 

1260 self._larch.eval(s) 

1261 

1262 def plot_model(self, model_spectrum=None, init=False, with_comps=False, 

1263 label=None): 

1264 conf = self.parent.conf 

1265 

1266 plotkws = {'linewidth': 2.5, 'delay_draw': True, 'grid': False, 

1267 'ylog_scale': self.parent.ylog_scale, 'show_legend': False, 

1268 'fullbox': False} 

1269 

1270 ppanel = self.parent.panel 

1271 ppanel.conf.reset_trace_properties() 

1272 self.parent.plot(self.mca.energy, self.mca.counts, mca=self.mca, 

1273 xlabel='E (keV)', xmin=0, with_rois=False, **plotkws) 

1274 

1275 if model_spectrum is None: 

1276 model_spectrum = self.xrfmod.current_model if init else self.xrfmod.best_fit 

1277 if label is None: 

1278 label = 'model' if init else 'best fit' 

1279 

1280 self.parent.oplot(self.mca.energy, model_spectrum, 

1281 label=label, color=conf.fit_color, **plotkws) 

1282 

1283 comp_traces = [] 

1284 plotkws.update({'fill': True, 'alpha':0.35, 'show_legend': True}) 

1285 for label, arr in self.xrfmod.comps.items(): 

1286 ppanel.oplot(self.mca.energy, arr, label=label, **plotkws) 

1287 comp_traces.append(ppanel.conf.ntrace - 1) 

1288 

1289 

1290 yscale = {False:'linear', True:'log'}[self.parent.ylog_scale] 

1291 ppanel.set_logscale(yscale=yscale) 

1292 ppanel.set_viewlimits() 

1293 ppanel.conf.auto_margins = False 

1294 ppanel.conf.set_margins(0.1, 0.02, 0.20, 0.1) 

1295 ppanel.conf.set_legend_location('upper right', False) 

1296 ppanel.conf.show_legend_frame = True 

1297 ppanel.conf.draw_legend(show=True, delay_draw=False) 

1298 

1299 if not with_comps: 

1300 for obj, data in ppanel.conf.legend_map.items(): 

1301 line, trace, legline, legtext = data 

1302 if trace in comp_traces: 

1303 legline.set_alpha(0.50) 

1304 legtext.set_alpha(0.50) 

1305 line.set_visible(False) 

1306 ppanel.conf.fills[trace].set_visible(False) 

1307 ppanel.draw() 

1308 

1309 def onShowModel(self, event=None): 

1310 self.build_model() 

1311 self.plot_model(init=True, with_comps=False) 

1312 

1313 def onFitIteration(self, iter=0, pars=None): 

1314 print("XRF Fit iteration %d" % iter) 

1315 # self.wids['fit_message'].SetLabel("Fit iteration %d" % iter) 

1316 

1317 def onFitModel(self, event=None): 

1318 self.build_model() 

1319 xrfmod = self._larch.symtable.get_symbol('_xrfmodel') 

1320 xrfmod.iter_callback = self.onFitIteration 

1321 

1322 fit_tol = float(self.wids['fit_toler'].GetStringSelection()) 

1323 fit_step = float(self.wids['fit_step'].GetStringSelection()) 

1324 max_nfev = int(self.wids['fit_maxnfev'].GetStringSelection()) 

1325 emin = float(self.wids['en_min'].GetValue()) 

1326 emax = float(self.wids['en_max'].GetValue()) 

1327 

1328 fit_script = xrfmod_fitscript.format(group=self.mcagroup, 

1329 XRFGROUP=XRFGROUP, 

1330 emin=emin, emax=emax, 

1331 fit_toler=fit_tol, 

1332 fit_step=fit_step, 

1333 max_nfev=max_nfev) 

1334 # print("-- > ", fit_script) 

1335 

1336 self._larch.eval(fit_script) 

1337 dgroup = self._larch.symtable.get_group(self.mcagroup) 

1338 self.xrfresults = self._larch.symtable.get_symbol(XRFRESULTS_GROUP) 

1339 

1340 xrfresult = self.xrfresults[0] 

1341 xrfresult.script = "%s\n%s" % (self.model_script, fit_script) 

1342 xrfresult.label = "fit %d" % (len(self.xrfresults)) 

1343 self.plot_model(init=True, with_comps=False) 

1344 for i in range(len(self.nb.pagelist)): 

1345 if self.nb.GetPageText(i).strip().startswith('Fit R'): 

1346 self.nb.SetSelection(i) 

1347 time.sleep(0.002) 

1348 self.show_results() 

1349 

1350 def onClose(self, event=None): 

1351 self.Destroy() 

1352 

1353 def onSaveFitResult(self, event=None): 

1354 result = self.get_fitresult() 

1355 deffile = self.mca.label + '_' + result.label 

1356 deffile = fix_filename(deffile.replace('.', '_')) + '.xrfmodel' 

1357 ModelWcards = "XRF Models(*.xrfmodel)|*.xrfmodel|All files (*.*)|*.*" 

1358 sfile = FileSave(self, 'Save XRF Model', default_file=deffile, 

1359 wildcard=ModelWcards) 

1360 if sfile is not None: 

1361 self._larch.eval(xrfmod_savejs.format(group=self.mcagroup, 

1362 nfit=self.nfit, 

1363 filename=sfile)) 

1364 

1365 def onExportFitResult(self, event=None): 

1366 result = self.get_fitresult() 

1367 deffile = self.mca.label + '_' + result.label 

1368 deffile = fix_filename(deffile.replace('.', '_')) + '_xrf.txt' 

1369 wcards = 'All files (*.*)|*.*' 

1370 outfile = FileSave(self, 'Export Fit Result', default_file=deffile) 

1371 if outfile is not None: 

1372 buff = ['# XRF Fit %s: %s' % (self.mca.label, result.label), 

1373 '## Fit Script:'] 

1374 for a in result.script.split('\n'): 

1375 buff.append('# %s' % a) 

1376 buff.append('## Fit Report:') 

1377 for a in result.fit_report.split('\n'): 

1378 buff.append('# %s' % a) 

1379 

1380 buff.append('#') 

1381 buff.append('########################################') 

1382 

1383 labels = ['energy', 'counts', 'best_fit', 

1384 'best_energy', 'fit_window', 

1385 'fit_weight', 'attenuation'] 

1386 labels.extend(list(result.comps.keys())) 

1387 

1388 buff.append('# %s' % (' '.join(labels))) 

1389 

1390 npts = len(self.mca.energy) 

1391 for i in range(npts): 

1392 dline = [gformat(self.mca.energy[i]), 

1393 gformat(self.mca.counts[i]), 

1394 gformat(result.best_fit[i]), 

1395 gformat(result.best_en[i]), 

1396 gformat(result.fit_window[i]), 

1397 gformat(result.fit_weight[i]), 

1398 gformat(result.atten[i])] 

1399 for c in result.comps.values(): 

1400 dline.append(gformat(c[i])) 

1401 buff.append(' '.join(dline)) 

1402 buff.append('\n') 

1403 with open(outfile, 'w', encoding=sys.getdefaultencoding()) as fh: 

1404 fh.write('\n'.join(buff)) 

1405 

1406 def get_fitresult(self, nfit=None): 

1407 if nfit is None: 

1408 nfit = self.nfit 

1409 

1410 self.xrfresults = self._larch.symtable.get_symbol(XRFRESULTS_GROUP) 

1411 self.nfit = max(0, nfit) 

1412 self.nfit = min(self.nfit, len(self.xrfresults)-1) 

1413 return self.xrfresults[self.nfit] 

1414 

1415 def onChangeFitLabel(self, event=None): 

1416 label = self.owids['fitlabel_txt'].GetValue() 

1417 result = self.get_fitresult() 

1418 result.label = label 

1419 self.show_results() 

1420 

1421 def onPlot(self, event=None): 

1422 result = self.get_fitresult() 

1423 xrfmod = self._larch.symtable.get_symbol('_xrfmodel') 

1424 with_comps = self.owids['plot_comps'].IsChecked() 

1425 spect = xrfmod.calc_spectrum(self.mca.energy, 

1426 params=result.params) 

1427 self.plot_model(model_spectrum=spect, with_comps=with_comps, 

1428 label=result.label) 

1429 

1430 def onSelectFit(self, evt=None): 

1431 if self.owids['stats'] is None: 

1432 return 

1433 item = self.owids['stats'].GetSelectedRow() 

1434 if item > -1: 

1435 self.show_fitresult(nfit=item) 

1436 

1437 def onSelectParameter(self, evt=None): 

1438 if self.owids['params'] is None: 

1439 return 

1440 if not self.owids['params'].HasSelection(): 

1441 return 

1442 item = self.owids['params'].GetSelectedRow() 

1443 pname = self.owids['paramsdata'][item] 

1444 

1445 cormin= self.owids['min_correl'].GetValue() 

1446 self.owids['correl'].DeleteAllItems() 

1447 

1448 result = self.get_fitresult() 

1449 this = result.params[pname] 

1450 if this.correl is not None: 

1451 sort_correl = sorted(this.correl.items(), key=lambda it: abs(it[1])) 

1452 for name, corval in reversed(sort_correl): 

1453 if abs(corval) > cormin: 

1454 self.owids['correl'].AppendItem((pname, name, "% .4f" % corval)) 

1455 

1456 def onAllCorrel(self, evt=None): 

1457 result = self.get_fitresult() 

1458 params = result.params 

1459 parnames = list(params.keys()) 

1460 

1461 cormin= self.owids['min_correl'].GetValue() 

1462 correls = {} 

1463 for i, name in enumerate(parnames): 

1464 par = params[name] 

1465 if not par.vary: 

1466 continue 

1467 if hasattr(par, 'correl') and par.correl is not None: 

1468 for name2 in parnames[i+1:]: 

1469 if (name != name2 and name2 in par.correl and 

1470 abs(par.correl[name2]) > cormin): 

1471 correls["%s$$%s" % (name, name2)] = par.correl[name2] 

1472 

1473 sort_correl = sorted(correls.items(), key=lambda it: abs(it[1])) 

1474 sort_correl.reverse() 

1475 

1476 self.owids['correl'].DeleteAllItems() 

1477 

1478 for namepair, corval in sort_correl: 

1479 name1, name2 = namepair.split('$$') 

1480 self.owids['correl'].AppendItem((name1, name2, "% .4f" % corval)) 

1481 

1482 def show_results(self): 

1483 cur = self.get_fitresult() 

1484 self.owids['stats'].DeleteAllItems() 

1485 for i, res in enumerate(self.xrfresults): 

1486 args = [res.label] 

1487 for attr in ('nvarys', 'nfev', 'chisqr', 'redchi', 'aic'): 

1488 val = getattr(res, attr) 

1489 if isinstance(val, int): 

1490 val = '%d' % val 

1491 else: 

1492 val = gformat(val, 11) 

1493 args.append(val) 

1494 self.owids['stats'].AppendItem(tuple(args)) 

1495 self.owids['data_title'].SetLabel("%s: %.3f sec" % (self.mca.label, cur.count_time)) 

1496 self.owids['data_title2'].SetLabel("%s: %.3f sec" % (self.mca.label, cur.count_time)) 

1497 self.owids['fitlabel_txt'].SetValue(cur.label) 

1498 self.show_fitresult(nfit=self.nfit) 

1499 

1500 def show_fitresult(self, nfit=0, mca=None): 

1501 if mca is not None: 

1502 self.mca = mca 

1503 result = self.get_fitresult(nfit=nfit) 

1504 

1505 self.owids['data_title'].SetLabel("%s: %.3f sec" % (self.mca.label, result.count_time)) 

1506 self.owids['data_title2'].SetLabel("%s: %.3f sec" % (self.mca.label, result.count_time)) 

1507 self.result = result 

1508 self.owids['fitlabel_txt'].SetValue(result.label) 

1509 self.owids['params'].DeleteAllItems() 

1510 self.owids['paramsdata'] = [] 

1511 for param in reversed(result.params.values()): 

1512 pname = param.name 

1513 try: 

1514 val = gformat(param.value, 10) 

1515 except (TypeError, ValueError): 

1516 val = ' ??? ' 

1517 serr, perr = ' N/A ', ' N/A ' 

1518 if param.stderr is not None: 

1519 serr = gformat(param.stderr, 10) 

1520 try: 

1521 perr = '{:.3f}'.format(100.0*abs(param.stderr/param.value)) 

1522 except ZeroDivisionError: 

1523 perr = '?' 

1524 extra = ' ' 

1525 if param.expr is not None: 

1526 extra = ' = %s ' % param.expr 

1527 elif not param.vary: 

1528 extra = ' (fixed)' 

1529 elif param.init_value is not None: 

1530 extra = gformat(param.init_value, 10) 

1531 

1532 self.owids['params'].AppendItem((pname, val, serr, perr, extra)) 

1533 self.owids['paramsdata'].append(pname) 

1534 self.Refresh()