pyTEMlib 0.2020.11.1__py3-none-any.whl → 0.2024.8.4__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/__init__.py +11 -11
- pyTEMlib/animation.py +631 -0
- pyTEMlib/atom_tools.py +240 -245
- pyTEMlib/config_dir.py +57 -33
- pyTEMlib/core_loss_widget.py +658 -0
- pyTEMlib/crystal_tools.py +1255 -0
- pyTEMlib/diffraction_plot.py +756 -0
- pyTEMlib/dynamic_scattering.py +293 -0
- pyTEMlib/eds_tools.py +609 -0
- pyTEMlib/eels_dialog.py +749 -491
- pyTEMlib/{interactive_eels.py → eels_dialog_utilities.py} +1199 -1177
- pyTEMlib/eels_tools.py +2031 -1698
- pyTEMlib/file_tools.py +1276 -560
- pyTEMlib/file_tools_qt.py +193 -0
- pyTEMlib/graph_tools.py +1166 -450
- pyTEMlib/graph_viz.py +449 -0
- pyTEMlib/image_dialog.py +158 -0
- pyTEMlib/image_dlg.py +146 -232
- pyTEMlib/image_tools.py +1399 -1028
- pyTEMlib/info_widget.py +933 -0
- pyTEMlib/interactive_image.py +1 -226
- pyTEMlib/kinematic_scattering.py +1196 -0
- pyTEMlib/low_loss_widget.py +176 -0
- pyTEMlib/microscope.py +61 -81
- pyTEMlib/peak_dialog.py +1047 -410
- pyTEMlib/peak_dlg.py +286 -242
- pyTEMlib/probe_tools.py +653 -207
- pyTEMlib/sidpy_tools.py +153 -136
- pyTEMlib/simulation_tools.py +104 -87
- pyTEMlib/version.py +6 -3
- pyTEMlib/xrpa_x_sections.py +20972 -0
- {pyTEMlib-0.2020.11.1.dist-info → pyTEMlib-0.2024.8.4.dist-info}/LICENSE +21 -21
- pyTEMlib-0.2024.8.4.dist-info/METADATA +93 -0
- pyTEMlib-0.2024.8.4.dist-info/RECORD +37 -0
- {pyTEMlib-0.2020.11.1.dist-info → pyTEMlib-0.2024.8.4.dist-info}/WHEEL +6 -5
- {pyTEMlib-0.2020.11.1.dist-info → pyTEMlib-0.2024.8.4.dist-info}/entry_points.txt +0 -1
- pyTEMlib/KinsCat.py +0 -2758
- pyTEMlib/__version__.py +0 -2
- pyTEMlib/data/TEMlibrc +0 -68
- pyTEMlib/data/edges_db.csv +0 -189
- pyTEMlib/data/edges_db.pkl +0 -0
- pyTEMlib/data/fparam.txt +0 -103
- pyTEMlib/data/microscopes.csv +0 -7
- pyTEMlib/data/microscopes.xml +0 -167
- pyTEMlib/data/path.txt +0 -1
- pyTEMlib/defaults_parser.py +0 -90
- pyTEMlib/dm3_reader.py +0 -613
- pyTEMlib/edges_db.py +0 -76
- pyTEMlib/eels_dlg.py +0 -224
- pyTEMlib/hdf_utils.py +0 -483
- pyTEMlib/image_tools1.py +0 -2194
- pyTEMlib/info_dialog.py +0 -237
- pyTEMlib/info_dlg.py +0 -202
- pyTEMlib/nion_reader.py +0 -297
- pyTEMlib/nsi_reader.py +0 -170
- pyTEMlib/structure_tools.py +0 -316
- pyTEMlib/test.py +0 -2072
- pyTEMlib-0.2020.11.1.dist-info/METADATA +0 -20
- pyTEMlib-0.2020.11.1.dist-info/RECORD +0 -45
- {pyTEMlib-0.2020.11.1.dist-info → pyTEMlib-0.2024.8.4.dist-info}/top_level.txt +0 -0
pyTEMlib/structure_tools.py
DELETED
|
@@ -1,316 +0,0 @@
|
|
|
1
|
-
import numpy as np
|
|
2
|
-
from math import gcd, ceil, atan
|
|
3
|
-
from fractions import Fraction
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
# SIGMA_SYMBOL = u'\u03A3'
|
|
7
|
-
UNIMODULAR_MATRIX = np.array([np.identity(3),
|
|
8
|
-
[[1, 0, 1],
|
|
9
|
-
[0, 1, 0],
|
|
10
|
-
[0, 1, 1]],
|
|
11
|
-
[[1, 0, 1],
|
|
12
|
-
[0, 1, 0],
|
|
13
|
-
[0, 1, -1]],
|
|
14
|
-
[[1, 0, 1],
|
|
15
|
-
[0, 1, 0],
|
|
16
|
-
[-1, 1, 0]],
|
|
17
|
-
[[1, 0, 1],
|
|
18
|
-
[1, 1, 0],
|
|
19
|
-
[1, 1, 1]]])
|
|
20
|
-
STRUCTURE_MATRIX = np.array([np.identity(3),
|
|
21
|
-
[[0.5, -0.5, 0],
|
|
22
|
-
[0.5, 0.5, 0],
|
|
23
|
-
[0.5, 0.5, 1]],
|
|
24
|
-
[[0.5, 0.5, 0],
|
|
25
|
-
[0, 0.5, 0.5],
|
|
26
|
-
[0.5, 0, 0.5]]])
|
|
27
|
-
|
|
28
|
-
# 0 is coprime only with 1
|
|
29
|
-
def coprime(a, b):
|
|
30
|
-
return gcd(a,b) in (0, 1)
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
def get_cubic_sigma(hkl, m, n=1):
|
|
34
|
-
sqsum = np.inner(hkl, hkl)
|
|
35
|
-
sigma = m*m + n*n * sqsum
|
|
36
|
-
while sigma != 0 and sigma % 2 == 0:
|
|
37
|
-
sigma /= 2
|
|
38
|
-
return (sigma if sigma > 1 else None)
|
|
39
|
-
|
|
40
|
-
def get_cubic_theta(hkl, m, n=1):
|
|
41
|
-
h,k,l = hkl
|
|
42
|
-
sqsum = h*h + k*k + l*l
|
|
43
|
-
assert sqsum > 0
|
|
44
|
-
if m > 0:
|
|
45
|
-
return 2 * atan(np.sqrt(sqsum) * n / m)
|
|
46
|
-
else:
|
|
47
|
-
return pi
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
def get_theta_m_n_list(hkl, sigma, verbose=False):
|
|
51
|
-
if sigma == 1:
|
|
52
|
-
return [(0., 0, 0)]
|
|
53
|
-
thetas = []
|
|
54
|
-
|
|
55
|
-
# From Grimmer, Acta Cryst. (1984). A40, 108-112
|
|
56
|
-
# S = m^2 + (u^2+v^2+w^2) n^2 (eq. 2)
|
|
57
|
-
# S = alpha * Sigma (eq. 4)
|
|
58
|
-
# where alpha = 1, 2 or 4.
|
|
59
|
-
# Since (u^2+v^2+w^2) n^2 > 0,
|
|
60
|
-
# thus alpha * Sigma > m^2 => m^2 < 4 * Sigma
|
|
61
|
-
max_m = int(ceil(np.sqrt(4*sigma)))
|
|
62
|
-
|
|
63
|
-
for m in range(max_m):
|
|
64
|
-
for n in range(1, max_m):
|
|
65
|
-
if not coprime(m, n):
|
|
66
|
-
continue
|
|
67
|
-
s = get_cubic_sigma(hkl, m, n)
|
|
68
|
-
if s != sigma:
|
|
69
|
-
continue
|
|
70
|
-
theta = get_cubic_theta(hkl, m, n)
|
|
71
|
-
if verbose:
|
|
72
|
-
print("m=%i n=%i" % (m, n), "%.3f" % np.degrees(theta))
|
|
73
|
-
thetas.append((theta, m, n))
|
|
74
|
-
return np.array(thetas)
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
def rodrigues(a, angle, verbose=False):
|
|
78
|
-
"use Rodrigues' rotation formula to get rotation matrix"
|
|
79
|
-
a = np.array(a, dtype=float)
|
|
80
|
-
a /= np.sqrt(np.inner(a, a)) # make unit vector
|
|
81
|
-
#assert abs(sin_angle - sin(acos(cos_angle))) < 1e-6
|
|
82
|
-
if verbose:
|
|
83
|
-
print ("rotation angle:", np.degrees(angle))
|
|
84
|
-
print ("rotation axis:", a)
|
|
85
|
-
omega = np.array([[ 0., -a[2], a[1]],
|
|
86
|
-
[ a[2], 0., -a[0]],
|
|
87
|
-
[-a[1], a[0], 0.]])
|
|
88
|
-
rm = (np.identity(3) + omega * np.sin(angle)
|
|
89
|
-
+ np.dot(omega, omega) * (1 - np.cos(angle)))
|
|
90
|
-
if verbose:
|
|
91
|
-
print("rotation matrix:", rm)
|
|
92
|
-
return rm
|
|
93
|
-
|
|
94
|
-
def is_integer(a, epsilon=1e-7):
|
|
95
|
-
"return true if numpy Float array consists off all integers"
|
|
96
|
-
return (np.abs(a - np.round(a)) < epsilon).all()
|
|
97
|
-
|
|
98
|
-
def get_smallest_multiplier(a, max_n=1000):
|
|
99
|
-
"""return the smallest positive integer n such that matrix a multiplied
|
|
100
|
-
by n is an integer matrix
|
|
101
|
-
"""
|
|
102
|
-
for i in range(1, max_n):
|
|
103
|
-
if is_integer(i*a):
|
|
104
|
-
return i
|
|
105
|
-
|
|
106
|
-
def plus_minus_gen(start, end):
|
|
107
|
-
"""
|
|
108
|
-
Generate a list of plus and minus alternating integers
|
|
109
|
-
"""
|
|
110
|
-
for i in range(start, end):
|
|
111
|
-
yield i
|
|
112
|
-
yield -i
|
|
113
|
-
def get_csl_matrix(sigma, rotate_matrix):
|
|
114
|
-
"""\
|
|
115
|
-
Find matrix that determines the coincidence site lattice
|
|
116
|
-
for cubic structures.
|
|
117
|
-
Parameters:
|
|
118
|
-
sigma: CSL sigma
|
|
119
|
-
R: rotation matrix
|
|
120
|
-
centering: "f" for f.c.c., "b" for b.c.c. and None for p.c.
|
|
121
|
-
Return value:
|
|
122
|
-
matrix, which column vectors are the unit vectors of the CSL.
|
|
123
|
-
Based on H. Grimmer et al., Acta Cryst. (1974) A30, 197
|
|
124
|
-
https://doi.org/10.1107/S056773947400043X
|
|
125
|
-
"""
|
|
126
|
-
|
|
127
|
-
s = STRUCTURE_MATRIX[0]
|
|
128
|
-
for u in UNIMODULAR_MATRIX:
|
|
129
|
-
t = np.eye(3) - np.dot(np.dot(np.dot(u, np.linalg.inv(s)), np.linalg.inv(rotate_matrix)), s)
|
|
130
|
-
if abs( np.linalg.det(t)) > 1e-6:
|
|
131
|
-
break
|
|
132
|
-
o_lattice = np.round( np.linalg.inv(t), 12)
|
|
133
|
-
n = np.round(sigma / np.linalg.det(o_lattice), 6)
|
|
134
|
-
csl_matrix = o_lattice_to_csl(o_lattice, n)
|
|
135
|
-
return csl_matrix
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
def o_lattice_to_csl(o_lattice, n):
|
|
139
|
-
"""
|
|
140
|
-
The algorithm was borrowed from gosam project with slight changes.
|
|
141
|
-
Link to the project: https://github.com/wojdyr/gosam
|
|
142
|
-
|
|
143
|
-
There are two major steps: (1) Manipulate the columns of O-lattice to get
|
|
144
|
-
an integral basis matrix for CSL: make two columns become integers and
|
|
145
|
-
the remaining column can be multiplied by n whereby the determinant
|
|
146
|
-
becomes sigma. (2) Simplify CSL so its vectors acquire the shortest length:
|
|
147
|
-
decrease the integers in the matrix while keeping the determinant the same
|
|
148
|
-
by adding other column vectors (row vectors in the following example) to a
|
|
149
|
-
column vector. If after the addition or subtraction, the maximum value or
|
|
150
|
-
absolute summation of added or subtracted vector is smaller than the
|
|
151
|
-
original, then proceed the addition or subtraction.
|
|
152
|
-
0 0 -1 0 0 -1 0 0 -1 0 0 -1 0 0 -1
|
|
153
|
-
1 2 -1 -> 1 2 0 -> 1 2 0 -> 1 2 0 -> 1 2 0
|
|
154
|
-
1 -3 2 1 -3 2 1 -3 1 1 -3 0 2 -1 0
|
|
155
|
-
|
|
156
|
-
Args:
|
|
157
|
-
o_lattice (3x3 array): O-lattice in crystal coordinates
|
|
158
|
-
n (int): Number of O-lattice units per CSL unit
|
|
159
|
-
|
|
160
|
-
Returns:
|
|
161
|
-
CSL matrix (3x3 array) in crystal coordinates
|
|
162
|
-
"""
|
|
163
|
-
csl = o_lattice.copy()
|
|
164
|
-
if n < 0:
|
|
165
|
-
csl[0] *= -1
|
|
166
|
-
n *= -1
|
|
167
|
-
while True:
|
|
168
|
-
m = [get_smallest_multiplier(i) for i in csl]
|
|
169
|
-
m_prod = np.prod(m)
|
|
170
|
-
if m_prod <= n:
|
|
171
|
-
for i in range(3):
|
|
172
|
-
csl[i] *= m[i]
|
|
173
|
-
if m_prod < n:
|
|
174
|
-
assert n % m_prod == 0
|
|
175
|
-
csl[0] *= n / m_prod
|
|
176
|
-
break
|
|
177
|
-
else:
|
|
178
|
-
changed = False
|
|
179
|
-
for i in range(3):
|
|
180
|
-
for j in range(3):
|
|
181
|
-
if changed or i == j or m[i] == 1 or m[j] == 1:
|
|
182
|
-
continue
|
|
183
|
-
a, b = (i, j) if m[i] <= m[j] else (j, i)
|
|
184
|
-
for k in plus_minus_gen(1, m[b]):
|
|
185
|
-
handle = csl[a] + k * csl[b]
|
|
186
|
-
if get_smallest_multiplier(handle) < m[a]:
|
|
187
|
-
csl[a] += k * csl[b]
|
|
188
|
-
changed = True
|
|
189
|
-
break
|
|
190
|
-
if not changed:
|
|
191
|
-
# This situation rarely happens. Not sure if this solution is
|
|
192
|
-
# legit, as det not equals to sigma. E.g. Sigma 115[113]
|
|
193
|
-
for i in range(3):
|
|
194
|
-
csl[i] *= m[i]
|
|
195
|
-
break
|
|
196
|
-
csl = csl.round().astype(int)
|
|
197
|
-
|
|
198
|
-
# Reshape CSL
|
|
199
|
-
def simplify(l1, l2):
|
|
200
|
-
x = abs(l1 + l2)
|
|
201
|
-
y = abs(l1)
|
|
202
|
-
changed = False
|
|
203
|
-
while max(x) < max(y) or (max(x) == max(y) and sum(x) < sum(y)):
|
|
204
|
-
l1 += l2
|
|
205
|
-
changed = True
|
|
206
|
-
x = abs(l1 + l2)
|
|
207
|
-
y = abs(l1)
|
|
208
|
-
return changed
|
|
209
|
-
|
|
210
|
-
while True:
|
|
211
|
-
changed = False
|
|
212
|
-
for i in range(3):
|
|
213
|
-
for j in range(3):
|
|
214
|
-
if i != j and not changed:
|
|
215
|
-
changed = simplify(csl[i], csl[j]) or simplify(csl[i], -csl[j])
|
|
216
|
-
if changed:
|
|
217
|
-
break
|
|
218
|
-
if not changed:
|
|
219
|
-
break
|
|
220
|
-
return csl
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
def orthogonalize_csl(csl, axis):
|
|
224
|
-
"""
|
|
225
|
-
(1) Set the 3rd column of csl same as the rotation axis. The algorithm was
|
|
226
|
-
borrowed from gosam project with slight changes. Link to the project:
|
|
227
|
-
https://github.com/wojdyr/gosam
|
|
228
|
-
(2) Orthogonalize CSL, which is essentially a Gram-Schmidt process. At the
|
|
229
|
-
same time, we want to make sure the column vectors of orthogonalized csl
|
|
230
|
-
has the smallest value possible. That's why we compared two different ways.
|
|
231
|
-
csl = [v1, v2, v3], vi is the column vector
|
|
232
|
-
u1 = v3/||v3||, y2 = v1 - (v1 . u1)u1
|
|
233
|
-
u2 = y2/||y2||, y3 = v3 - [(v3 . u1)u1 + (v3 . u2)u2]
|
|
234
|
-
u3 = y3/||y3||
|
|
235
|
-
"""
|
|
236
|
-
axis = np.array(axis)
|
|
237
|
-
c = np.linalg.solve(csl.transpose(), axis)
|
|
238
|
-
if not is_integer(c):
|
|
239
|
-
mult = get_smallest_multiplier(c)
|
|
240
|
-
c *= mult
|
|
241
|
-
c = c.round().astype(int)
|
|
242
|
-
ind = min([(i, v) for i, v in enumerate(c) if not np.allclose(v, 0)],
|
|
243
|
-
key=lambda x: abs(x[1]))[0]
|
|
244
|
-
if ind != 2:
|
|
245
|
-
csl[ind], csl[2] = csl[2].copy(), -csl[ind]
|
|
246
|
-
c[ind], c[2] = c[2], -c[ind]
|
|
247
|
-
|
|
248
|
-
csl[2] = np.dot(c, csl)
|
|
249
|
-
if c[2] < 0:
|
|
250
|
-
csl[1] *= -1
|
|
251
|
-
|
|
252
|
-
def get_integer(vec):
|
|
253
|
-
# Used vec = np.array(vec, dtype=float) before, but does not work for
|
|
254
|
-
# [5.00000000e-01, -5.00000000e-01, 2.22044605e-16] in Sigma3[112]
|
|
255
|
-
vec = np.round(vec, 12)
|
|
256
|
-
vec_sign = np.array([1 if abs(i) == i else -1 for i in vec])
|
|
257
|
-
vec = list(abs(vec))
|
|
258
|
-
new_vec = []
|
|
259
|
-
if 0.0 in vec:
|
|
260
|
-
zero_ind = vec.index(0)
|
|
261
|
-
vec.pop(zero_ind)
|
|
262
|
-
if 0.0 in vec:
|
|
263
|
-
new_vec = [get_smallest_multiplier(vec) * i for i in vec]
|
|
264
|
-
else:
|
|
265
|
-
frac = Fraction(vec[0] / vec[1]).limit_denominator()
|
|
266
|
-
new_vec = [frac.numerator, frac.denominator]
|
|
267
|
-
new_vec.insert(zero_ind, 0)
|
|
268
|
-
else:
|
|
269
|
-
for i in range(len(vec) - 1):
|
|
270
|
-
frac = Fraction(vec[i] / vec[i + 1]).limit_denominator()
|
|
271
|
-
new_vec.extend([frac.numerator, frac.denominator])
|
|
272
|
-
if new_vec[1] == new_vec[2]:
|
|
273
|
-
new_vec = [new_vec[0], new_vec[1], new_vec[3]]
|
|
274
|
-
else:
|
|
275
|
-
new_vec = reduce_vector([new_vec[0] * new_vec[2],
|
|
276
|
-
new_vec[1] * new_vec[2],
|
|
277
|
-
new_vec[3] * new_vec[1]])
|
|
278
|
-
assert is_integer(new_vec)
|
|
279
|
-
return new_vec * vec_sign
|
|
280
|
-
|
|
281
|
-
u1 = csl[2] / np.linalg.norm(csl[2])
|
|
282
|
-
y2_1 = csl[1] - np.dot(csl[1], u1) * u1
|
|
283
|
-
c0_1 = get_integer(y2_1)
|
|
284
|
-
y2_2 = csl[0] - np.dot(csl[0], u1) * u1
|
|
285
|
-
c0_2 = get_integer(y2_2)
|
|
286
|
-
if sum(abs(c0_1)) > sum(abs(c0_2)):
|
|
287
|
-
u2 = y2_2 / np.linalg.norm(y2_2)
|
|
288
|
-
y3 = csl[1] - np.dot(csl[1], u1) * u1 - np.dot(csl[1], u2) * u2
|
|
289
|
-
csl[1] = get_integer(y3)
|
|
290
|
-
csl[0] = c0_2
|
|
291
|
-
else:
|
|
292
|
-
u2 = y2_1 / np.linalg.norm(y2_1)
|
|
293
|
-
y3 = csl[0] - np.dot(csl[0], u1) * u1 - np.dot(csl[0], u2) * u2
|
|
294
|
-
csl[1] = c0_1
|
|
295
|
-
csl[0] = get_integer(y3)
|
|
296
|
-
for i in range(3):
|
|
297
|
-
for j in range(i + 1, 3):
|
|
298
|
-
if not np.allclose(np.dot(csl[i], csl[j]), 0):
|
|
299
|
-
raise ValueError("Non-orthogonal basis: %s" % csl)
|
|
300
|
-
return csl.round().astype(int)
|
|
301
|
-
|
|
302
|
-
def find_smallest_real_multiplier(a, max_n=1000):
|
|
303
|
-
"""return the smallest positive real f such that matrix `a' multiplied
|
|
304
|
-
by f is an integer matrix
|
|
305
|
-
"""
|
|
306
|
-
# |the smallest non-zero element|
|
|
307
|
-
m = min(abs(i) for i in a if abs(i) > 1e-9)
|
|
308
|
-
for i in range(1, max_n):
|
|
309
|
-
t = i / float(m)
|
|
310
|
-
if is_integer(t * a):
|
|
311
|
-
return t
|
|
312
|
-
raise ValueError("Sorry, we can't make this matrix integer:\n%s" % a)
|
|
313
|
-
|
|
314
|
-
def scale_to_integers(v):
|
|
315
|
-
return np.array(v * find_smallest_real_multiplier(v)).round().astype(int)
|
|
316
|
-
|