pyTEMlib 0.2025.4.1__py3-none-any.whl → 0.2025.9.1__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.

Files changed (94) hide show
  1. build/lib/pyTEMlib/__init__.py +33 -0
  2. build/lib/pyTEMlib/animation.py +640 -0
  3. build/lib/pyTEMlib/atom_tools.py +238 -0
  4. build/lib/pyTEMlib/config_dir.py +31 -0
  5. build/lib/pyTEMlib/crystal_tools.py +1219 -0
  6. build/lib/pyTEMlib/diffraction_plot.py +756 -0
  7. build/lib/pyTEMlib/dynamic_scattering.py +293 -0
  8. build/lib/pyTEMlib/eds_tools.py +826 -0
  9. build/lib/pyTEMlib/eds_xsections.py +432 -0
  10. build/lib/pyTEMlib/eels_tools/__init__.py +44 -0
  11. build/lib/pyTEMlib/eels_tools/core_loss_tools.py +751 -0
  12. build/lib/pyTEMlib/eels_tools/eels_database.py +134 -0
  13. build/lib/pyTEMlib/eels_tools/low_loss_tools.py +655 -0
  14. build/lib/pyTEMlib/eels_tools/peak_fit_tools.py +175 -0
  15. build/lib/pyTEMlib/eels_tools/zero_loss_tools.py +264 -0
  16. build/lib/pyTEMlib/file_reader.py +274 -0
  17. build/lib/pyTEMlib/file_tools.py +811 -0
  18. build/lib/pyTEMlib/get_bote_salvat.py +69 -0
  19. build/lib/pyTEMlib/graph_tools.py +1153 -0
  20. build/lib/pyTEMlib/graph_viz.py +599 -0
  21. build/lib/pyTEMlib/image/__init__.py +37 -0
  22. build/lib/pyTEMlib/image/image_atoms.py +270 -0
  23. build/lib/pyTEMlib/image/image_clean.py +197 -0
  24. build/lib/pyTEMlib/image/image_distortion.py +299 -0
  25. build/lib/pyTEMlib/image/image_fft.py +277 -0
  26. build/lib/pyTEMlib/image/image_graph.py +926 -0
  27. build/lib/pyTEMlib/image/image_registration.py +316 -0
  28. build/lib/pyTEMlib/image/image_utilities.py +309 -0
  29. build/lib/pyTEMlib/image/image_window.py +421 -0
  30. build/lib/pyTEMlib/image_tools.py +699 -0
  31. build/lib/pyTEMlib/interactive_image.py +1 -0
  32. build/lib/pyTEMlib/kinematic_scattering.py +1196 -0
  33. build/lib/pyTEMlib/microscope.py +61 -0
  34. build/lib/pyTEMlib/probe_tools.py +906 -0
  35. build/lib/pyTEMlib/sidpy_tools.py +153 -0
  36. build/lib/pyTEMlib/simulation_tools.py +104 -0
  37. build/lib/pyTEMlib/test.py +437 -0
  38. build/lib/pyTEMlib/utilities.py +314 -0
  39. build/lib/pyTEMlib/version.py +5 -0
  40. build/lib/pyTEMlib/xrpa_x_sections.py +20976 -0
  41. pyTEMlib/__init__.py +25 -3
  42. pyTEMlib/animation.py +31 -22
  43. pyTEMlib/atom_tools.py +29 -34
  44. pyTEMlib/config_dir.py +2 -28
  45. pyTEMlib/crystal_tools.py +129 -165
  46. pyTEMlib/eds_tools.py +559 -342
  47. pyTEMlib/eds_xsections.py +432 -0
  48. pyTEMlib/eels_tools/__init__.py +44 -0
  49. pyTEMlib/eels_tools/core_loss_tools.py +751 -0
  50. pyTEMlib/eels_tools/eels_database.py +134 -0
  51. pyTEMlib/eels_tools/low_loss_tools.py +655 -0
  52. pyTEMlib/eels_tools/peak_fit_tools.py +175 -0
  53. pyTEMlib/eels_tools/zero_loss_tools.py +264 -0
  54. pyTEMlib/file_reader.py +274 -0
  55. pyTEMlib/file_tools.py +260 -1130
  56. pyTEMlib/get_bote_salvat.py +69 -0
  57. pyTEMlib/graph_tools.py +101 -174
  58. pyTEMlib/graph_viz.py +150 -0
  59. pyTEMlib/image/__init__.py +37 -0
  60. pyTEMlib/image/image_atoms.py +270 -0
  61. pyTEMlib/image/image_clean.py +197 -0
  62. pyTEMlib/image/image_distortion.py +299 -0
  63. pyTEMlib/image/image_fft.py +277 -0
  64. pyTEMlib/image/image_graph.py +926 -0
  65. pyTEMlib/image/image_registration.py +316 -0
  66. pyTEMlib/image/image_utilities.py +309 -0
  67. pyTEMlib/image/image_window.py +421 -0
  68. pyTEMlib/image_tools.py +154 -915
  69. pyTEMlib/kinematic_scattering.py +1 -1
  70. pyTEMlib/probe_tools.py +1 -1
  71. pyTEMlib/test.py +437 -0
  72. pyTEMlib/utilities.py +314 -0
  73. pyTEMlib/version.py +2 -3
  74. pyTEMlib/xrpa_x_sections.py +14 -10
  75. {pytemlib-0.2025.4.1.dist-info → pytemlib-0.2025.9.1.dist-info}/METADATA +13 -16
  76. pytemlib-0.2025.9.1.dist-info/RECORD +86 -0
  77. {pytemlib-0.2025.4.1.dist-info → pytemlib-0.2025.9.1.dist-info}/WHEEL +1 -1
  78. pytemlib-0.2025.9.1.dist-info/top_level.txt +6 -0
  79. pyTEMlib/core_loss_widget.py +0 -721
  80. pyTEMlib/eels_dialog.py +0 -754
  81. pyTEMlib/eels_dialog_utilities.py +0 -1199
  82. pyTEMlib/eels_tools.py +0 -2359
  83. pyTEMlib/file_tools_qt.py +0 -193
  84. pyTEMlib/image_dialog.py +0 -158
  85. pyTEMlib/image_dlg.py +0 -146
  86. pyTEMlib/info_widget.py +0 -1086
  87. pyTEMlib/info_widget3.py +0 -1120
  88. pyTEMlib/low_loss_widget.py +0 -479
  89. pyTEMlib/peak_dialog.py +0 -1129
  90. pyTEMlib/peak_dlg.py +0 -286
  91. pytemlib-0.2025.4.1.dist-info/RECORD +0 -38
  92. pytemlib-0.2025.4.1.dist-info/top_level.txt +0 -1
  93. {pytemlib-0.2025.4.1.dist-info → pytemlib-0.2025.9.1.dist-info}/entry_points.txt +0 -0
  94. {pytemlib-0.2025.4.1.dist-info → pytemlib-0.2025.9.1.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,314 @@
1
+ """
2
+ # ###############################################################
3
+ # Utility Functions for spectroscopy data in pyTEMlib
4
+ # ################################################################
5
+ """
6
+ import typing
7
+ import numpy as np
8
+ from numba import jit
9
+ import scipy
10
+ import sidpy
11
+
12
+ from .xrpa_x_sections import x_sections
13
+
14
+ ELECTRON_REST_ENERGY = 5.10998918e5 # electron rest energy in eV
15
+
16
+ major_edges = ['K1', 'L3', 'M5', 'N5']
17
+
18
+ all_edges = ['K1', 'L1', 'L2', 'L3', 'M1', 'M2', 'M3', 'M4', 'M5',
19
+ 'N1', 'N2', 'N3', 'N4', 'N5', 'N6', 'N7', 'O1', 'O2',
20
+ 'O3', 'O4', 'O5', 'O6', 'O7', 'P1', 'P2', 'P3']
21
+
22
+ shell_occupancy = {'K1': 2, 'L1': 2, 'L2': 2, 'L3': 4, 'M1': 2, 'M2': 2, 'M3': 4, 'M4': 4, 'M5': 6,
23
+ 'N1': 2, 'N2': 2, 'N3': 4, 'N4': 4, 'N5': 6, 'N6': 6, 'N7': 8, 'O1': 2, 'O2': 2,
24
+ 'O3': 4, 'O4': 4, 'O5': 6, 'O6': 6, 'O7': 8, 'O8': 8, 'O9': 10}
25
+
26
+
27
+ first_close_edges = ['K1', 'L3', 'M5', 'M3', 'N5', 'N3']
28
+
29
+ elements = [' ', 'H', 'He', 'Li', 'Be', 'B', 'C', 'N', 'O', 'F', 'Ne', 'Na',
30
+ 'Mg', 'Al', 'Si', 'P', 'S', 'Cl', 'Ar', 'K', 'Ca', 'Sc', 'Ti', 'V',
31
+ 'Cr', 'Mn', 'Fe', 'Co', 'Ni', 'Cu', 'Zn', 'Ga', 'Ge', 'As', 'Se', 'Br',
32
+ 'Kr', 'Rb', 'Sr', 'Y', 'Zr', 'Nb', 'Mo', 'Tc', 'Ru', 'Rh', 'Pd', 'Ag',
33
+ 'Cd', 'In', 'Sn', 'Sb', 'Te', 'I', 'Xe', 'Cs', 'Ba', 'La', 'Ce', 'Pr',
34
+ 'Nd', 'Pm', 'Sm', 'Eu', 'Gd', 'Tb', 'Dy', 'Ho', 'Er', 'Tm', 'Yb', 'Lu',
35
+ 'Hf', 'Ta', 'W', 'Re', 'Os', 'Ir', 'Pt', 'Au', 'Hg', 'Tl', 'Pb', 'Bi']
36
+
37
+ def get_wave_length(e0: float) -> float:
38
+ """get deBroglie wavelength of electron accelerated by energy (in eV) e0"""
39
+ ev = scipy.constants.e * e0
40
+ m_e = scipy.constants.m_e
41
+ c = scipy.constants.c
42
+ h = scipy.constants.h
43
+ return h / np.sqrt(2 * m_e * ev * (1 + ev / (2 * m_e * c**2)))
44
+
45
+
46
+ def effective_collection_angle(energy_scale: np.ndarray,
47
+ alpha: float,
48
+ beta: float,
49
+ beam_ev: float) -> float:
50
+ """Calculates the effective collection angle in mrad:
51
+
52
+ Translate from original Fortran program
53
+ Calculates the effective collection angle in mrad:
54
+ Parameter
55
+ ---------
56
+ energy_scale: numpy array
57
+ first and last energy loss of spectrum in eV
58
+ alpha: float
59
+ convergence angle in mrad
60
+ beta: float
61
+ collection angle in mrad
62
+ beamKV: float
63
+ acceleration voltage in V
64
+
65
+ Returns
66
+ -------
67
+ eff_beta: float
68
+ effective collection angle in mrad
69
+
70
+ # function y = effbeta(ene, alpha, beta, beam_kv) Note Pierre uses keV
71
+ #
72
+ # This program computes etha(alpha,beta), that is the collection
73
+ # efficiency associated to the following geometry :
74
+ #
75
+ # alpha = half angle of illumination (0 -> pi/2)
76
+ # beta = half angle of collection (0 -> pi/2)
77
+ # (pi/2 = 1570.795 mrad)
78
+ #
79
+ # A constant angular distribution of incident electrons is assumed
80
+ # for any incident angle (-alpha,alpha). These electrons imping the
81
+ # target and a single energy-loss event occurs, with a characteristic
82
+ # angle theta-e (relativistic). The angular distribution of the
83
+ # electrons after the target is analytically derived.
84
+ # This program integrates this distribution from theta=0 up to
85
+ # theta=beta with an adjustable angular step.
86
+ # This program also computes beta* which is the theoretical
87
+ # collection angle which would give the same value of etha(alpha,beta)
88
+ # with a parallel incident beam.
89
+ #
90
+ # subroutines and function subprograms required
91
+ # ---------------------------------------------
92
+ # none
93
+ #
94
+ # comments
95
+ # --------
96
+ #
97
+ # The following parameters are asked as input :
98
+ # accelerating voltage (kV), energy loss range (eV) for the study,
99
+ # energy loss step (eV) in this range, alpha (mrad), beta (mrad).
100
+ # The program returns for each energy loss step :
101
+ # alpha (mrad), beta (mrad), theta-e (relativistic) (mrad),
102
+ # energy loss (eV), etha (#), beta * (mrad)
103
+ #
104
+ # author :
105
+ # --------
106
+ # Pierre TREBBIA
107
+ # US 41 : "Microscopie Electronique Analytique Quantitative"
108
+ # Laboratoire de Physique des Solides, Bat. 510
109
+ # Universite Paris-Sud, F91405 ORSAY Cedex
110
+ # Phone : (33-1) 69 41 53 68
111
+ #
112
+ """
113
+ if beam_ev == 0:
114
+ beam_ev = 100.0 * 1e3
115
+
116
+ if alpha == 0:
117
+ return beta
118
+
119
+ if beta == 0:
120
+ return alpha
121
+
122
+ alpha = alpha * 0.001 # rad
123
+ beta = beta * 0.001 # rad
124
+ z7 = 500.0 # number of integration steps to be modified at will
125
+
126
+ # main loop on energy loss
127
+ for zx in range(int(energy_scale[0]), int(energy_scale[-1]), 100):
128
+ # ! zx = current energy loss
129
+ eta = 0.0
130
+ # x0 = relativistic theta-e
131
+ x0 = float(zx) * (beam_ev + 511060.) / (beam_ev * (beam_ev + 1022120.))
132
+ dtheta = (beta - 0.1 * np.sqrt((x0**2 + alpha**2))) / 500 # integration steps
133
+ #
134
+ # calculation of the analytical expression
135
+ #
136
+ for zi in range(1, int(z7)):
137
+ theta = 0.1 * np.sqrt((x0**2 + alpha**2)) + dtheta * float(zi)
138
+ x5 = theta**2
139
+ x6 = 4. * x5 * x0 * x0
140
+ x7 = (x0**2 + alpha**2) - x5
141
+ eta += 2. * theta * dtheta * np.log((np.sqrt(x7**2 + x6) + x7) / (2. * x0**2))
142
+ # addition of the central contribution
143
+ eta = eta + (x0**2 + alpha**2) / 100. * np.log(1. + alpha**2/x0**2)
144
+ # normalisation
145
+ eta = eta / alpha * alpha * np.log(1. + np.pi**2 / (4. * x0**2))
146
+ #
147
+ # correction by geometrical factor (beta/alpha)**2
148
+ #
149
+ if beta < alpha:
150
+ x5 = alpha / beta
151
+ eta = eta * x5**2
152
+
153
+ # etha2 = eta * 100.
154
+ #
155
+ # calculation of beta *
156
+ #
157
+ x6 = np.power((1. + (1. + np.pi**2 / (4. * x0**2))), eta)
158
+ x7 = x0 * np.sqrt(x6 - 1.)
159
+ beta = x7 * 1000. # in mrad
160
+
161
+ return beta
162
+
163
+ def set_default_metadata(current_dataset: sidpy.Dataset) -> None:
164
+ """sets default metadata for the dataset"""
165
+
166
+ if 'experiment' not in current_dataset.metadata:
167
+ current_dataset.metadata['experiment'] = {}
168
+ if 'convergence_angle' not in current_dataset.metadata['experiment']:
169
+ current_dataset.metadata['experiment']['convergence_angle'] = 30
170
+ if 'collection_angle' not in current_dataset.metadata['experiment']:
171
+ current_dataset.metadata['experiment']['collection_angle'] = 50
172
+ if 'acceleration_voltage' not in current_dataset.metadata['experiment']:
173
+ current_dataset.metadata['experiment']['acceleration_voltage'] = 200000
174
+
175
+
176
+ def lorentz(x, center, amplitude, width):
177
+ """ Lorentzian Function """
178
+ lorentz_peak = 0.5 * width / np.pi / ((x - center)**2 + (width / 2)**2)
179
+ return amplitude * lorentz_peak / lorentz_peak.max()
180
+
181
+ @jit
182
+ def gauss(x, p): # p[0]==mean, p[1]= amplitude p[2]==fwhm,
183
+ """Gaussian Function
184
+
185
+ p[0]==mean, p[1]= amplitude p[2]==fwhm
186
+ area = np.sqrt(2* np.pi)* p[1] * np.abs(p[2] / 2.3548)
187
+ FWHM = 2 * np.sqrt(2 np.log(2)) * sigma = 2.3548 * sigma
188
+ sigma = FWHM/3548
189
+ """
190
+ if p[2] == 0:
191
+ return x * 0.
192
+ return p[1] * np.exp(-(x - p[0])**2 / (2.0 * (p[2] / 2.3548)**2))
193
+
194
+ def get_atomic_number(z):
195
+ """Returns the atomic number independent of input as a string or number"""
196
+ return get_z(z)
197
+
198
+ def get_z(z: typing.Union[int, str]) -> int:
199
+ """Returns the atomic number independent of input as a string or number
200
+
201
+ Parameter
202
+ ---------
203
+ z: int, str
204
+ atomic number of chemical symbol (0 if not valid)
205
+ Return:
206
+ ------
207
+ z_out: int
208
+ atomic number
209
+ """
210
+ z_out = 0
211
+ if str(z).isdigit():
212
+ z_out = int(z)
213
+ elif isinstance(z, str):
214
+ z_out = elements.index(z)
215
+ else:
216
+ raise TypeError('A valid element string or number is required')
217
+ return z_out
218
+
219
+
220
+ def get_x_sections(z: int=0) -> dict:
221
+ """Reads X-ray fluorescent cross-sections from a dictionary.
222
+
223
+ Parameters
224
+ ----------
225
+ z: int
226
+ atomic number if zero all cross-sections will be returned
227
+
228
+ Returns
229
+ -------
230
+ dictionary
231
+ cross-section of an element or of all elements if z = 0
232
+ """
233
+ if z < 1:
234
+ return x_sections
235
+ z = str(z)
236
+ if z in x_sections:
237
+ return x_sections[z]
238
+ return {}
239
+
240
+
241
+ def get_spectrum(dataset, x=0, y=0, bin_x=1, bin_y=1):
242
+ """
243
+ Extracts a spectrum from a sidpy.Dataset object
244
+ Parameter
245
+ ---------
246
+ dataset: sidpy.Dataset object
247
+ contains spectrum or spectrum image
248
+ x: int default = 0
249
+ x position of spectrum image
250
+ y: int default = 0
251
+ y position of spectrum
252
+ bin_x: int default = 1
253
+ binning of spectrum image in x-direction
254
+ bin_y: int default = 1
255
+ binning of spectrum image in y-direction
256
+
257
+ Returns:
258
+ --------
259
+ spectrum: sidpy.Dataset object
260
+
261
+ """
262
+ if dataset.data_type.name == 'SPECTRUM':
263
+ spectrum = dataset.copy()
264
+ else:
265
+ image_dims = dataset.get_image_dims()
266
+ x = min(x, dataset.shape[image_dims[0]] - bin_x)
267
+ y = min(y, dataset.shape[image_dims[1]] - bin_y)
268
+ selection = []
269
+ dimensions = dataset.get_dimension_types()
270
+ for dim, dimension_type in enumerate(dimensions):
271
+ # print(dim, axis.dimension_type)
272
+ if dimension_type == 'SPATIAL':
273
+ if dim == image_dims[0]:
274
+ selection.append(slice(x, x + bin_x))
275
+ else:
276
+ selection.append(slice(y, y + bin_y))
277
+ elif dimension_type == 'SPECTRAL':
278
+ selection.append(slice(None))
279
+ elif dimension_type == 'CHANNEL':
280
+ selection.append(slice(None))
281
+ else:
282
+ selection.append(slice(0, 1))
283
+ spectrum = dataset[tuple(selection)].mean(axis=tuple(image_dims))
284
+ spectrum.squeeze().compute()
285
+ spectrum.data_type = 'Spectrum'
286
+ return spectrum
287
+
288
+ def second_derivative(dataset: sidpy.Dataset) -> None:
289
+ """Calculates second derivative of a sidpy.dataset"""
290
+ energy_scale = dataset.get_spectral_dims(return_axis=True)[0]
291
+ if dataset.data_type.name == 'SPECTRAL_IMAGE':
292
+ spectrum = dataset.view.get_spectrum()
293
+ else:
294
+ spectrum = np.array(dataset)
295
+ spec = scipy.ndimage.gaussian_filter(spectrum, 3)
296
+ dispersion = energy_scale.slope
297
+ second_dif = np.roll(spec, -3) - 2 * spec + np.roll(spec, +3)
298
+ second_dif[:3] = 0
299
+ second_dif[-3:] = 0
300
+
301
+ # find if there is a strong edge at high energy_scale
302
+ noise_level = 2. * np.std(second_dif[3:50])
303
+ [indices, _] = scipy.signal.find_peaks(second_dif, noise_level)
304
+ width = max(50 / dispersion, 50)
305
+ start_end_noise = int(len(energy_scale) - width)
306
+ for index in indices[::-1]:
307
+ if index > start_end_noise:
308
+ start_end_noise = index - 70
309
+
310
+ # noise_level_start = sensitivity * np.std(second_dif[3:50])
311
+ # noise_level_end = sensitivity * np.std(second_dif[start_end_noise: start_end_noise + 50])
312
+ # slope = (noise_level_end - noise_level_start) / (len(energy_scale) - 400)
313
+ # noise_level = noise_level_start #+ np.arange(len(energy_scale)) * slope
314
+ return second_dif , noise_level
@@ -0,0 +1,5 @@
1
+ """
2
+ version
3
+ """
4
+ __version__ = '0.2025.09.1'
5
+ __time__ = '2025-09-03 19:58:26'