pytme 0.3.1.post2__cp311-cp311-macosx_15_0_arm64.whl → 0.3.2__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 (68) hide show
  1. pytme-0.3.2.data/scripts/estimate_ram_usage.py +97 -0
  2. {pytme-0.3.1.post2.data → pytme-0.3.2.data}/scripts/match_template.py +213 -196
  3. {pytme-0.3.1.post2.data → pytme-0.3.2.data}/scripts/postprocess.py +40 -78
  4. {pytme-0.3.1.post2.data → pytme-0.3.2.data}/scripts/preprocess.py +4 -5
  5. {pytme-0.3.1.post2.data → pytme-0.3.2.data}/scripts/preprocessor_gui.py +49 -103
  6. {pytme-0.3.1.post2.data → pytme-0.3.2.data}/scripts/pytme_runner.py +46 -69
  7. {pytme-0.3.1.post2.dist-info → pytme-0.3.2.dist-info}/METADATA +3 -2
  8. {pytme-0.3.1.post2.dist-info → pytme-0.3.2.dist-info}/RECORD +68 -65
  9. scripts/estimate_ram_usage.py +97 -0
  10. scripts/match_template.py +213 -196
  11. scripts/match_template_devel.py +1339 -0
  12. scripts/postprocess.py +40 -78
  13. scripts/preprocess.py +4 -5
  14. scripts/preprocessor_gui.py +49 -103
  15. scripts/pytme_runner.py +46 -69
  16. tests/preprocessing/test_compose.py +31 -30
  17. tests/preprocessing/test_frequency_filters.py +17 -32
  18. tests/preprocessing/test_preprocessor.py +0 -19
  19. tests/preprocessing/test_utils.py +13 -1
  20. tests/test_analyzer.py +2 -10
  21. tests/test_backends.py +47 -18
  22. tests/test_density.py +72 -13
  23. tests/test_extensions.py +1 -0
  24. tests/test_matching_cli.py +23 -9
  25. tests/test_matching_exhaustive.py +5 -5
  26. tests/test_matching_utils.py +3 -3
  27. tests/test_orientations.py +12 -0
  28. tests/test_rotations.py +13 -23
  29. tests/test_structure.py +1 -7
  30. tme/__version__.py +1 -1
  31. tme/analyzer/aggregation.py +47 -16
  32. tme/analyzer/base.py +34 -0
  33. tme/analyzer/peaks.py +26 -13
  34. tme/analyzer/proxy.py +14 -0
  35. tme/backends/_jax_utils.py +91 -68
  36. tme/backends/cupy_backend.py +6 -19
  37. tme/backends/jax_backend.py +103 -98
  38. tme/backends/matching_backend.py +0 -17
  39. tme/backends/mlx_backend.py +0 -29
  40. tme/backends/npfftw_backend.py +100 -97
  41. tme/backends/pytorch_backend.py +65 -78
  42. tme/cli.py +2 -2
  43. tme/density.py +44 -57
  44. tme/extensions.cpython-311-darwin.so +0 -0
  45. tme/filters/_utils.py +52 -24
  46. tme/filters/bandpass.py +99 -105
  47. tme/filters/compose.py +133 -39
  48. tme/filters/ctf.py +51 -102
  49. tme/filters/reconstruction.py +67 -122
  50. tme/filters/wedge.py +296 -325
  51. tme/filters/whitening.py +39 -75
  52. tme/mask.py +2 -2
  53. tme/matching_data.py +87 -15
  54. tme/matching_exhaustive.py +70 -120
  55. tme/matching_optimization.py +9 -63
  56. tme/matching_scores.py +261 -100
  57. tme/matching_utils.py +150 -91
  58. tme/memory.py +1 -0
  59. tme/orientations.py +17 -3
  60. tme/preprocessor.py +0 -239
  61. tme/rotations.py +102 -70
  62. tme/structure.py +601 -631
  63. tme/types.py +1 -0
  64. {pytme-0.3.1.post2.data → pytme-0.3.2.data}/scripts/estimate_memory_usage.py +0 -0
  65. {pytme-0.3.1.post2.dist-info → pytme-0.3.2.dist-info}/WHEEL +0 -0
  66. {pytme-0.3.1.post2.dist-info → pytme-0.3.2.dist-info}/entry_points.txt +0 -0
  67. {pytme-0.3.1.post2.dist-info → pytme-0.3.2.dist-info}/licenses/LICENSE +0 -0
  68. {pytme-0.3.1.post2.dist-info → pytme-0.3.2.dist-info}/top_level.txt +0 -0
