pytme 0.2.9__cp311-cp311-macosx_15_0_arm64.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 (119) hide show
  1. pytme-0.2.9.data/scripts/estimate_ram_usage.py +97 -0
  2. pytme-0.2.9.data/scripts/match_template.py +1135 -0
  3. pytme-0.2.9.data/scripts/postprocess.py +622 -0
  4. pytme-0.2.9.data/scripts/preprocess.py +209 -0
  5. pytme-0.2.9.data/scripts/preprocessor_gui.py +1227 -0
  6. pytme-0.2.9.dist-info/METADATA +95 -0
  7. pytme-0.2.9.dist-info/RECORD +119 -0
  8. pytme-0.2.9.dist-info/WHEEL +5 -0
  9. pytme-0.2.9.dist-info/entry_points.txt +6 -0
  10. pytme-0.2.9.dist-info/licenses/LICENSE +153 -0
  11. pytme-0.2.9.dist-info/top_level.txt +3 -0
  12. scripts/__init__.py +0 -0
  13. scripts/estimate_ram_usage.py +97 -0
  14. scripts/match_template.py +1135 -0
  15. scripts/postprocess.py +622 -0
  16. scripts/preprocess.py +209 -0
  17. scripts/preprocessor_gui.py +1227 -0
  18. tests/__init__.py +0 -0
  19. tests/data/Blurring/blob_width18.npy +0 -0
  20. tests/data/Blurring/edgegaussian_sigma3.npy +0 -0
  21. tests/data/Blurring/gaussian_sigma2.npy +0 -0
  22. tests/data/Blurring/hamming_width6.npy +0 -0
  23. tests/data/Blurring/kaiserb_width18.npy +0 -0
  24. tests/data/Blurring/localgaussian_sigma0510.npy +0 -0
  25. tests/data/Blurring/mean_size5.npy +0 -0
  26. tests/data/Blurring/ntree_sigma0510.npy +0 -0
  27. tests/data/Blurring/rank_rank3.npy +0 -0
  28. tests/data/Maps/.DS_Store +0 -0
  29. tests/data/Maps/emd_8621.mrc.gz +0 -0
  30. tests/data/README.md +2 -0
  31. tests/data/Raw/em_map.map +0 -0
  32. tests/data/Structures/.DS_Store +0 -0
  33. tests/data/Structures/1pdj.cif +3339 -0
  34. tests/data/Structures/1pdj.pdb +1429 -0
  35. tests/data/Structures/5khe.cif +3685 -0
  36. tests/data/Structures/5khe.ent +2210 -0
  37. tests/data/Structures/5khe.pdb +2210 -0
  38. tests/data/Structures/5uz4.cif +70548 -0
  39. tests/preprocessing/__init__.py +0 -0
  40. tests/preprocessing/test_compose.py +76 -0
  41. tests/preprocessing/test_frequency_filters.py +178 -0
  42. tests/preprocessing/test_preprocessor.py +136 -0
  43. tests/preprocessing/test_utils.py +79 -0
  44. tests/test_analyzer.py +216 -0
  45. tests/test_backends.py +446 -0
  46. tests/test_density.py +503 -0
  47. tests/test_extensions.py +130 -0
  48. tests/test_matching_cli.py +283 -0
  49. tests/test_matching_data.py +162 -0
  50. tests/test_matching_exhaustive.py +124 -0
  51. tests/test_matching_memory.py +30 -0
  52. tests/test_matching_optimization.py +226 -0
  53. tests/test_matching_utils.py +189 -0
  54. tests/test_orientations.py +175 -0
  55. tests/test_parser.py +33 -0
  56. tests/test_rotations.py +153 -0
  57. tests/test_structure.py +247 -0
  58. tme/__init__.py +6 -0
  59. tme/__version__.py +1 -0
  60. tme/analyzer/__init__.py +2 -0
  61. tme/analyzer/_utils.py +186 -0
  62. tme/analyzer/aggregation.py +577 -0
  63. tme/analyzer/peaks.py +953 -0
  64. tme/backends/__init__.py +171 -0
  65. tme/backends/_cupy_utils.py +734 -0
  66. tme/backends/_jax_utils.py +188 -0
  67. tme/backends/cupy_backend.py +294 -0
  68. tme/backends/jax_backend.py +314 -0
  69. tme/backends/matching_backend.py +1270 -0
  70. tme/backends/mlx_backend.py +241 -0
  71. tme/backends/npfftw_backend.py +583 -0
  72. tme/backends/pytorch_backend.py +430 -0
  73. tme/data/__init__.py +0 -0
  74. tme/data/c48n309.npy +0 -0
  75. tme/data/c48n527.npy +0 -0
  76. tme/data/c48n9.npy +0 -0
  77. tme/data/c48u1.npy +0 -0
  78. tme/data/c48u1153.npy +0 -0
  79. tme/data/c48u1201.npy +0 -0
  80. tme/data/c48u1641.npy +0 -0
  81. tme/data/c48u181.npy +0 -0
  82. tme/data/c48u2219.npy +0 -0
  83. tme/data/c48u27.npy +0 -0
  84. tme/data/c48u2947.npy +0 -0
  85. tme/data/c48u3733.npy +0 -0
  86. tme/data/c48u4749.npy +0 -0
  87. tme/data/c48u5879.npy +0 -0
  88. tme/data/c48u7111.npy +0 -0
  89. tme/data/c48u815.npy +0 -0
  90. tme/data/c48u83.npy +0 -0
  91. tme/data/c48u8649.npy +0 -0
  92. tme/data/c600v.npy +0 -0
  93. tme/data/c600vc.npy +0 -0
  94. tme/data/metadata.yaml +80 -0
  95. tme/data/quat_to_numpy.py +42 -0
  96. tme/data/scattering_factors.pickle +0 -0
  97. tme/density.py +2263 -0
  98. tme/extensions.cpython-311-darwin.so +0 -0
  99. tme/external/bindings.cpp +332 -0
  100. tme/filters/__init__.py +6 -0
  101. tme/filters/_utils.py +311 -0
  102. tme/filters/bandpass.py +230 -0
  103. tme/filters/compose.py +81 -0
  104. tme/filters/ctf.py +393 -0
  105. tme/filters/reconstruction.py +160 -0
  106. tme/filters/wedge.py +542 -0
  107. tme/filters/whitening.py +191 -0
  108. tme/matching_data.py +863 -0
  109. tme/matching_exhaustive.py +497 -0
  110. tme/matching_optimization.py +1311 -0
  111. tme/matching_scores.py +1183 -0
  112. tme/matching_utils.py +1188 -0
  113. tme/memory.py +337 -0
  114. tme/orientations.py +598 -0
  115. tme/parser.py +685 -0
  116. tme/preprocessor.py +1329 -0
  117. tme/rotations.py +350 -0
  118. tme/structure.py +1864 -0
  119. tme/types.py +13 -0
