pyTEMlib 0.2025.12.0__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.
Files changed (92) hide show
  1. build/lib/pyTEMlib/__init__.py +36 -0
  2. build/lib/pyTEMlib/animation.py +667 -0
  3. build/lib/pyTEMlib/atom_tools.py +229 -0
  4. build/lib/pyTEMlib/config_dir.py +43 -0
  5. build/lib/pyTEMlib/crystal_tools.py +1219 -0
  6. build/lib/pyTEMlib/diffraction_plot.py +757 -0
  7. build/lib/pyTEMlib/dynamic_scattering.py +298 -0
  8. build/lib/pyTEMlib/eds_tools.py +901 -0
  9. build/lib/pyTEMlib/eds_xsections.py +268 -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 +275 -0
  17. build/lib/pyTEMlib/file_tools.py +816 -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 +198 -0
  24. build/lib/pyTEMlib/image/image_distortion.py +299 -0
  25. build/lib/pyTEMlib/image/image_fft.py +278 -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 +308 -0
  29. build/lib/pyTEMlib/image/image_window.py +421 -0
  30. build/lib/pyTEMlib/image_tools.py +701 -0
  31. build/lib/pyTEMlib/interactive_image.py +1 -0
  32. build/lib/pyTEMlib/kinematic_scattering.py +1145 -0
  33. build/lib/pyTEMlib/microscope.py +62 -0
  34. build/lib/pyTEMlib/probe_tools.py +928 -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 +431 -0
  39. build/lib/pyTEMlib/version.py +5 -0
  40. build/lib/pyTEMlib/xrpa_x_sections.py +20976 -0
  41. pyTEMlib/__init__.py +36 -0
  42. pyTEMlib/animation.py +667 -0
  43. pyTEMlib/atom_tools.py +229 -0
  44. pyTEMlib/config_dir.py +43 -0
  45. pyTEMlib/crystal_tools.py +1219 -0
  46. pyTEMlib/data/k_factors_Bruker_15keV.json +293 -0
  47. pyTEMlib/data/k_factors_Thermo_200keV.json +494 -0
  48. pyTEMlib/data/xrays_X_section_100kV.json +19334 -0
  49. pyTEMlib/data/xrays_X_section_200kV.json +18711 -0
  50. pyTEMlib/data/xrays_X_section_300kV.json +18347 -0
  51. pyTEMlib/data/xrays_X_section_60kV.json +20202 -0
  52. pyTEMlib/diffraction_plot.py +757 -0
  53. pyTEMlib/dynamic_scattering.py +298 -0
  54. pyTEMlib/eds_tools.py +901 -0
  55. pyTEMlib/eds_xsections.py +268 -0
  56. pyTEMlib/eels_tools/__init__.py +44 -0
  57. pyTEMlib/eels_tools/core_loss_tools.py +751 -0
  58. pyTEMlib/eels_tools/eels_database.py +134 -0
  59. pyTEMlib/eels_tools/low_loss_tools.py +655 -0
  60. pyTEMlib/eels_tools/peak_fit_tools.py +175 -0
  61. pyTEMlib/eels_tools/zero_loss_tools.py +264 -0
  62. pyTEMlib/file_reader.py +275 -0
  63. pyTEMlib/file_tools.py +816 -0
  64. pyTEMlib/get_bote_salvat.py +69 -0
  65. pyTEMlib/graph_tools.py +1153 -0
  66. pyTEMlib/graph_viz.py +599 -0
  67. pyTEMlib/image/__init__.py +37 -0
  68. pyTEMlib/image/image_atoms.py +270 -0
  69. pyTEMlib/image/image_clean.py +198 -0
  70. pyTEMlib/image/image_distortion.py +299 -0
  71. pyTEMlib/image/image_fft.py +278 -0
  72. pyTEMlib/image/image_graph.py +926 -0
  73. pyTEMlib/image/image_registration.py +316 -0
  74. pyTEMlib/image/image_utilities.py +308 -0
  75. pyTEMlib/image/image_window.py +421 -0
  76. pyTEMlib/image_tools.py +701 -0
  77. pyTEMlib/interactive_image.py +1 -0
  78. pyTEMlib/kinematic_scattering.py +1145 -0
  79. pyTEMlib/microscope.py +62 -0
  80. pyTEMlib/probe_tools.py +928 -0
  81. pyTEMlib/sidpy_tools.py +153 -0
  82. pyTEMlib/simulation_tools.py +104 -0
  83. pyTEMlib/test.py +437 -0
  84. pyTEMlib/utilities.py +431 -0
  85. pyTEMlib/version.py +5 -0
  86. pyTEMlib/xrpa_x_sections.py +20976 -0
  87. pytemlib-0.2025.12.0.dist-info/METADATA +100 -0
  88. pytemlib-0.2025.12.0.dist-info/RECORD +92 -0
  89. pytemlib-0.2025.12.0.dist-info/WHEEL +5 -0
  90. pytemlib-0.2025.12.0.dist-info/entry_points.txt +2 -0
  91. pytemlib-0.2025.12.0.dist-info/licenses/LICENSE +21 -0
  92. pytemlib-0.2025.12.0.dist-info/top_level.txt +5 -0