tme/rotations.py CHANGED
@@ -7,7 +7,6 @@ Author: Valentin Maurer <valentin.maurer@embl-hamburg.de>
7
7
  """
8
8
 
9
9
  import yaml
10
- import warnings
11
10
  from typing import Tuple
12
11
  from os.path import join, dirname
13
12
 
@@ -68,12 +67,7 @@ def _sample_cone(
68
67
  ],
69
68
  axis=1,
70
69
  )
71
-
72
- rotation = Rotation.from_euler(
73
- angles=align_vectors((1, 0, 0), axis, seq="zyz"),
74
- seq="zyz",
75
- degrees=True,
76
- )
70
+ rotation = Rotation.from_matrix(align_vectors((1, 0, 0), axis, seq=None))
77
71
  return rotation.apply(points)
78
72
 
79
73
 
@@ -85,7 +79,7 @@ def get_cone_rotations(
85
79
  axis_sampling: float = None,
86
80
  reference: Tuple[float] = (1, 0, 0),
87
81
  n_symmetry: int = 1,
88
- seq: str = None,
82
+ **kwargs,
89
83
  ) -> NDArray:
90
84
  """
91
85
  Generate rotations describing the possible placements of a vector in a cone.
@@ -108,14 +102,17 @@ def get_cone_rotations(
108
102
  the principal axis of the template.
109
103
  n_symmetry : int, optional
110
104
  Number of symmetry axis around the vector axis.
111
- seq : str, optional
112
- Convention for angles. By default returns rotation matrices.
105
+ seq : str
106
+ Output convention.
107
+
108
+ .. deprecated:: 0.3.2
109
+
110
+ Returns rotation matrices always.
113
111
 
114
112
  Returns
115
113
  -------
116
114
  NDArray
117
- An arary of rotations represented as stack of rotation matrices when convention
118
- None (n, 3, 3) or an array of Euler angles (n, 3) for available conventions.
115
+ An arary of rotations represented as stack of rotation matrices (n, 3, 3).
119
116
  """
120
117
  if axis_sampling is None:
121
118
  axis_sampling = cone_sampling
@@ -133,17 +130,13 @@ def get_cone_rotations(
133
130
  axis_rotation * Rotation.from_matrix(align_vectors(reference, x))
134
131
  for x in points
135
132
  ]
133
+ return Rotation.concatenate(all_rotations).as_matrix()
136
134
 
137
- rotations = Rotation.concatenate(all_rotations)
138
- if seq is None:
139
- return rotations.as_matrix()
140
135
 
141
- return rotations.as_euler(seq=seq, degrees=True)
142
-
143
-
144
- def align_vectors(base: NDArray, target: NDArray = (0, 0, 1), seq: str = None):
136
+ def align_vectors(base: NDArray, target: NDArray = (0, 0, 1), **kwargs) -> NDArray:
145
137
  """
146
- Compute the rotation matrix or Euler angles required to align an initial vector with a target vector.
138
+ Compute the rotation matrix or Euler angles required to align an initial
139
+ vector with a target vector.
147
140
 
148
141
  Parameters
149
142
  ----------
@@ -151,77 +144,59 @@ def align_vectors(base: NDArray, target: NDArray = (0, 0, 1), seq: str = None):
151
144
  The basis vector.
152
145
  target : NDArray, optional
153
146
  The vector to map base to, defaults to (0,0,1).
154
- seq : str, optional
155
- Euler angle convention, None returns a rotation matrix instead.
147
+ seq : str
148
+ Output convention.
149
+
150
+ .. deprecated:: 0.3.2
151
+
152
+ Returns rotation matrices always.
156
153
 
157
154
  Returns
158
155
  -------
159
156
  NDArray
160
- Rotation matrix if seq is None otherwise Euler angles in desired convention
157
+ Rotation matrix mapping base to target.
161
158
  """
162
- base = np.asarray(base, dtype=np.float32)
163
- target = np.asarray(target, dtype=np.float32)
164
-
165
- rotation, error = Rotation.align_vectors(target, base)
166
- if seq is None:
167
- return rotation.as_matrix()
168
- return rotation.as_euler(seq=seq, degrees=True)
159
+ rotation, _ = Rotation.align_vectors(target, base)
160
+ return rotation.as_matrix().astype(np.float32)
169
161
 
170
162
 
171
- def euler_to_rotationmatrix(angles: Tuple[float], seq: str = "zyz") -> NDArray:
163
+ def euler_to_rotationmatrix(angles: Tuple[float], seq: str = "ZYZ") -> NDArray:
172
164
  """
173
165
  Convert Euler angles to a rotation matrix.
174
166
 
175
167
  Parameters
176
168
  ----------
177
169
  angles : tuple
178
- A tuple representing the Euler angles in degrees.
170
+ Euler angles in degrees.
179
171
  seq : str, optional
180
- Euler angle convention.
172
+ Euler angle convention, defaults to ZYZ.
181
173
 
182
174
  Returns
183
175
  -------
184
176
  NDArray
185
- The generated rotation matrix.
177
+ Corresponding rotation matrix.
186
178
  """
187
- angles = np.asarray(angles)
188
-
189
- n_angles = len(angles)
190
- if angles.ndim == 2:
191
- n_angles = angles.shape[1]
192
-
193
- rotation_matrix = Rotation.from_euler(
194
- seq=seq[:n_angles], angles=angles, degrees=True
195
- )
196
- return rotation_matrix.as_matrix().astype(np.float32)
179
+ rotation = Rotation.from_euler(seq=seq, angles=angles, degrees=True)
180
+ return rotation.as_matrix().astype(np.float32)
197
181
 
198
182
 
199
- def euler_from_rotationmatrix(rotation_matrix: NDArray, seq: str = "zyz") -> Tuple:
183
+ def euler_from_rotationmatrix(rotation_matrix: NDArray, seq: str = "ZYZ") -> NDArray:
200
184
  """
201
- Convert a rotation matrix to euler angles.
185
+ Convert a rotation matrix to Euler angles.
202
186
 
203
187
  Parameters
204
188
  ----------
205
189
  rotation_matrix : NDArray
206
- A 2 x 2 or 3 x 3 rotation matrix.
190
+ Rotation matrix (d,d).
207
191
  seq : str, optional
208
- Euler angle convention, zyz by default.
192
+ Euler angle convention, default to intrinsic ZYZ.
209
193
 
210
194
  Returns
211
195
  -------
212
- Tuple
213
- The generate euler angles in degrees
196
+ NDArray
197
+ Corresponding Euler angles in degrees.
214
198
  """
215
- if rotation_matrix.shape[0] == 2:
216
- temp_matrix = np.eye(3)
217
- temp_matrix[:2, :2] = rotation_matrix
218
- rotation_matrix = temp_matrix
219
-
220
- with warnings.catch_warnings():
221
- warnings.simplefilter("ignore")
222
- rotation = Rotation.from_matrix(rotation_matrix)
223
- angles = rotation.as_euler(seq=seq, degrees=True).astype(np.float32)
224
- return angles
199
+ return Rotation.from_matrix(rotation_matrix).as_euler(seq=seq, degrees=True)
225
200
 
226
201
 
227
202
  def get_rotation_matrices(
@@ -250,16 +225,16 @@ def get_rotation_matrices(
250
225
  """
251
226
  if dim == 3 and use_optimized_set:
252
227
  quaternions, *_ = _load_quaternions_by_angle(angular_sampling)
253
- ret = Rotation.from_quat(quaternions, scalar_first=True).as_matrix()
254
- else:
255
- num_rotations = dim * (dim - 1) // 2
256
- k = int((360 / angular_sampling) ** num_rotations)
257
- As = np.random.randn(k, dim, dim)
258
- ret, _ = np.linalg.qr(As)
259
- dets = np.linalg.det(ret)
260
- neg_dets = dets < 0
261
- ret[neg_dets, :, -1] *= -1
262
- ret[0] = np.eye(dim, dtype=ret.dtype)
228
+ return Rotation.from_quat(quaternions, scalar_first=True).as_matrix()
229
+
230
+ num_rotations = dim * (dim - 1) // 2
231
+ k = int((360 / angular_sampling) ** num_rotations)
232
+ As = np.random.randn(k, dim, dim)
233
+ ret, _ = np.linalg.qr(As)
234
+ dets = np.linalg.det(ret)
235
+ neg_dets = dets < 0
236
+ ret[neg_dets, :, -1] *= -1
237
+ ret[0] = np.eye(dim, dtype=ret.dtype)
263
238
  return ret
264
239
 
265
240
 
@@ -351,3 +326,60 @@ def align_to_axis(
351
326
  eigenvalues, eigenvectors = np.linalg.eigh(cov_matrix)
352
327
  eigenvector = eigenvectors[:, -(eigenvector_index + 1)]
353
328
  return align_vectors(eigenvector, alignment_axis)
329
+
330
+
331
+ def get_symmetry_matrices(
332
+ symmetry_type: str, axis: Tuple[float] = (0, 0, 1)
333
+ ) -> NDArray:
334
+ """
335
+ Generate rotation matrices for common point group symmetries.
336
+
337
+ Parameters
338
+ ----------
339
+ symmetry_type : str
340
+ Type of symmetry. Supported: 'C1', 'C2', 'C3', 'C4', 'C5', 'C6', 'D2', 'D3', 'D4'
341
+ axis : Tuple[float], optional
342
+ Symmetry axis as (x, y, z) vector, defaults to (0, 0, 1) for Z-axis.
343
+
344
+ Returns
345
+ -------
346
+ NDArray
347
+ Array of rotation matrices with shape (n, 3, 3).
348
+
349
+ """
350
+ axis = np.array(axis, dtype=np.float32)
351
+ axis = axis / np.linalg.norm(axis)
352
+
353
+ try:
354
+ n = int(symmetry_type[1:])
355
+ except IndexError:
356
+ n = 1
357
+
358
+ matrices = []
359
+ symmetry = symmetry_type.upper()[0]
360
+ if symmetry == "C":
361
+
362
+ for i in range(n):
363
+ angle = 2 * np.pi * i / n
364
+ R = Rotation.from_rotvec(angle * axis)
365
+ matrices.append(R.as_matrix().astype(np.float32))
366
+
367
+ elif symmetry == "D":
368
+ # First add the Cn rotations around main axis
369
+ matrices.extend(get_symmetry_matrices(f"C{n}", axis=axis))
370
+
371
+ # Then add n 180° rotations around perpendicular axes
372
+ _, _, vh = np.linalg.svd(axis.reshape(1, -1))
373
+
374
+ perp = vh[-1].astype(np.float32)
375
+ perp = perp / np.linalg.norm(perp)
376
+ for i in range(n):
377
+ angle = 2 * np.pi * i / n
378
+ R = Rotation.from_rotvec(angle * axis)
379
+
380
+ R_180 = Rotation.from_rotvec(np.pi * R.apply(perp))
381
+ matrices.append(R_180.as_matrix().astype(np.float32))
382
+ else:
383
+ raise ValueError(f"Unsupported symmetry type: {symmetry_type}")
384
+
385
+ return np.array(matrices)