tme/rotations.py ADDED
@@ -0,0 +1,350 @@
1
+ """ Implements various means of generating rotation matrices.
2
+
3
+ Copyright (c) 2023-2025 European Molecular Biology Laboratory
4
+
5
+ Author: Valentin Maurer <valentin.maurer@embl-hamburg.de>
6
+ """
7
+
8
+ import yaml
9
+ import warnings
10
+ from typing import Tuple
11
+ from os.path import join, dirname
12
+
13
+ import numpy as np
14
+ from scipy.spatial.transform import Rotation
15
+
16
+ from .types import NDArray
17
+
18
+ __all__ = [
19
+ "get_cone_rotations",
20
+ "align_vectors",
21
+ "euler_to_rotationmatrix",
22
+ "euler_from_rotationmatrix",
23
+ "get_rotation_matrices",
24
+ "align_to_axis",
25
+ ]
26
+
27
+
28
+ def _sample_cone(
29
+ angle: float, sampling: float, axis: Tuple[float] = (1, 0, 0)
30
+ ) -> NDArray:
31
+ """
32
+ Sample points on a cone surface around cone_axis using golden spiral distribution.
33
+
34
+ Parameters
35
+ ----------
36
+ angle : float
37
+ The half-angle of the cone in degrees.
38
+ sampling : float
39
+ Angular increment used for sampling points in degrees.
40
+ axis : tuple of floats
41
+ Vector to align the cone with.
42
+
43
+ Returns
44
+ -------
45
+ NDArray
46
+ Array of points around axis with shape n,3.
47
+
48
+ References
49
+ ----------
50
+ .. [1] https://stackoverflow.com/questions/9600801/evenly-distributing-n-points-on-a-sphere
51
+ """
52
+ theta = np.linspace(0, angle, round(angle / sampling) + 1)
53
+ number_of_points = np.ceil(
54
+ 360 * np.divide(np.sin(np.radians(theta)), sampling),
55
+ )
56
+ number_of_points = int(np.sum(number_of_points + 1) + 2)
57
+
58
+ indices = np.arange(0, number_of_points, dtype=float) + 0.5
59
+ radius = np.radians(angle * np.sqrt(indices / number_of_points))
60
+ theta = np.pi * (1 + np.sqrt(5)) * indices
61
+
62
+ points = np.stack(
63
+ [
64
+ np.cos(radius),
65
+ np.cos(theta) * np.sin(radius),
66
+ np.sin(theta) * np.sin(radius),
67
+ ],
68
+ axis=1,
69
+ )
70
+
71
+ rotation = Rotation.from_euler(
72
+ angles=align_vectors((1, 0, 0), axis, seq="zyz"),
73
+ seq="zyz",
74
+ degrees=True,
75
+ )
76
+ return rotation.apply(points)
77
+
78
+
79
+ def get_cone_rotations(
80
+ cone_angle: float,
81
+ cone_sampling: float,
82
+ axis: Tuple[float] = (1, 0, 0),
83
+ axis_angle: float = 360.0,
84
+ axis_sampling: float = None,
85
+ reference: Tuple[float] = (1, 0, 0),
86
+ n_symmetry: int = 1,
87
+ seq: str = None,
88
+ ) -> NDArray:
89
+ """
90
+ Generate rotations describing the possible placements of a vector in a cone.
91
+
92
+ Parameters
93
+ ----------
94
+ cone_angle : float
95
+ The half-angle of the cone in degrees.
96
+ cone_sampling : float
97
+ Angular increment used for sampling points on the cone in degrees.
98
+ axis : Tuple[float], optional
99
+ Base-vector of the cone.
100
+ axis_angle : float, optional
101
+ The total angle of rotation around the cone axis in degrees (default is 360.0).
102
+ axis_sampling : float, optional
103
+ Angular increment used for sampling points around the cone axis in degrees.
104
+ If None, it takes the value of cone_sampling.
105
+ reference : Tuple[float], optional
106
+ Returned rotations will map this point onto the cone. In practice, this is
107
+ the principal axis of the template.
108
+ n_symmetry : int, optional
109
+ Number of symmetry axis around the vector axis.
110
+ seq : str, optional
111
+ Convention for angles. By default returns rotation matrices.
112
+
113
+ Returns
114
+ -------
115
+ NDArray
116
+ An arary of rotations represented as stack of rotation matrices when convention
117
+ None (n, 3, 3) or an array of Euler angles (n, 3) for available conventions.
118
+ """
119
+ if axis_sampling is None:
120
+ axis_sampling = cone_sampling
121
+
122
+ points = _sample_cone(angle=cone_angle, sampling=cone_sampling, axis=axis)
123
+ reference = np.asarray(reference).astype(np.float32)
124
+ reference /= np.linalg.norm(reference)
125
+
126
+ axis_angle /= n_symmetry
127
+ phi_steps = np.maximum(np.round(axis_angle / axis_sampling), 1).astype(int)
128
+ phi = np.linspace(0, axis_angle, phi_steps + 1)[:-1]
129
+
130
+ axis_rotation = Rotation.from_rotvec(axis * np.radians(phi)[:, None])
131
+ all_rotations = [
132
+ axis_rotation * Rotation.from_matrix(align_vectors(reference, x))
133
+ for x in points
134
+ ]
135
+
136
+ rotations = Rotation.concatenate(all_rotations)
137
+ if seq is None:
138
+ return rotations.as_matrix()
139
+
140
+ return rotations.as_euler(seq=seq, degrees=True)
141
+
142
+
143
+ def align_vectors(base: NDArray, target: NDArray = (0, 0, 1), seq: str = None):
144
+ """
145
+ Compute the rotation matrix or Euler angles required to align an initial vector with a target vector.
146
+
147
+ Parameters
148
+ ----------
149
+ base : NDArray
150
+ The basis vector.
151
+ target : NDArray, optional
152
+ The vector to map base to, defaults to (0,0,1).
153
+ seq : str, optional
154
+ Euler angle convention, None returns a rotation matrix instead.
155
+
156
+ Returns
157
+ -------
158
+ NDArray
159
+ Rotation matrix if seq is None otherwise Euler angles in desired convention
160
+ """
161
+ base = np.asarray(base, dtype=np.float32)
162
+ target = np.asarray(target, dtype=np.float32)
163
+
164
+ rotation, error = Rotation.align_vectors(target, base)
165
+ if seq is None:
166
+ return rotation.as_matrix()
167
+ return rotation.as_euler(seq=seq, degrees=True)
168
+
169
+
170
+ def euler_to_rotationmatrix(angles: Tuple[float], seq: str = "zyz") -> NDArray:
171
+ """
172
+ Convert Euler angles to a rotation matrix.
173
+
174
+ Parameters
175
+ ----------
176
+ angles : tuple
177
+ A tuple representing the Euler angles in degrees.
178
+ seq : str, optional
179
+ Euler angle convention.
180
+
181
+ Returns
182
+ -------
183
+ NDArray
184
+ The generated rotation matrix.
185
+ """
186
+ n_angles = len(angles)
187
+ angle_convention = seq[:n_angles]
188
+ if n_angles == 1:
189
+ angles = (angles, 0, 0)
190
+ rotation_matrix = Rotation.from_euler(
191
+ seq=angle_convention, angles=angles, degrees=True
192
+ )
193
+ return rotation_matrix.as_matrix().astype(np.float32)
194
+
195
+
196
+ def euler_from_rotationmatrix(rotation_matrix: NDArray, seq: str = "zyz") -> Tuple:
197
+ """
198
+ Convert a rotation matrix to euler angles.
199
+
200
+ Parameters
201
+ ----------
202
+ rotation_matrix : NDArray
203
+ A 2 x 2 or 3 x 3 rotation matrix.
204
+ seq : str, optional
205
+ Euler angle convention, zyz by default.
206
+
207
+ Returns
208
+ -------
209
+ Tuple
210
+ The generate euler angles in degrees
211
+ """
212
+ if rotation_matrix.shape[0] == 2:
213
+ temp_matrix = np.eye(3)
214
+ temp_matrix[:2, :2] = rotation_matrix
215
+ rotation_matrix = temp_matrix
216
+
217
+ with warnings.catch_warnings():
218
+ warnings.simplefilter("ignore")
219
+ rotation = Rotation.from_matrix(rotation_matrix)
220
+ angles = rotation.as_euler(seq=seq, degrees=True).astype(np.float32)
221
+ return angles
222
+
223
+
224
+ def get_rotation_matrices(
225
+ angular_sampling: float, dim: int = 3, use_optimized_set: bool = True
226
+ ) -> NDArray:
227
+ """
228
+ Returns rotation matrices with desired ``angular_sampling`` rate.
229
+
230
+ Parameters
231
+ ----------
232
+ angular_sampling : float
233
+ The desired angular sampling in degrees.
234
+ dim : int, optional
235
+ Dimension of the rotation matrices.
236
+ use_optimized_set : bool, optional
237
+ Use optimized rotational sets, True by default and available for dim=3.
238
+
239
+ Notes
240
+ -----
241
+ For dim = 3 optimized sets are used, otherwise QR-decomposition.
242
+
243
+ Returns
244
+ -------
245
+ NDArray
246
+ Array of shape (n, d, d) containing n rotation matrices.
247
+ """
248
+ if dim == 3 and use_optimized_set:
249
+ quaternions, *_ = _load_quaternions_by_angle(angular_sampling)
250
+ ret = Rotation.from_quat(quaternions).as_matrix()
251
+ else:
252
+ num_rotations = dim * (dim - 1) // 2
253
+ k = int((360 / angular_sampling) ** num_rotations)
254
+ As = np.random.randn(k, dim, dim)
255
+ ret, _ = np.linalg.qr(As)
256
+ dets = np.linalg.det(ret)
257
+ neg_dets = dets < 0
258
+ ret[neg_dets, :, -1] *= -1
259
+ ret[0] = np.eye(dim, dtype=ret.dtype)
260
+ return ret
261
+
262
+
263
+ def _load_quaternions_by_angle(
264
+ angular_sampling: float,
265
+ ) -> Tuple[NDArray, NDArray, float]:
266
+ """
267
+ Get orientations and weights proportional to the given angular_sampling.
268
+
269
+ Parameters
270
+ ----------
271
+ angular_sampling : float
272
+ Requested angular sampling.
273
+
274
+ Returns
275
+ -------
276
+ Tuple[NDArray, NDArray, float]
277
+ Quaternions, associated weights and realized angular sampling rate.
278
+ """
279
+ # Metadata contains (N orientations, rotational sampling, coverage as values)
280
+ with open(join(dirname(__file__), "data", "metadata.yaml"), "r") as infile:
281
+ metadata = yaml.full_load(infile)
282
+
283
+ set_diffs = {
284
+ setname: abs(angular_sampling - set_angle)
285
+ for setname, (_, set_angle, _) in metadata.items()
286
+ }
287
+ fname = min(set_diffs, key=set_diffs.get)
288
+
289
+ infile = join(dirname(__file__), "data", fname)
290
+ quat_weights = np.load(infile)
291
+
292
+ quat = quat_weights[:, :4]
293
+ weights = quat_weights[:, -1]
294
+ angle = metadata[fname][0]
295
+
296
+ return quat, weights, angle
297
+
298
+
299
+ def align_to_axis(
300
+ coordinates: NDArray,
301
+ weights: NDArray = None,
302
+ axis: int = 2,
303
+ flip: bool = False,
304
+ eigenvector_index: int = 0,
305
+ ) -> NDArray:
306
+ """
307
+ Calculate a rotation matrix that aligns the principal axis of a point cloud
308
+ with a specified coordinate axis.
309
+
310
+ Parameters
311
+ ----------
312
+ coordinates : NDArray
313
+ Array of 3D coordinates with shape (n, 3) representing the point cloud.
314
+ weights : NDArray
315
+ Coordinate weighting factors with shape (n,).
316
+ axis : int, optional
317
+ The target axis to align with, defaults to 2 (z-axis).
318
+ flip : bool, optional
319
+ Whether to align with the negative direction of the axis, default is False.
320
+ eigenvector_index : int, optional
321
+ Index of eigenvector to select, sorted by descending eigenvalues.
322
+ 0 = largest eigenvalue (most variance), 1 = second largest, etc.
323
+ Default is 0 (primary principal component).
324
+
325
+ Returns
326
+ -------
327
+ NDArray
328
+ 3x3 rotation matrix that aligns the principal component of the
329
+ coordinates with the specified axis.
330
+ """
331
+ axis = int(axis)
332
+ coordinates = np.asarray(coordinates)
333
+ alignment_axis = np.array(
334
+ [0 if i != axis else 1 for i in range(coordinates.shape[1])]
335
+ )
336
+ if flip:
337
+ alignment_axis *= -1
338
+
339
+ ndim = coordinates.shape[1]
340
+ if eigenvector_index >= ndim:
341
+ raise ValueError(f"eigenvector_index has to be less than {ndim}.")
342
+
343
+ avg = np.average(coordinates, axis=0, weights=weights)
344
+ coordinates = coordinates - avg
345
+ cov_matrix = np.cov(coordinates.T, aweights=weights)
346
+
347
+ # Eigenvalues are already sorted in ascending order
348
+ eigenvalues, eigenvectors = np.linalg.eigh(cov_matrix)
349
+ eigenvector = eigenvectors[:, -(eigenvector_index + 1)]
350
+ return align_vectors(eigenvector, alignment_axis)