pyTEMlib/atom_tools.py ADDED
@@ -0,0 +1,229 @@
1
+ """ Atom detection
2
+
3
+ All atom detection is done here
4
+ Everything is in unit of pixel!!
5
+
6
+ Author: Gerd Duscher
7
+
8
+ part of pyTEMlib
9
+
10
+
11
+ a pycroscopy package
12
+ """
13
+
14
+ import numpy as np
15
+
16
+ import skimage.feature
17
+ import sklearn.cluster
18
+ import scipy.spatial
19
+ import scipy.optimize
20
+
21
+ import sidpy
22
+ import pyTEMlib
23
+
24
+ def find_atoms(image, atom_size=0.1, threshold=0.):
25
+ """ Find atoms is a simple wrapper for blob_log in skimage.feature
26
+
27
+ Parameters
28
+ ----------
29
+ image: sidpy.Dataset
30
+ the image to find atoms
31
+ atom_size: float
32
+ visible size of atom blob diameter in nm gives minimal distance between found blobs
33
+ threshold: float
34
+ threshold for blob finder; (usually between 0.001 and 1.0)
35
+ for threshold <= 0 we use the RMS contrast
36
+
37
+ Returns
38
+ -------
39
+ atoms: numpy array(Nx3)
40
+ atoms positions and radius of blob
41
+ """
42
+
43
+ if not isinstance(image, sidpy.Dataset):
44
+ raise TypeError('We need a sidpy.Dataset')
45
+ if image.data_type.name != 'IMAGE':
46
+ raise TypeError('We need sidpy.Dataset of sidpy.Datatype: IMAGE')
47
+ if not isinstance(atom_size, (float, int)):
48
+ raise TypeError('atom_size parameter has to be a number')
49
+ if not isinstance(threshold, float):
50
+ raise TypeError('threshold parameter has to be a float number')
51
+
52
+ scale_x = np.unique(np.gradient(image.dim_0.values))[0]
53
+ im = np.array(image-image.min())
54
+ im = im/im.max()
55
+ if threshold <= 0.:
56
+ threshold = np.std(im)
57
+ atoms = skimage.feature.blob_log(im, max_sigma=atom_size/scale_x, threshold=threshold)
58
+ return atoms
59
+
60
+
61
+ def atoms_clustering(atoms, mid_atoms, number_of_clusters=3, nearest_neighbours=7):
62
+ """ A wrapper for sklearn.cluster kmeans clustering of atoms.
63
+
64
+ Parameters
65
+ ----------
66
+ atoms: list or np.array (Nx2)
67
+ list of all atoms
68
+ mid_atoms: list or np.array (Nx2)
69
+ atoms to be evaluated
70
+ number_of_clusters: int
71
+ number of clusters to sort (ini=3)
72
+ nearest_neighbours: int
73
+ number of nearest neighbours evaluated
74
+
75
+ Returns
76
+ -------
77
+ clusters, distances, indices: numpy arrays
78
+ """
79
+
80
+ # get distances
81
+ nn_tree = scipy.spatial.KDTree(np.array(atoms)[:, 0:2])
82
+
83
+ distances, indices = nn_tree.query(np.array(mid_atoms)[:, 0:2], nearest_neighbours)
84
+
85
+ # Clustering with fixed RNG in kmeans
86
+ k_means = sklearn.cluster.KMeans(n_clusters=number_of_clusters, random_state=0)
87
+ k_means.fit(distances)
88
+ clusters = k_means.predict(distances)
89
+
90
+ return clusters, distances, indices
91
+
92
+
93
+ def gauss_difference(params, area):
94
+ """
95
+ Difference between part of an image and a Gaussian
96
+ This function is used int he atom refine function of pyTEMlib
97
+
98
+ Parameters
99
+ ----------
100
+ params: list
101
+ list of Gaussian parameters [width, position_x, position_y, intensity]
102
+ area: numpy array
103
+ 2D matrix = part of an image
104
+
105
+ Returns
106
+ -------
107
+ numpy array: flattened array of difference
108
+
109
+ """
110
+ gauss = pyTEMlib.probe_tools.make_gauss(area.shape[0], area.shape[1],
111
+ width=params[0], x0=params[1],
112
+ y0=params[2], intensity=params[3])
113
+ return (area - gauss).flatten()
114
+
115
+
116
+ def atom_refine(image, atoms, radius, max_int=0, min_int=0, max_dist=4):
117
+ """Fits a Gaussian in a blob of an image
118
+
119
+ Parameters
120
+ ----------
121
+ image: np.array or sidpy Dataset
122
+ atoms: list or np.array
123
+ positions of atoms
124
+ radius: float
125
+ radius of circular mask to define fitting of Gaussian
126
+ max_int: float
127
+ optional - maximum intensity to be considered for fitting
128
+ (to exclude contaminated areas for example)
129
+ min_int: float
130
+ optional - minimum intensity to be considered for fitting
131
+ (to exclude contaminated holes for example)
132
+ max_dist: float
133
+ optional - maximum distance of movement of Gaussian during fitting
134
+
135
+ Returns
136
+ -------
137
+ sym: dict
138
+ dictionary containing new atom positions and other output
139
+ """
140
+ atom_radius = int(radius + 0.5) # atom radius
141
+
142
+ pixels = np.linspace(0, 2 * atom_radius, 2 * atom_radius + 1) - atom_radius
143
+ x, y = np.meshgrid(pixels, pixels)
144
+ mask = (x ** 2 + y ** 2) < atom_radius**2
145
+
146
+ guess = [atom_radius * 2, 0.0, 0.0, 1]
147
+
148
+ volume = []
149
+ position = []
150
+ intensities = []
151
+ maximum_area = []
152
+ new_atoms = []
153
+ gauss_width = []
154
+ gauss_amplitude = []
155
+ gauss_intensity = []
156
+
157
+ for atom in atoms:
158
+ x = int(atom[0])
159
+ y = int(atom[1])
160
+ area = image[x - atom_radius:x + atom_radius + 1, y - atom_radius:y + atom_radius + 1]
161
+ append = False
162
+
163
+ if (atom_radius < x < image.shape[0] - atom_radius and
164
+ atom_radius < y < image.shape[1] - atom_radius):
165
+ position.append(1)
166
+ intensities.append((area * mask).sum())
167
+ maximum_area.append((area * mask).max())
168
+ else: # atom on rim
169
+ position.append(-1)
170
+ intensities.append(-1.)
171
+ maximum_area.append(-1.)
172
+
173
+ if max_int > 0 and min_int < area.sum() < max_int:
174
+ append = True
175
+ elif area.sum() > min_int:
176
+ append = True
177
+
178
+ pout = [0, 0, 0, 0]
179
+ if append:
180
+ if position[-1] > 0:
181
+ [pout, _] = scipy.optimize.leastsq(gauss_difference, guess, args=area)
182
+ if (abs(pout[1]) > max_dist) or (abs(pout[2]) > max_dist):
183
+ pout = [0, 0, 0, 0]
184
+
185
+ volume.append(2 * np.pi * pout[3] * pout[0] * pout[0])
186
+
187
+ new_atoms.append([x + pout[1], y + pout[2]]) # ,pout[0], volume)) #,pout[3]))
188
+ if all(v == 0 for v in pout):
189
+ gauss_intensity.append(0.)
190
+ else:
191
+ gauss = pyTEMlib.probe_tools.make_gauss(area.shape[0], area.shape[1], width=pout[0],
192
+ x0=pout[1], y0=pout[2], intensity=pout[3])
193
+ gauss_intensity.append((gauss * mask).sum())
194
+ gauss_width.append(pout[0])
195
+ gauss_amplitude.append(pout[3])
196
+
197
+ sym = {'number_of_atoms': len(atoms),
198
+ 'inside': position,
199
+ 'intensity_area': intensities,
200
+ 'maximum_area': maximum_area,
201
+ 'atoms': new_atoms,
202
+ 'gauss_width': gauss_width,
203
+ 'gauss_amplitude': gauss_amplitude,
204
+ 'gauss_intensity': gauss_intensity,
205
+ 'gauss_volume': volume}
206
+
207
+ return sym
208
+
209
+
210
+ def intensity_area(image, atoms, radius):
211
+ """
212
+ integrated intensity of atoms in an image with a mask around each atom of radius radius
213
+ """
214
+ atom_radius = int(radius + 0.5) # atom radius
215
+ print('using radius ', atom_radius, 'pixels')
216
+
217
+ pixels = np.linspace(0, 2 * atom_radius, 2 * atom_radius + 1) - atom_radius
218
+ x, y = np.meshgrid(pixels, pixels)
219
+ mask = np.array((x ** 2 + y ** 2) < atom_radius ** 2)
220
+ intensities = []
221
+ for atom in atoms:
222
+ x = int(atom[1])
223
+ y = int(atom[0])
224
+ area = image[x - atom_radius:x + atom_radius + 1, y - atom_radius:y + atom_radius + 1]
225
+ if area.shape == mask.shape:
226
+ intensities.append((area * mask).sum())
227
+ else:
228
+ intensities.append(-1)
229
+ return intensities
pyTEMlib/config_dir.py ADDED
@@ -0,0 +1,43 @@
1
+ # -*- coding: utf-8 -*-
2
+ # part of pyTEMlib
3
+ # 2022/08 Changed this to be hopefully compatible with conda-forge
4
+ #
5
+ #
6
+ """
7
+ config_dir: setup of directory ~/.pyTEMlib for custom sources and database
8
+ """
9
+ import os
10
+ import importlib
11
+ import shutil
12
+
13
+ if os.name in ['nt', 'dos', 'posix']:
14
+ config_path = os.path.join(os.path.expanduser('~'), '.pyTEMlib')
15
+ else:
16
+ config_path = '.'
17
+
18
+ origin_path = os.path.join(importlib.resources.files('pyTEMlib'), 'data')
19
+
20
+ if os.path.isdir(config_path) is False:
21
+ # messages.information("Creating config directory: %s" % config_path)
22
+ os.mkdir(config_path)
23
+
24
+ lines = ['Microscope,E0,alpha,beta,pppc,correlation_factor,VOA_conv,EELS_b1,EELS_b2,EELS_b100,MADF_offset,MADF_slope,'
25
+ 'HADF_offset,HADF_slope,BF_offset,BF_slope',
26
+ 'Libra 200,2.00E+05,10,15,1,1,6241509.647,0.0634,0.0634,0.0634,0,0,0,0,0,0',
27
+ 'UltraSTEM 60,6.00E+04,30,50,1,1,1.79E+07,0.2,0.45,0.9,0.001383,4.04E-06,0,0,0,0',
28
+ 'UltraSTEM 100,1.00E+05,30,50,1,1,6.24E+06,0.45,1,2,0,0,0,0,0,0',
29
+ 'UltraSTEM 200,2.00E+05,30,50,1,1,6.24E+06,0.45,1,2,0,0,0,0,0,0']
30
+
31
+ config_file = os.path.join(config_path, 'microscopes.csv')
32
+ if os.path.isfile(config_file) is False: # Do not overwrite users microscopy files
33
+ with open(config_file, 'w', encoding='utf-8') as f:
34
+ f.write('\n'.join(lines))
35
+
36
+ for filename in os.listdir(origin_path):
37
+ source_file = os.path.join(origin_path, filename)
38
+ target_file = os.path.join(config_path, filename)
39
+ if os.path.isfile(source_file)is False:
40
+ continue
41
+ if os.path.isfile(target_file) is False: # Do not overwrite users files
42
+ shutil.copy(source_file, target_file)
43
+ print(f"copied from {origin_path}: {filename}")