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