pyTEMlib 0.2024.2.2__py2.py3-none-any.whl → 0.2024.8.4__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of pyTEMlib might be problematic. Click here for more details.
- pyTEMlib/core_loss_widget.py +658 -0
- pyTEMlib/eds_tools.py +218 -167
- pyTEMlib/eels_dialog.py +13 -12
- pyTEMlib/eels_dialog_utilities.py +2 -3
- pyTEMlib/eels_tools.py +56 -71
- pyTEMlib/file_tools.py +7 -1
- pyTEMlib/image_tools.py +103 -27
- pyTEMlib/info_widget.py +301 -365
- pyTEMlib/low_loss_widget.py +176 -0
- pyTEMlib/version.py +2 -2
- pyTEMlib/xrpa_x_sections.py +140 -54
- {pyTEMlib-0.2024.2.2.dist-info → pyTEMlib-0.2024.8.4.dist-info}/METADATA +2 -3
- {pyTEMlib-0.2024.2.2.dist-info → pyTEMlib-0.2024.8.4.dist-info}/RECORD +17 -15
- {pyTEMlib-0.2024.2.2.dist-info → pyTEMlib-0.2024.8.4.dist-info}/WHEEL +1 -1
- {pyTEMlib-0.2024.2.2.dist-info → pyTEMlib-0.2024.8.4.dist-info}/entry_points.txt +0 -1
- {pyTEMlib-0.2024.2.2.dist-info → pyTEMlib-0.2024.8.4.dist-info}/LICENSE +0 -0
- {pyTEMlib-0.2024.2.2.dist-info → pyTEMlib-0.2024.8.4.dist-info}/top_level.txt +0 -0
pyTEMlib/eds_tools.py
CHANGED
|
@@ -56,7 +56,6 @@ shell_occupancy = {'K1': 2, 'L1': 2, 'L2': 2, 'L3': 4, 'M1': 2, 'M2': 2, 'M3': 4
|
|
|
56
56
|
def detector_response(dataset):
|
|
57
57
|
tags = dataset.metadata['experiment']
|
|
58
58
|
|
|
59
|
-
tags['acceleration_voltage_V'] = tags['microscope']['acceleration_voltage_V']
|
|
60
59
|
energy_scale = dataset.get_spectral_dims(return_axis=True)[0]
|
|
61
60
|
if 'start_channel' not in tags['detector']:
|
|
62
61
|
tags['detector']['start_channel'] = np.searchsorted(energy_scale, 100)
|
|
@@ -88,7 +87,7 @@ def get_detector_response(detector_definition, energy_scale):
|
|
|
88
87
|
-------
|
|
89
88
|
|
|
90
89
|
tags ={}
|
|
91
|
-
tags['
|
|
90
|
+
tags['acceleration_voltage'] = 200000
|
|
92
91
|
|
|
93
92
|
tags['detector'] ={}
|
|
94
93
|
|
|
@@ -182,19 +181,13 @@ def find_elements(spectrum, minor_peaks):
|
|
|
182
181
|
found = False
|
|
183
182
|
for element in range(3,82):
|
|
184
183
|
if 'lines' in x_sections[str(element)]:
|
|
185
|
-
if 'K-
|
|
186
|
-
if abs(x_sections[str(element)]['lines']['K-
|
|
184
|
+
if 'K-L2' in x_sections[str(element)]['lines']:
|
|
185
|
+
if abs(x_sections[str(element)]['lines']['K-L2']['position']- energy_scale[peak]) <10:
|
|
187
186
|
found = True
|
|
188
187
|
if x_sections[str(element)]['name'] not in elements:
|
|
189
188
|
elements.append( x_sections[str(element)]['name'])
|
|
190
189
|
if not found:
|
|
191
|
-
if '
|
|
192
|
-
if abs(x_sections[str(element)]['lines']['K-L2']['position']- energy_scale[peak]) <10:
|
|
193
|
-
found = True
|
|
194
|
-
if x_sections[str(element)]['name'] not in elements:
|
|
195
|
-
elements.append( x_sections[str(element)]['name'])
|
|
196
|
-
if not found:
|
|
197
|
-
if 'L3-M5' in x_sections[str(element)]['lines']:
|
|
190
|
+
if 'L3-M3' in x_sections[str(element)]['lines']:
|
|
198
191
|
if abs(x_sections[str(element)]['lines']['L3-M5']['position']- energy_scale[peak]) <30:
|
|
199
192
|
if x_sections[str(element)]['name'] not in elements:
|
|
200
193
|
elements.append( x_sections[str(element)]['name'])
|
|
@@ -212,87 +205,71 @@ def get_x_ray_lines(spectrum, elements):
|
|
|
212
205
|
# omega_K = Z**4/(alpha_K+Z**4)
|
|
213
206
|
# omega_L = Z**4/(alpha_L+Z**4)
|
|
214
207
|
# omega_M = Z**4/(alpha_M+Z**4)
|
|
215
|
-
energy_scale = spectrum.get_spectral_dims(return_axis=True)[0]
|
|
208
|
+
energy_scale = np.array(spectrum.get_spectral_dims(return_axis=True)[0].values)
|
|
216
209
|
for element in elements:
|
|
217
|
-
atomic_number = elements_list.index(element)
|
|
210
|
+
atomic_number = pyTEMlib.eds_tools.elements_list.index(element)
|
|
218
211
|
out_tags[element] ={'Z': atomic_number}
|
|
212
|
+
lines = x_sections[str(atomic_number)]['lines']
|
|
213
|
+
K_weight = 0
|
|
214
|
+
K_main = 'None'
|
|
215
|
+
K_lines = []
|
|
216
|
+
L_weight = 0
|
|
217
|
+
L_main = 'None'
|
|
218
|
+
L_lines = []
|
|
219
|
+
M_weight = 0
|
|
220
|
+
M_main = 'None'
|
|
221
|
+
M_lines = []
|
|
222
|
+
|
|
223
|
+
for key, line in lines.items():
|
|
224
|
+
if 'K' == key[0]:
|
|
225
|
+
if line['position'] < energy_scale[-1]:
|
|
226
|
+
K_lines.append(key)
|
|
227
|
+
if line['weight'] > K_weight:
|
|
228
|
+
K_weight = line['weight']
|
|
229
|
+
K_main = key
|
|
230
|
+
if 'L' == key[0]:
|
|
231
|
+
if line['position'] < energy_scale[-1]:
|
|
232
|
+
L_lines.append(key)
|
|
233
|
+
if line['weight'] > L_weight:
|
|
234
|
+
L_weight = line['weight']
|
|
235
|
+
L_main = key
|
|
236
|
+
if 'M' == key[0]:
|
|
237
|
+
if line['position'] < energy_scale[-1]:
|
|
238
|
+
M_lines.append(key)
|
|
239
|
+
if line['weight'] > M_weight:
|
|
240
|
+
M_weight = line['weight']
|
|
241
|
+
M_main = key
|
|
242
|
+
|
|
243
|
+
if K_weight > 0:
|
|
244
|
+
out_tags[element]['K-family'] = {'main': K_main, 'weight': K_weight, 'lines': K_lines}
|
|
245
|
+
height = spectrum[np.searchsorted(energy_scale, x_sections[str(atomic_number)]['lines'][K_main]['position'] )].compute()
|
|
246
|
+
out_tags[element]['K-family']['height'] = height/K_weight
|
|
247
|
+
for key in K_lines:
|
|
248
|
+
out_tags[element]['K-family'][key] = x_sections[str(atomic_number)]['lines'][key]
|
|
249
|
+
if L_weight > 0:
|
|
250
|
+
out_tags[element]['L-family'] = {'main': L_main, 'weight': L_weight, 'lines': L_lines}
|
|
251
|
+
height = spectrum[np.searchsorted(energy_scale, x_sections[str(atomic_number)]['lines'][L_main]['position'] )].compute()
|
|
252
|
+
out_tags[element]['L-family']['height'] = height/L_weight
|
|
253
|
+
for key in L_lines:
|
|
254
|
+
out_tags[element]['L-family'][key] = x_sections[str(atomic_number)]['lines'][key]
|
|
255
|
+
if M_weight > 0:
|
|
256
|
+
out_tags[element]['M-family'] = {'main': M_main, 'weight': M_weight, 'lines': M_lines}
|
|
257
|
+
height = spectrum[np.searchsorted(energy_scale, x_sections[str(atomic_number)]['lines'][M_main]['position'] )].compute()
|
|
258
|
+
out_tags[element]['M-family']['height'] = height/M_weight
|
|
259
|
+
for key in M_lines:
|
|
260
|
+
out_tags[element]['M-family'][key] = x_sections[str(atomic_number)]['lines'][key]
|
|
219
261
|
|
|
220
|
-
if 'K-L3' in x_sections[str(atomic_number)]['lines']:
|
|
221
|
-
if x_sections[str(atomic_number)]['lines']['K-L3']['position'] < energy_scale[-1]:
|
|
222
|
-
height = spectrum[np.searchsorted(energy_scale, x_sections[str(atomic_number)]['lines']['K-L3']['position'] )].compute()
|
|
223
|
-
out_tags[element]['K-family'] = {'height': height}
|
|
224
|
-
if 'K' in x_sections[str(atomic_number)]['fluorescent_yield']:
|
|
225
|
-
out_tags[element]['K-family']['yield'] = x_sections[str(atomic_number)]['fluorescent_yield']['K']
|
|
226
|
-
else:
|
|
227
|
-
out_tags[element]['K-family']['yield'] = atomic_number**4/(alpha_K+atomic_number**4)/4/1.4
|
|
228
|
-
|
|
229
|
-
if 'L3-M5' in x_sections[str(atomic_number)]['lines']:
|
|
230
|
-
if x_sections[str(atomic_number)]['lines']['L3-M5']['position'] < energy_scale[-1]:
|
|
231
|
-
height = spectrum[np.searchsorted(energy_scale, x_sections[str(atomic_number)]['lines']['L3-M5']['position'] )].compute()
|
|
232
|
-
out_tags[element]['L-family'] = {'height': height}
|
|
233
|
-
if 'L' in x_sections[str(atomic_number)]['fluorescent_yield']:
|
|
234
|
-
out_tags[element]['L-family']['yield'] = x_sections[str(atomic_number)]['fluorescent_yield']['L']
|
|
235
|
-
else:
|
|
236
|
-
out_tags[element]['L-family']['yield'] = (atomic_number**4/(alpha_L+atomic_number**4))**2
|
|
237
|
-
|
|
238
|
-
if 'M5-N6' in x_sections[str(atomic_number)]['lines']:
|
|
239
|
-
if x_sections[str(atomic_number)]['lines']['M5-N6']['position'] < energy_scale[-1]:
|
|
240
|
-
height = spectrum[np.searchsorted(energy_scale, x_sections[str(atomic_number)]['lines']['M5-N6']['position'] )].compute()
|
|
241
|
-
out_tags[element]['M-family'] = {'height': height}
|
|
242
|
-
if 'M' in x_sections[str(atomic_number)]['fluorescent_yield']:
|
|
243
|
-
out_tags[element]['M-family']['yield'] = x_sections[str(atomic_number)]['fluorescent_yield']['M']
|
|
244
|
-
else:
|
|
245
|
-
out_tags[element]['M-family']['yield'] = (atomic_number**4/(alpha_M+atomic_number**4))**2
|
|
246
|
-
|
|
247
|
-
for key, line in x_sections[str(atomic_number)]['lines'].items():
|
|
248
|
-
other = True
|
|
249
|
-
if line['weight'] > 0.01 and line['position'] < 3e4:
|
|
250
|
-
if 'K-family' in out_tags[element]:
|
|
251
|
-
if key[0] == 'K':
|
|
252
|
-
other = False
|
|
253
|
-
out_tags[element]['K-family'][key]=line
|
|
254
|
-
if 'L-family' in out_tags[element]:
|
|
255
|
-
if key[:2] in ['L2', 'L3']:
|
|
256
|
-
other = False
|
|
257
|
-
out_tags[element]['L-family'][key]=line
|
|
258
|
-
if 'M-family' in out_tags[element]:
|
|
259
|
-
if key[:2] in ['M5', 'M4']:
|
|
260
|
-
other = False
|
|
261
|
-
out_tags[element]['M-family'][key]=line
|
|
262
|
-
if other:
|
|
263
|
-
if 'other' not in out_tags[element]:
|
|
264
|
-
out_tags[element]['other'] = {}
|
|
265
|
-
height = spectrum[np.searchsorted(energy_scale, x_sections[str(atomic_number)]['lines'][key]['position'] )].compute()
|
|
266
|
-
out_tags[element]['other'][key]=line
|
|
267
|
-
out_tags[element]['other'][key]['height'] = height
|
|
268
|
-
|
|
269
262
|
xs = get_eds_cross_sections(atomic_number)
|
|
270
263
|
if 'K' in xs and 'K-family' in out_tags[element]:
|
|
271
|
-
out_tags[element]['K-family']['
|
|
264
|
+
out_tags[element]['K-family']['probability'] = xs['K']
|
|
272
265
|
if 'L' in xs and 'L-family' in out_tags[element]:
|
|
273
|
-
out_tags[element]['L-family']['
|
|
266
|
+
out_tags[element]['L-family']['probability'] = xs['L']
|
|
274
267
|
if 'M' in xs and 'M-family' in out_tags[element]:
|
|
275
|
-
out_tags[element]['M-family']['
|
|
268
|
+
out_tags[element]['M-family']['probability'] = xs['M']
|
|
276
269
|
|
|
277
|
-
"""
|
|
278
|
-
We really should use the sum of the family
|
|
279
|
-
for key, x_lines in out_tags.items():
|
|
280
|
-
if 'K-family' in x_lines:
|
|
281
|
-
xs = pyTEMlib.eels_tools.xsec_xrpa(np.arange(100)+x_sections[str(x_lines['Z'])]['K1']['onset'], 200,x_lines['Z'], 100).sum()
|
|
282
|
-
|
|
283
|
-
x_lines['K-family']['ionization_x_section'] = xs
|
|
284
|
-
|
|
285
|
-
if 'L-family' in x_lines:
|
|
286
|
-
xs = pyTEMlib.eels_tools.xsec_xrpa(np.arange(100)+x_sections[str(x_lines['Z'])]['L3']['onset'], 200,x_lines['Z'], 100).sum()
|
|
287
|
-
x_lines['L-family']['ionization_x_section'] = xs
|
|
288
|
-
if 'M-family' in x_lines:
|
|
289
|
-
xs = pyTEMlib.eels_tools.xsec_xrpa(np.arange(100)+x_sections[str(x_lines['Z'])]['M5']['onset'], 200,x_lines['Z'], 100).sum()
|
|
290
|
-
x_lines['M-family']['ionization_x_section'] = xs
|
|
291
|
-
"""
|
|
292
270
|
if 'EDS' not in spectrum.metadata:
|
|
293
271
|
spectrum.metadata['EDS'] = {}
|
|
294
|
-
|
|
295
|
-
spectrum.metadata['EDS']['lines'] = out_tags
|
|
272
|
+
spectrum.metadata['EDS'].update(out_tags)
|
|
296
273
|
return out_tags
|
|
297
274
|
|
|
298
275
|
|
|
@@ -313,7 +290,7 @@ def get_peak(E, energy_scale):
|
|
|
313
290
|
|
|
314
291
|
|
|
315
292
|
def initial_model_parameter(spectrum):
|
|
316
|
-
tags = spectrum.metadata['EDS']
|
|
293
|
+
tags = spectrum.metadata['EDS']
|
|
317
294
|
energy_scale = spectrum.get_spectral_dims(return_axis=True)[0]
|
|
318
295
|
p = []
|
|
319
296
|
peaks = []
|
|
@@ -324,9 +301,9 @@ def initial_model_parameter(spectrum):
|
|
|
324
301
|
for line, info in lines['K-family'].items():
|
|
325
302
|
if line[0] == 'K':
|
|
326
303
|
model += get_peak(info['position'], energy_scale)*info['weight']
|
|
327
|
-
lines['K-family']['peaks'] = model/model.sum()
|
|
328
|
-
|
|
329
|
-
p.append(lines['K-family']['height'])
|
|
304
|
+
lines['K-family']['peaks'] = model /model.sum() # *lines['K-family']['probability']
|
|
305
|
+
|
|
306
|
+
p.append(lines['K-family']['height'] / lines['K-family']['peaks'].max())
|
|
330
307
|
peaks.append(lines['K-family']['peaks'])
|
|
331
308
|
keys.append(element+':K-family')
|
|
332
309
|
if 'L-family' in lines:
|
|
@@ -334,9 +311,8 @@ def initial_model_parameter(spectrum):
|
|
|
334
311
|
for line, info in lines['L-family'].items():
|
|
335
312
|
if line[0] == 'L':
|
|
336
313
|
model += get_peak(info['position'], energy_scale)*info['weight']
|
|
337
|
-
lines['L-family']['peaks'] = model/model.sum()
|
|
338
|
-
lines['L-family']['height']
|
|
339
|
-
p.append(lines['L-family']['height'])
|
|
314
|
+
lines['L-family']['peaks'] = model /model.sum() # *lines['L-family']['probability']
|
|
315
|
+
p.append(lines['L-family']['height'] / lines['L-family']['peaks'].max())
|
|
340
316
|
peaks.append(lines['L-family']['peaks'])
|
|
341
317
|
keys.append(element+':L-family')
|
|
342
318
|
if 'M-family' in lines:
|
|
@@ -344,18 +320,11 @@ def initial_model_parameter(spectrum):
|
|
|
344
320
|
for line, info in lines['M-family'].items():
|
|
345
321
|
if line[0] == 'M':
|
|
346
322
|
model += get_peak(info['position'], energy_scale)*info['weight']
|
|
347
|
-
lines['M-family']['peaks'] = model/model.sum()
|
|
348
|
-
lines['M-family']['height']
|
|
349
|
-
p.append(lines['M-family']['height'])
|
|
323
|
+
lines['M-family']['peaks'] = model /model.sum()*lines['M-family']['probability']
|
|
324
|
+
p.append(lines['M-family']['height'] / lines['M-family']['peaks'].max())
|
|
350
325
|
peaks.append(lines['M-family']['peaks'])
|
|
351
326
|
keys.append(element+':M-family')
|
|
352
|
-
|
|
353
|
-
if 'other' in lines:
|
|
354
|
-
for line, info in lines['other'].items():
|
|
355
|
-
info['peak'] = get_peak(info['position'], energy_scale)
|
|
356
|
-
peaks.append(info['peak'])
|
|
357
|
-
p.append(info['height'])
|
|
358
|
-
keys.append(element+':other:'+line)
|
|
327
|
+
|
|
359
328
|
|
|
360
329
|
#p.extend([300, 10, 1.e-04])
|
|
361
330
|
# p.extend([1, 300, -.02])
|
|
@@ -363,22 +332,23 @@ def initial_model_parameter(spectrum):
|
|
|
363
332
|
return np.array(peaks), np.array(p), keys
|
|
364
333
|
|
|
365
334
|
def get_model(spectrum, start=100):
|
|
366
|
-
|
|
367
|
-
peaks, pp, keys = initial_model_parameter(spectrum)
|
|
368
335
|
model = np.zeros(len(spectrum))
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
336
|
+
for key in spectrum.metadata['EDS']:
|
|
337
|
+
for family in spectrum.metadata['EDS'][key]:
|
|
338
|
+
if isinstance(spectrum.metadata['EDS'][key][family], dict):
|
|
339
|
+
intensity = spectrum.metadata['EDS'][key][family]['areal_density']
|
|
340
|
+
peaks = spectrum.metadata['EDS'][key][family]['peaks']
|
|
341
|
+
model += peaks * intensity
|
|
342
|
+
|
|
343
|
+
if 'detector_efficiency' in spectrum.metadata['EDS']['detector'].keys():
|
|
344
|
+
detector_efficiency = spectrum.metadata['EDS']['detector']['detector_efficiency']
|
|
375
345
|
else:
|
|
376
346
|
detector_efficiency = None
|
|
377
|
-
E_0 = spectrum.metadata['experiment']['
|
|
347
|
+
E_0 = spectrum.metadata['experiment']['acceleration_voltage']
|
|
378
348
|
|
|
379
|
-
if detector_efficiency is not None:
|
|
380
|
-
|
|
381
|
-
|
|
349
|
+
# if detector_efficiency is not None:
|
|
350
|
+
# model[start:] += detector_efficiency[start:] * (pp[-3] + pp[-2] * (E_0 - energy_scale) / energy_scale +
|
|
351
|
+
# pp[-1] * (E_0 - energy_scale) ** 2 / energy_scale)
|
|
382
352
|
|
|
383
353
|
return model
|
|
384
354
|
|
|
@@ -386,22 +356,22 @@ def fit_model(spectrum, elements, use_detector_efficiency=False):
|
|
|
386
356
|
out_tags = get_x_ray_lines(spectrum, elements)
|
|
387
357
|
peaks, pin, keys = initial_model_parameter(spectrum)
|
|
388
358
|
energy_scale = spectrum.get_spectral_dims(return_axis=True)[0].values
|
|
389
|
-
|
|
390
|
-
if 'detector' in spectrum.metadata['
|
|
391
|
-
if 'start_channel' not in spectrum.metadata['
|
|
392
|
-
spectrum.metadata['
|
|
393
|
-
if 'detector_efficiency' in spectrum.metadata['
|
|
359
|
+
|
|
360
|
+
if 'detector' in spectrum.metadata['EDS'].keys():
|
|
361
|
+
if 'start_channel' not in spectrum.metadata['EDS']['detector']:
|
|
362
|
+
spectrum.metadata['EDS']['detector']['start_channel'] = np.searchsorted(energy_scale, 100)
|
|
363
|
+
if 'detector_efficiency' in spectrum.metadata['EDS']['detector'].keys():
|
|
394
364
|
if use_detector_efficiency:
|
|
395
|
-
detector_efficiency = spectrum.metadata['
|
|
365
|
+
detector_efficiency = spectrum.metadata['EDS']['detector']['detector_efficiency']
|
|
396
366
|
else:
|
|
397
367
|
use_detector_efficiency = False
|
|
398
368
|
else:
|
|
399
369
|
print('need detector information to fit spectrum')
|
|
400
370
|
return
|
|
401
|
-
start = spectrum.metadata['
|
|
371
|
+
start = spectrum.metadata['EDS']['detector']['start_channel']
|
|
402
372
|
energy_scale = energy_scale[start:]
|
|
403
373
|
|
|
404
|
-
E_0= spectrum.metadata['experiment']['
|
|
374
|
+
E_0= spectrum.metadata['experiment']['acceleration_voltage']
|
|
405
375
|
|
|
406
376
|
def residuals(pp, yy):
|
|
407
377
|
#get_model(peaks, pp, detector_efficiency=None)
|
|
@@ -426,33 +396,31 @@ def fit_model(spectrum, elements, use_detector_efficiency=False):
|
|
|
426
396
|
|
|
427
397
|
# print(pin[-6:], p[-6:])
|
|
428
398
|
|
|
429
|
-
update_fit_values(out_tags, p)
|
|
399
|
+
update_fit_values(out_tags, peaks, p)
|
|
430
400
|
|
|
431
401
|
|
|
432
402
|
if 'EDS' not in spectrum.metadata:
|
|
433
403
|
spectrum.metadata['EDS'] = {}
|
|
434
|
-
spectrum.metadata['EDS']
|
|
404
|
+
spectrum.metadata['EDS'].update(out_tags)
|
|
435
405
|
|
|
436
406
|
return np.array(peaks), np.array(p)
|
|
437
407
|
|
|
438
408
|
|
|
439
|
-
def update_fit_values(out_tags, p):
|
|
409
|
+
def update_fit_values(out_tags, peaks, p):
|
|
440
410
|
index = 0
|
|
441
411
|
for element, lines in out_tags.items():
|
|
442
412
|
if 'K-family' in lines:
|
|
443
|
-
lines['K-family']['
|
|
413
|
+
lines['K-family']['areal_density'] = p[index]
|
|
414
|
+
lines['K-family']['peaks'] = peaks[index]
|
|
444
415
|
index += 1
|
|
445
416
|
if 'L-family' in lines:
|
|
446
|
-
lines['L-family']['
|
|
417
|
+
lines['L-family']['areal_density'] = p[index]
|
|
418
|
+
lines['L-family']['peaks'] = peaks[index]
|
|
447
419
|
index += 1
|
|
448
420
|
if 'M-family' in lines:
|
|
449
|
-
lines['M-family']['
|
|
421
|
+
lines['M-family']['areal_density'] =p[index]
|
|
422
|
+
lines['M-family']['peaks'] = peaks[index]
|
|
450
423
|
index += 1
|
|
451
|
-
if 'other' in lines:
|
|
452
|
-
for line, info in lines['other'].items():
|
|
453
|
-
info['height'] = p[index]
|
|
454
|
-
index += 1
|
|
455
|
-
|
|
456
424
|
|
|
457
425
|
def get_eds_xsection(Xsection, energy_scale, start_bgd, end_bgd):
|
|
458
426
|
background = pyTEMlib.eels_tools.power_law_background(Xsection, energy_scale, [start_bgd, end_bgd], verbose=False)
|
|
@@ -462,44 +430,97 @@ def get_eds_xsection(Xsection, energy_scale, start_bgd, end_bgd):
|
|
|
462
430
|
return cross_section_core
|
|
463
431
|
|
|
464
432
|
|
|
465
|
-
def get_eds_cross_sections(z):
|
|
466
|
-
energy_scale = np.arange(
|
|
467
|
-
Xsection = pyTEMlib.eels_tools.xsec_xrpa(energy_scale,
|
|
433
|
+
def get_eds_cross_sections(z, acceleration_voltage=200000):
|
|
434
|
+
energy_scale = np.arange(1,20000)
|
|
435
|
+
Xsection = pyTEMlib.eels_tools.xsec_xrpa(energy_scale, acceleration_voltage/1000., z, 400.)
|
|
468
436
|
edge_info = pyTEMlib.eels_tools.get_x_sections(z)
|
|
437
|
+
|
|
438
|
+
|
|
469
439
|
eds_cross_sections = {}
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
start_bgd
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
440
|
+
Xyield = edge_info['total_fluorescent_yield']
|
|
441
|
+
if 'K' in Xyield:
|
|
442
|
+
start_bgd = edge_info['K1']['onset'] * 0.8
|
|
443
|
+
end_bgd = edge_info['K1']['onset'] - 5
|
|
444
|
+
if start_bgd > end_bgd:
|
|
445
|
+
start_bgd = end_bgd-100
|
|
446
|
+
if start_bgd > energy_scale[0] and end_bgd< energy_scale[-1]-100:
|
|
447
|
+
eds_xsection = get_eds_xsection(Xsection, energy_scale, start_bgd, end_bgd)
|
|
448
|
+
eds_xsection[eds_xsection<0] = 0.
|
|
449
|
+
start_sum = np.searchsorted(energy_scale, edge_info['K1']['onset'])
|
|
450
|
+
end_sum = start_sum+600
|
|
451
|
+
if end_sum> len(Xsection):
|
|
452
|
+
end_sum = len(Xsection)-1
|
|
453
|
+
eds_cross_sections['K1'] = eds_xsection[start_sum:end_sum].sum()
|
|
454
|
+
eds_cross_sections['K'] = eds_xsection[start_sum:end_sum].sum() * Xyield['K']
|
|
455
|
+
|
|
456
|
+
if 'L3' in Xyield:
|
|
457
|
+
start_bgd = edge_info['L3']['onset'] * 0.8
|
|
458
|
+
end_bgd = edge_info['L3']['onset'] - 5
|
|
459
|
+
if start_bgd > end_bgd:
|
|
460
|
+
start_bgd = end_bgd-100
|
|
461
|
+
if start_bgd > energy_scale[0] and end_bgd< energy_scale[-1]-100:
|
|
462
|
+
eds_xsection = get_eds_xsection(Xsection, energy_scale, start_bgd, end_bgd)
|
|
463
|
+
eds_xsection[eds_xsection<0] = 0.
|
|
464
|
+
start_sum = np.searchsorted(energy_scale, edge_info['L3']['onset'])
|
|
465
|
+
end_sum = start_sum+600
|
|
466
|
+
if end_sum> len(Xsection):
|
|
467
|
+
end_sum = len(Xsection)-1
|
|
468
|
+
if end_sum >np.searchsorted(energy_scale, edge_info['K1']['onset'])-10:
|
|
469
|
+
end_sum = np.searchsorted(energy_scale, edge_info['K1']['onset'])-10
|
|
470
|
+
eds_cross_sections['L'] = eds_xsection[start_sum:end_sum].sum()
|
|
471
|
+
L1_channel = np.searchsorted(energy_scale, edge_info['L1']['onset'])
|
|
472
|
+
m_start = start_sum-100
|
|
473
|
+
if m_start < 2:
|
|
474
|
+
m_start = start_sum-20
|
|
475
|
+
l3_rise = np.max(Xsection[m_start: L1_channel-10])-np.min(Xsection[m_start: L1_channel-10])
|
|
476
|
+
l1_rise = np.max(Xsection[L1_channel-10: L1_channel+100])-np.min(Xsection[L1_channel-10: L1_channel+100])
|
|
477
|
+
l1_ratio = l1_rise/l3_rise
|
|
478
|
+
|
|
479
|
+
eds_cross_sections['L1'] = l1_ratio * eds_cross_sections['L']
|
|
480
|
+
eds_cross_sections['L2'] = eds_cross_sections['L']*(1-l1_ratio)*1/3
|
|
481
|
+
eds_cross_sections['L3'] = eds_cross_sections['L']*(1-l1_ratio)*2/3
|
|
482
|
+
eds_cross_sections['yield_L1'] = Xyield['L1']
|
|
483
|
+
eds_cross_sections['yield_L2'] = Xyield['L2']
|
|
484
|
+
eds_cross_sections['yield_L3'] = Xyield['L3']
|
|
485
|
+
|
|
486
|
+
eds_cross_sections['L'] = eds_cross_sections['L1']*Xyield['L1']+eds_cross_sections['L2']*Xyield['L2']+eds_cross_sections['L3']*Xyield['L3']
|
|
487
|
+
# eds_cross_sections['L'] /= 8
|
|
488
|
+
if 'M5' in Xyield:
|
|
489
|
+
start_bgd = edge_info['M5']['onset'] * 0.8
|
|
490
|
+
end_bgd = edge_info['M5']['onset'] - 5
|
|
491
|
+
if start_bgd > end_bgd:
|
|
492
|
+
start_bgd = end_bgd-100
|
|
493
|
+
if start_bgd > energy_scale[0] and end_bgd< energy_scale[-1]-100:
|
|
494
|
+
eds_xsection = get_eds_xsection(Xsection, energy_scale, start_bgd, end_bgd)
|
|
495
|
+
eds_xsection[eds_xsection<0] = 0.
|
|
496
|
+
start_sum = np.searchsorted(energy_scale, edge_info['M5']['onset'])
|
|
497
|
+
end_sum = start_sum+600
|
|
498
|
+
if end_sum > np.searchsorted(energy_scale, edge_info['L3']['onset'])-10:
|
|
499
|
+
end_sum = np.searchsorted(energy_scale, edge_info['L3']['onset'])-10
|
|
500
|
+
eds_cross_sections['M'] = eds_xsection[start_sum:end_sum].sum()
|
|
501
|
+
#print(edge_info['M5']['onset'] - edge_info['M1']['onset'])
|
|
502
|
+
M3_channel = np.searchsorted(energy_scale, edge_info['M3']['onset'])
|
|
503
|
+
M1_channel = np.searchsorted(energy_scale, edge_info['M1']['onset'])
|
|
504
|
+
m5_rise = np.max(Xsection[start_sum-100: M3_channel-10])-np.min(Xsection[start_sum-100: M3_channel-10])
|
|
505
|
+
m3_rise = np.max(Xsection[M3_channel-10: M1_channel-10])-np.min(Xsection[M3_channel-10: M1_channel-10])
|
|
506
|
+
m1_rise = np.max(Xsection[M1_channel-10: M1_channel+100])-np.min(Xsection[M1_channel-10: M1_channel+100])
|
|
507
|
+
m1_ratio = m1_rise/m5_rise
|
|
508
|
+
m3_ratio = m3_rise/m5_rise
|
|
509
|
+
m5_ratio = 1-(m1_ratio+m3_ratio)
|
|
510
|
+
#print(m1_ratio, m3_ratio, 1-(m1_ratio+m3_ratio))
|
|
511
|
+
eds_cross_sections['M1'] = m1_ratio * eds_cross_sections['M']
|
|
512
|
+
eds_cross_sections['M2'] = m3_ratio * eds_cross_sections['M']*1/3
|
|
513
|
+
eds_cross_sections['M3'] = m3_ratio * eds_cross_sections['M']*2/3
|
|
514
|
+
eds_cross_sections['M4'] = m5_ratio * eds_cross_sections['M']*2/5
|
|
515
|
+
eds_cross_sections['M5'] = m5_ratio * eds_cross_sections['M']*3/5
|
|
516
|
+
eds_cross_sections['yield_M1'] = Xyield['M1']
|
|
517
|
+
eds_cross_sections['yield_M2'] = Xyield['M2']
|
|
518
|
+
eds_cross_sections['yield_M3'] = Xyield['M3']
|
|
519
|
+
eds_cross_sections['yield_M4'] = Xyield['M4']
|
|
520
|
+
eds_cross_sections['yield_M5'] = Xyield['M5']
|
|
521
|
+
eds_cross_sections['M'] = eds_cross_sections['M1']*Xyield['M1']+eds_cross_sections['M2']*Xyield['M2']+eds_cross_sections['M3']*Xyield['M3'] \
|
|
522
|
+
+eds_cross_sections['M4']*Xyield['M4']+eds_cross_sections['M5']*Xyield['M5']
|
|
523
|
+
#eds_cross_sections['M'] /= 18
|
|
503
524
|
return eds_cross_sections
|
|
504
525
|
|
|
505
526
|
|
|
@@ -555,4 +576,34 @@ def plot_phases(dataset, image=None, survey_image=None):
|
|
|
555
576
|
plt.legend()
|
|
556
577
|
plt.tight_layout()
|
|
557
578
|
plt.show()
|
|
558
|
-
return fig
|
|
579
|
+
return fig
|
|
580
|
+
|
|
581
|
+
|
|
582
|
+
def plot_lines(eds_quantification: dict, axis: plt.Axes):
|
|
583
|
+
for key, lines in eds_quantification.items():
|
|
584
|
+
if 'K-family' in lines:
|
|
585
|
+
intensity = lines['K-family']['height']
|
|
586
|
+
for line in lines['K-family']:
|
|
587
|
+
if line[0] == 'K':
|
|
588
|
+
pos = lines['K-family'][line]['position']
|
|
589
|
+
axis.plot([pos,pos], [0, intensity*lines['K-family'][line]['weight']], color='blue')
|
|
590
|
+
if line == lines['K-family']['main']:
|
|
591
|
+
axis.text(pos,0, key+'\n'+line, verticalalignment='top')
|
|
592
|
+
|
|
593
|
+
if 'L-family' in lines:
|
|
594
|
+
intensity = lines['L-family']['height']
|
|
595
|
+
for line in lines['L-family']:
|
|
596
|
+
if line[0] == 'L':
|
|
597
|
+
pos = lines['L-family'][line]['position']
|
|
598
|
+
axis.plot([pos,pos], [0, intensity*lines['L-family'][line]['weight']], color='black')
|
|
599
|
+
if line in [lines['L-family']['main'], 'L3-M5', 'L3-N5', 'L1-M3']:
|
|
600
|
+
axis.text(pos,0, key+'\n'+line, verticalalignment='top')
|
|
601
|
+
|
|
602
|
+
if 'M-family' in lines:
|
|
603
|
+
intensity = lines['M-family']['height']
|
|
604
|
+
for line in lines['M-family']:
|
|
605
|
+
if line[0] == 'M':
|
|
606
|
+
pos = lines['M-family'][line]['position']
|
|
607
|
+
axis.plot([pos,pos], [0, intensity*lines['M-family'][line]['weight']], color='green')
|
|
608
|
+
if line in [lines['M-family']['main'], 'M5-N7', 'M4-N6']:
|
|
609
|
+
axis.text(pos,0, key+'\n'+line, verticalalignment='top')
|
pyTEMlib/eels_dialog.py
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
"""
|
|
2
|
-
QT dialog window for EELS compositional analysis
|
|
3
|
-
|
|
4
2
|
Author: Gerd Duscher
|
|
5
3
|
"""
|
|
6
4
|
|
|
@@ -93,7 +91,7 @@ class CurveVisualizer(object):
|
|
|
93
91
|
legline.set_alpha(0.2)
|
|
94
92
|
self.fig.canvas.draw()
|
|
95
93
|
|
|
96
|
-
def
|
|
94
|
+
def get_core_loss_sidebar():
|
|
97
95
|
side_bar = ipywidgets.GridspecLayout(14, 3,width='auto', grid_gap="0px")
|
|
98
96
|
|
|
99
97
|
|
|
@@ -194,6 +192,7 @@ def get_sidebar():
|
|
|
194
192
|
return side_bar
|
|
195
193
|
|
|
196
194
|
|
|
195
|
+
|
|
197
196
|
class CompositionWidget(object):
|
|
198
197
|
def __init__(self, datasets=None, key=None):
|
|
199
198
|
|
|
@@ -203,7 +202,7 @@ class CompositionWidget(object):
|
|
|
203
202
|
|
|
204
203
|
|
|
205
204
|
self.model = []
|
|
206
|
-
self.sidebar =
|
|
205
|
+
self.sidebar = get_core_loss_sidebar()
|
|
207
206
|
|
|
208
207
|
self.set_dataset(key)
|
|
209
208
|
|
|
@@ -312,11 +311,12 @@ class CompositionWidget(object):
|
|
|
312
311
|
reference_list =[('None', -1)]
|
|
313
312
|
|
|
314
313
|
for index, key in enumerate(self.datasets.keys()):
|
|
315
|
-
if '
|
|
316
|
-
if '
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
314
|
+
if '_rel' not in key:
|
|
315
|
+
if 'Reference' not in key :
|
|
316
|
+
if 'SPECTR' in self.datasets[key].data_type.name:
|
|
317
|
+
spectrum_list.append((f'{key}: {self.datasets[key].title}', index))
|
|
318
|
+
self.spectrum_keys_list.append(key)
|
|
319
|
+
reference_list.append((f'{key}: {self.datasets[key].title}', index))
|
|
320
320
|
|
|
321
321
|
if set_key in self.spectrum_keys_list:
|
|
322
322
|
self.key = set_key
|
|
@@ -324,10 +324,11 @@ class CompositionWidget(object):
|
|
|
324
324
|
self.key = self.spectrum_keys_list[-1]
|
|
325
325
|
self.dataset = self.datasets[self.key]
|
|
326
326
|
|
|
327
|
-
spec_dim = self.dataset.
|
|
328
|
-
self.spec_dim = self.dataset._axes[spec_dim[0]]
|
|
327
|
+
self.spec_dim = self.dataset.get_spectral_dims(return_axis=True)[0]
|
|
329
328
|
|
|
330
329
|
self.energy_scale = self.spec_dim.values
|
|
330
|
+
self.dd = (self.energy_scale[0], self.energy_scale[1])
|
|
331
|
+
|
|
331
332
|
self.dataset.metadata['experiment']['offset'] = self.energy_scale[0]
|
|
332
333
|
self.dataset.metadata['experiment']['dispersion'] = self.energy_scale[1] - self.energy_scale[0]
|
|
333
334
|
if 'edges' not in self.dataset.metadata or self.dataset.metadata['edges'] == {}:
|
|
@@ -634,7 +635,7 @@ class CompositionWidget(object):
|
|
|
634
635
|
raise ValueError('need a experiment parameter in metadata dictionary')
|
|
635
636
|
|
|
636
637
|
eff_beta = eels.effective_collection_angle(self.energy_scale, alpha, beta, beam_kv)
|
|
637
|
-
|
|
638
|
+
eff_beta = beta
|
|
638
639
|
self.low_loss = None
|
|
639
640
|
if self.sidebar[12, 1].value:
|
|
640
641
|
for key in self.datasets.keys():
|
|
@@ -1033,13 +1033,12 @@ class EdgesAtCursor(object):
|
|
|
1033
1033
|
self.label.remove()
|
|
1034
1034
|
self.line.remove()
|
|
1035
1035
|
if event.button == 1:
|
|
1036
|
-
self.label = self.ax.text(x, y_max, eels.
|
|
1036
|
+
self.label = self.ax.text(x, y_max, eels.find_all_edges(event.xdata, self.maximal_chemical_shift, major_edges_only=True),
|
|
1037
1037
|
verticalalignment='top')
|
|
1038
1038
|
self.line, = self.ax.plot([x, x], [y_min, y_max], color='black')
|
|
1039
1039
|
if event.button == 3:
|
|
1040
1040
|
self.line, = self.ax.plot([x, x], [y_min, y_max], color='black')
|
|
1041
|
-
self.label = self.ax.text(x, y_max, eels.find_all_edges(event.xdata, self.maximal_chemical_shift),
|
|
1042
|
-
verticalalignment='top')
|
|
1041
|
+
self.label = self.ax.text(x, y_max, eels.find_all_edges(event.xdata, self.maximal_chemical_shift), verticalalignment='top')
|
|
1043
1042
|
self.ax.set_ylim(y_min, y_max)
|
|
1044
1043
|
|
|
1045
1044
|
def mouse_move(self, event):
|