pytme 0.2.0__cp311-cp311-macosx_14_0_arm64.whl → 0.2.1__cp311-cp311-macosx_14_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 (40) hide show
  1. {pytme-0.2.0.data → pytme-0.2.1.data}/scripts/match_template.py +183 -69
  2. {pytme-0.2.0.data → pytme-0.2.1.data}/scripts/postprocess.py +107 -49
  3. {pytme-0.2.0.data → pytme-0.2.1.data}/scripts/preprocessor_gui.py +4 -1
  4. {pytme-0.2.0.dist-info → pytme-0.2.1.dist-info}/METADATA +1 -1
  5. pytme-0.2.1.dist-info/RECORD +73 -0
  6. scripts/extract_candidates.py +117 -85
  7. scripts/match_template.py +183 -69
  8. scripts/match_template_filters.py +193 -71
  9. scripts/postprocess.py +107 -49
  10. scripts/preprocessor_gui.py +4 -1
  11. scripts/refine_matches.py +364 -160
  12. tme/__version__.py +1 -1
  13. tme/analyzer.py +259 -117
  14. tme/backends/__init__.py +1 -0
  15. tme/backends/cupy_backend.py +20 -13
  16. tme/backends/jax_backend.py +218 -0
  17. tme/backends/matching_backend.py +25 -10
  18. tme/backends/mlx_backend.py +13 -9
  19. tme/backends/npfftw_backend.py +20 -8
  20. tme/backends/pytorch_backend.py +20 -9
  21. tme/density.py +79 -60
  22. tme/extensions.cpython-311-darwin.so +0 -0
  23. tme/matching_data.py +85 -61
  24. tme/matching_exhaustive.py +222 -129
  25. tme/matching_optimization.py +117 -76
  26. tme/orientations.py +175 -55
  27. tme/preprocessing/_utils.py +17 -5
  28. tme/preprocessing/composable_filter.py +2 -1
  29. tme/preprocessing/compose.py +1 -2
  30. tme/preprocessing/frequency_filters.py +97 -41
  31. tme/preprocessing/tilt_series.py +137 -87
  32. tme/preprocessor.py +3 -0
  33. tme/structure.py +4 -1
  34. pytme-0.2.0.dist-info/RECORD +0 -72
  35. {pytme-0.2.0.data → pytme-0.2.1.data}/scripts/estimate_ram_usage.py +0 -0
  36. {pytme-0.2.0.data → pytme-0.2.1.data}/scripts/preprocess.py +0 -0
  37. {pytme-0.2.0.dist-info → pytme-0.2.1.dist-info}/LICENSE +0 -0
  38. {pytme-0.2.0.dist-info → pytme-0.2.1.dist-info}/WHEEL +0 -0
  39. {pytme-0.2.0.dist-info → pytme-0.2.1.dist-info}/entry_points.txt +0 -0
  40. {pytme-0.2.0.dist-info → pytme-0.2.1.dist-info}/top_level.txt +0 -0
@@ -20,11 +20,14 @@ from ._utils import (
20
20
  compute_tilt_shape,
21
21
  crop_real_fourier,
22
22
  centered_grid,
23
- fftfreqn
23
+ fftfreqn,
24
+ shift_fourier,
24
25
  )
25
26
 
26
27
 
27
- def create_reconstruction_filter(filter_shape : Tuple[int], filter_type : str):
28
+ def create_reconstruction_filter(
29
+ filter_shape: Tuple[int], filter_type: str, **kwargs: Dict
30
+ ):
28
31
  """Create a reconstruction filter of given filter_type.
29
32
 
30
33
  Parameters
@@ -32,20 +35,25 @@ def create_reconstruction_filter(filter_shape : Tuple[int], filter_type : str):
32
35
  filter_shape : tuple of int
33
36
  Shape of the returned filter
34
37
  filter_type: str
35
- The type of created filter, available options include:
38
+ The type of created filter, available options are:
36
39
 
37
40
  +---------------+----------------------------------------------------+
38
- | 'ram-lak' | Returns |w| |
41
+ | ram-lak | Returns |w| |
39
42
  +---------------+----------------------------------------------------+
40
- | 'ramp' | Principles of Computerized Tomographic Imaging Avin|
43
+ | ramp-cont | Principles of Computerized Tomographic Imaging Avin|
41
44
  | | ash C. Kak and Malcolm Slaney Chap 3 Eq. 61 [1]_ |
42
45
  +---------------+----------------------------------------------------+
43
- | 'shepp-logan' | |w| * sinc(|w| / 2) [2]_ |
46
+ | ramp | Like ramp-cont but considering tilt angles |
44
47
  +---------------+----------------------------------------------------+
45
- | 'cosine' | |w| * cos(|w| * pi / 2) [2]_ |
48
+ | shepp-logan | |w| * sinc(|w| / 2) [2]_ |
46
49
  +---------------+----------------------------------------------------+
47
- | 'hamming' | |w| * (.54 + .46 ( cos(|w| * pi))) [2]_ |
50
+ | cosine | |w| * cos(|w| * pi / 2) [2]_ |
48
51
  +---------------+----------------------------------------------------+
52
+ | hamming | |w| * (.54 + .46 ( cos(|w| * pi))) [2]_ |
53
+ +---------------+----------------------------------------------------+
54
+
55
+ kwargs: Dict
56
+ Keyword arguments for particular filter_types.
49
57
 
50
58
  Returns
51
59
  -------
@@ -58,11 +66,11 @@ def create_reconstruction_filter(filter_shape : Tuple[int], filter_type : str):
58
66
  .. [2] https://odlgroup.github.io/odl/index.html
59
67
  """
60
68
  filter_type = str(filter_type).lower()
61
- freq = fftfreqn(filter_shape, sampling_rate = .5, compute_euclidean_norm = True)
69
+ freq = fftfreqn(filter_shape, sampling_rate=0.5, compute_euclidean_norm=True)
62
70
 
63
- if filter_type == 'ram-lak':
71
+ if filter_type == "ram-lak":
64
72
  ret = np.copy(freq)
65
- elif filter_type == "ramp":
73
+ elif filter_type == "ramp-cont":
66
74
  ret, ndim = None, len(filter_shape)
67
75
  for dim, size in enumerate(filter_shape):
68
76
  n = np.concatenate(
@@ -81,20 +89,38 @@ def create_reconstruction_filter(filter_shape : Tuple[int], filter_type : str):
81
89
  else:
82
90
  ret = ret * ret1d
83
91
  ret = 2 * np.real(np.fft.fftn(ret))
84
- elif filter_type == 'shepp-logan':
92
+ elif filter_type == "ramp":
93
+ tilt_angles = kwargs.get("tilt_angles", False)
94
+ if tilt_angles is False:
95
+ raise ValueError("'ramp' filter requires specifying tilt angles.")
96
+ size, odd = filter_shape[0], filter_shape[0] % 2
97
+ ret = np.arange(-size // 2 + odd, size // 2 + odd, 1, dtype=np.float32)
98
+ ret /= size // 2
99
+ ret *= 0.5
100
+ np.abs(ret, out=ret)
101
+
102
+ min_increment = np.radians(np.min(np.abs(np.diff(np.sort(tilt_angles)))))
103
+ ret *= min_increment * size
104
+ np.fmin(ret, 1, out=ret)
105
+
106
+ ret = np.tile(ret[:, np.newaxis], (1, filter_shape[1]))
107
+
108
+ elif filter_type == "shepp-logan":
85
109
  ret = freq * np.sinc(freq / 2)
86
- elif filter_type == 'cosine':
110
+ elif filter_type == "cosine":
87
111
  ret = freq * np.cos(freq * np.pi / 2)
88
- elif filter_type == 'hamming':
112
+ elif filter_type == "hamming":
89
113
  ret = freq * (0.54 + 0.46 * np.cos(freq * np.pi))
90
114
  else:
91
115
  raise ValueError("Unsupported filter type")
92
116
 
93
117
  return ret
94
118
 
119
+
95
120
  @dataclass
96
121
  class ReconstructFromTilt:
97
122
  """Reconstruct a volume from a tilt series."""
123
+
98
124
  #: Shape of the reconstruction.
99
125
  shape: Tuple[int] = None
100
126
  #: Angle of each individual tilt.
@@ -111,7 +137,7 @@ class ReconstructFromTilt:
111
137
  reconstruction_filter: str = None
112
138
 
113
139
  def __call__(self, **kwargs):
114
- func_args = vars(self)
140
+ func_args = vars(self).copy()
115
141
  func_args.update(kwargs)
116
142
 
117
143
  ret = self.reconstruct(**func_args)
@@ -135,11 +161,11 @@ class ReconstructFromTilt:
135
161
  tilt_axis: int,
136
162
  interpolation_order: int = 1,
137
163
  return_real_fourier: bool = True,
138
- reconstruction_filter:str = None,
164
+ reconstruction_filter: str = None,
139
165
  **kwargs,
140
166
  ):
141
167
  """
142
- Reconstruct the volume from tilt series.
168
+ Reconstruct a volume from a tilt series.
143
169
 
144
170
  Parameters:
145
171
  -----------
@@ -156,7 +182,7 @@ class ReconstructFromTilt:
156
182
  interpolation_order : int, optional
157
183
  Interpolation order used for rotation, defautls to 1.
158
184
  return_real_fourier : bool, optional
159
- Whether to return a share compliant with rfftn, defaults to True.
185
+ Whether to return a shape compliant with rfftn, defaults to True.
160
186
  reconstruction_filter : bool, optional
161
187
  Filter window applied during reconstruction.
162
188
  See :py:meth:`create_reconstruction_filter` for available options.
@@ -170,11 +196,13 @@ class ReconstructFromTilt:
170
196
  return data
171
197
 
172
198
  data = backend.to_backend_array(data)
173
- volume_temp = backend.zeros(shape, dtype=backend._default_dtype)
174
- volume_temp_rotated = backend.zeros(shape, dtype=backend._default_dtype)
175
- volume = backend.zeros(shape, dtype=backend._default_dtype)
199
+ volume_temp = backend.zeros(shape, dtype=backend._float_dtype)
200
+ volume_temp_rotated = backend.zeros(shape, dtype=backend._float_dtype)
201
+ volume = backend.zeros(shape, dtype=backend._float_dtype)
176
202
 
177
- slices = tuple(slice(a, a + 1) for a in backend.divide(shape, 2).astype(int))
203
+ slices = tuple(
204
+ slice(a, a + 1) for a in backend.astype(backend.divide(shape, 2), int)
205
+ )
178
206
  subset = tuple(
179
207
  slice(None) if i != opening_axis else slices[opening_axis]
180
208
  for i in range(len(shape))
@@ -187,9 +215,19 @@ class ReconstructFromTilt:
187
215
  rec_filter = 1
188
216
  if reconstruction_filter is not None:
189
217
  rec_filter = create_reconstruction_filter(
190
- filter_type = reconstruction_filter,
191
- filter_shape = tuple(x for x in wedges[0].shape if x != 1)
218
+ filter_type=reconstruction_filter,
219
+ filter_shape=tuple(x for x in wedges[0].shape if x != 1),
220
+ tilt_angles=angles,
192
221
  )
222
+ if tilt_axis > 0:
223
+ rec_filter = rec_filter.T
224
+
225
+ # This is most likely an upstream bug
226
+ if tilt_axis == 1 and opening_axis == 0:
227
+ rec_filter = rec_filter.T
228
+
229
+ rec_filter = backend.to_backend_array(rec_filter)
230
+ rec_filter = backend.reshape(rec_filter, wedges[0].shape)
193
231
 
194
232
  for index in range(len(angles)):
195
233
  backend.fill(angles_loop, 0)
@@ -199,7 +237,7 @@ class ReconstructFromTilt:
199
237
  volume_temp[subset] = wedges[index] * rec_filter
200
238
 
201
239
  angles_loop[tilt_axis] = angles[index]
202
- angles_loop = backend.roll(angles_loop, opening_axis - 1, axis=0)
240
+ angles_loop = backend.roll(angles_loop, (opening_axis - 1,), axis=0)
203
241
  rotation_matrix = euler_to_rotationmatrix(
204
242
  backend.to_numpy_array(angles_loop)
205
243
  )
@@ -214,11 +252,7 @@ class ReconstructFromTilt:
214
252
  )
215
253
  backend.add(volume, volume_temp_rotated, out=volume)
216
254
 
217
- shift = backend.add(
218
- backend.astype(backend.divide(volume.shape, 2), int),
219
- backend.mod(volume.shape, 2),
220
- )
221
- volume = backend.roll(volume, shift, tuple(i for i in range(len(shift))))
255
+ volume = shift_fourier(data=volume, shape_is_real_fourier=False)
222
256
 
223
257
  if return_real_fourier:
224
258
  volume = crop_real_fourier(volume)
@@ -333,7 +367,7 @@ class Wedge:
333
367
  return ret
334
368
 
335
369
  def __call__(self, **kwargs: Dict) -> NDArray:
336
- func_args = vars(self)
370
+ func_args = vars(self).copy()
337
371
  func_args.update(kwargs)
338
372
 
339
373
  weight_types = {
@@ -353,10 +387,7 @@ class Wedge:
353
387
  func_args["weights"] = np.cos(np.radians(self.angles))
354
388
 
355
389
  ret = weight_types[weight_type](**func_args)
356
- ret = backend.astype(
357
- backend.to_backend_array(ret),
358
- backend._default_dtype
359
- )
390
+ ret = backend.astype(backend.to_backend_array(ret), backend._float_dtype)
360
391
 
361
392
  return {
362
393
  "data": ret,
@@ -374,7 +405,6 @@ class Wedge:
374
405
  angles: Tuple[float],
375
406
  opening_axis: int,
376
407
  tilt_axis: int,
377
- frequency_cutoff: float = 0.5,
378
408
  **kwargs,
379
409
  ) -> NDArray:
380
410
  """
@@ -386,14 +416,6 @@ class Wedge:
386
416
  wedge, wedges = np.ones(tilt_shape), np.zeros((len(angles), *tilt_shape))
387
417
  for index, angle in enumerate(angles):
388
418
  wedge.fill(weights[index])
389
- frequency_grid = frequency_grid_at_angle(
390
- shape=shape,
391
- opening_axis=opening_axis,
392
- tilt_axis=tilt_axis,
393
- angle=angle,
394
- sampling_rate=1,
395
- )
396
- np.multiply(wedge, frequency_grid <= frequency_cutoff, out=wedge)
397
419
  wedges[index] = wedge
398
420
 
399
421
  return wedges
@@ -422,7 +444,7 @@ class Wedge:
422
444
  angle=angle,
423
445
  sampling_rate=1,
424
446
  )
425
- frequency_mask = frequency_grid <= self.frequency_cutoff
447
+ # frequency_mask = frequency_grid <= self.frequency_cutoff
426
448
 
427
449
  sigma = np.sqrt(self.weights[index] * 4 / (8 * np.pi**2))
428
450
  sigma = -2 * np.pi**2 * sigma**2
@@ -430,7 +452,7 @@ class Wedge:
430
452
  np.multiply(sigma, frequency_grid, out=frequency_grid)
431
453
  np.exp(frequency_grid, out=frequency_grid)
432
454
  np.multiply(frequency_grid, np.cos(np.radians(angle)), out=frequency_grid)
433
- np.multiply(frequency_grid, frequency_mask, out=frequency_grid)
455
+ # np.multiply(frequency_grid, frequency_mask, out=frequency_grid)
434
456
 
435
457
  wedges[index] = frequency_grid
436
458
 
@@ -456,10 +478,12 @@ class Wedge:
456
478
  .. [1] Timothy GrantNikolaus Grigorieff (2015), eLife 4:e06980.
457
479
  """
458
480
  tilt_shape = compute_tilt_shape(
459
- shape=self.shape, opening_axis=self.opening_axis, reduce_dim=True,
481
+ shape=self.shape,
482
+ opening_axis=self.opening_axis,
483
+ reduce_dim=True,
460
484
  )
461
485
 
462
- wedges = np.zeros((len(self.angles), *tilt_shape), dtype=backend._default_dtype)
486
+ wedges = np.zeros((len(self.angles), *tilt_shape), dtype=backend._float_dtype)
463
487
  for index, angle in enumerate(self.angles):
464
488
  frequency_grid = frequency_grid_at_angle(
465
489
  shape=self.shape,
@@ -468,13 +492,13 @@ class Wedge:
468
492
  angle=angle,
469
493
  sampling_rate=1,
470
494
  )
471
- frequency_mask = frequency_grid <= self.frequency_cutoff
495
+ # frequency_mask = frequency_grid <= self.frequency_cutoff
472
496
 
473
497
  with np.errstate(divide="ignore"):
474
- np.power(frequency_grid, power, out = frequency_grid)
475
- np.multiply(amplitude, frequency_grid, out = frequency_grid)
476
- np.add(frequency_grid, offset, out = frequency_grid)
477
- np.multiply(-2, frequency_grid, out = frequency_grid)
498
+ np.power(frequency_grid, power, out=frequency_grid)
499
+ np.multiply(amplitude, frequency_grid, out=frequency_grid)
500
+ np.add(frequency_grid, offset, out=frequency_grid)
501
+ np.multiply(-2, frequency_grid, out=frequency_grid)
478
502
  np.divide(
479
503
  self.weights[index],
480
504
  frequency_grid,
@@ -482,7 +506,7 @@ class Wedge:
482
506
  )
483
507
 
484
508
  np.exp(frequency_grid, out=frequency_grid)
485
- np.multiply(frequency_grid, frequency_mask, out=frequency_grid)
509
+ # np.multiply(frequency_grid, frequency_mask, out=frequency_grid)
486
510
 
487
511
  wedges[index] = frequency_grid
488
512
 
@@ -512,8 +536,8 @@ class WedgeReconstructed:
512
536
  stop_tilt: float = None,
513
537
  opening_axis: int = 0,
514
538
  tilt_axis: int = 2,
515
- weight_wedge : bool = False,
516
- create_continuous_wedge : bool = False,
539
+ weight_wedge: bool = False,
540
+ create_continuous_wedge: bool = False,
517
541
  **kwargs: Dict,
518
542
  ):
519
543
  self.angles = angles
@@ -538,7 +562,7 @@ class WedgeReconstructed:
538
562
  Dict
539
563
  A dictionary containing the reconstructed wedge and related information.
540
564
  """
541
- func_args = vars(self)
565
+ func_args = vars(self).copy()
542
566
  func_args.update(kwargs)
543
567
 
544
568
  if kwargs.get("is_fourier_shape", False):
@@ -549,10 +573,7 @@ class WedgeReconstructed:
549
573
  func = self.continuous_wedge
550
574
 
551
575
  ret = func(shape=shape, **func_args)
552
- ret = backend.astype(
553
- backend.to_backend_array(ret),
554
- backend._default_dtype
555
- )
576
+ ret = backend.astype(backend.to_backend_array(ret), backend._float_dtype)
556
577
 
557
578
  return {
558
579
  "data": ret,
@@ -561,7 +582,7 @@ class WedgeReconstructed:
561
582
  "tilt_axis": func_args["tilt_axis"],
562
583
  "opening_axis": func_args["opening_axis"],
563
584
  "is_multiplicative_filter": True,
564
- "angles" : func_args["angles"],
585
+ "angles": func_args["angles"],
565
586
  }
566
587
 
567
588
  @staticmethod
@@ -678,7 +699,7 @@ class CTF:
678
699
  #: The defocus value in x direction.
679
700
  defocus_x: float
680
701
  #: The tilt angles.
681
- angles: Tuple[float]
702
+ angles: Tuple[float] = None
682
703
  #: The axis around which the wedge is opened, defaults to None.
683
704
  opening_axis: int = None
684
705
  #: The axis along which the tilt is applied, defaults to None.
@@ -689,8 +710,8 @@ class CTF:
689
710
  sampling_rate: Tuple[float] = 1
690
711
  #: The acceleration voltage in Volts, defaults to 300e3.
691
712
  acceleration_voltage: float = 300e3
692
- #: The spherical aberration coefficient, defaults to 2.7e3.
693
- spherical_aberration: float = 2.7e3
713
+ #: The spherical aberration coefficient, defaults to 2.7e7.
714
+ spherical_aberration: float = 2.7e7
694
715
  #: The amplitude contrast, defaults to 0.07.
695
716
  amplitude_contrast: float = 0.07
696
717
  #: The phase shift, defaults to 0.
@@ -699,6 +720,10 @@ class CTF:
699
720
  defocus_angle: float = 0
700
721
  #: The defocus value in y direction, defaults to None.
701
722
  defocus_y: float = None
723
+ #: Whether the returned CTF should be phase-flipped.
724
+ flip_phase: bool = True
725
+ #: Whether to return a format compliant with rfft. Only relevant for single angles.
726
+ return_real_fourier: bool = False
702
727
 
703
728
  @classmethod
704
729
  def from_file(cls, filename: str) -> "CTF":
@@ -811,7 +836,6 @@ class CTF:
811
836
  "defocus_x",
812
837
  "defocus_y",
813
838
  ]
814
-
815
839
  if "sampling_rate" in kwargs:
816
840
  self.sampling_rate = kwargs["sampling_rate"]
817
841
 
@@ -819,19 +843,22 @@ class CTF:
819
843
  kwargs["electron_wavelength"] = self._compute_electron_wavelength()
820
844
 
821
845
  for key, value in kwargs.items():
822
- if key in voxel_based:
823
- value = value / self.sampling_rate
846
+ if key in voxel_based and value is not None:
847
+ value = np.divide(value, np.max(self.sampling_rate))
824
848
  setattr(self, key, value)
825
849
 
826
850
  def __call__(self, **kwargs) -> NDArray:
827
- func_args = vars(self)
851
+ func_args = vars(self).copy()
828
852
  func_args.update(kwargs)
829
853
 
854
+ if len(func_args["angles"]) != len(func_args["defocus_x"]):
855
+ func_args["angles"] = self.angles
856
+ func_args["return_real_fourier"] = False
857
+ func_args["tilt_axis"] = None
858
+ func_args["opening_axis"] = None
859
+
830
860
  ret = self.weight(**func_args)
831
- ret = backend.astype(
832
- backend.to_backend_array(ret),
833
- backend._default_dtype
834
- )
861
+ ret = backend.astype(backend.to_backend_array(ret), backend._float_dtype)
835
862
  return {
836
863
  "data": ret,
837
864
  "angles": func_args["angles"],
@@ -856,6 +883,8 @@ class CTF:
856
883
  sampling_rate: Tuple[float] = 1,
857
884
  acceleration_voltage: float = 300e3,
858
885
  spherical_aberration: float = 2.7e3,
886
+ flip_phase: bool = True,
887
+ return_real_fourier: bool = False,
859
888
  **kwargs: Dict,
860
889
  ) -> NDArray:
861
890
  """
@@ -891,6 +920,8 @@ class CTF:
891
920
  The acceleration voltage in electron microscopy, defaults to 300e3.
892
921
  spherical_aberration : float, optional
893
922
  The spherical aberration coefficient, defaults to 2.7e3.
923
+ flip_phase : bool, optional
924
+ Whether the returned CTF should be phase-flipped.
894
925
  **kwargs : Dict
895
926
  Additional keyword arguments.
896
927
 
@@ -899,21 +930,31 @@ class CTF:
899
930
  NDArray
900
931
  A stack containing the CTF weight.
901
932
  """
933
+ defoci_x = np.atleast_1d(defocus_x)
934
+ defoci_y = np.atleast_1d(defocus_y)
935
+ phase_shift = np.atleast_1d(phase_shift)
936
+ angles = np.atleast_1d(angles)
937
+ defocus_angle = np.atleast_1d(defocus_angle)
938
+
939
+ sampling_rate = np.max(sampling_rate)
902
940
  tilt_shape = compute_tilt_shape(
903
941
  shape=shape, opening_axis=opening_axis, reduce_dim=True
904
942
  )
905
943
  stack = np.zeros((len(angles), *tilt_shape))
906
- electron_wavelength = self._compute_electron_wavelength()
907
- defoci_x = defocus_x
908
- defoci_y = defocus_y
944
+ electron_wavelength = self._compute_electron_wavelength() / sampling_rate
945
+
946
+ correct_defocus_gradient &= len(shape) == 3
947
+ correct_defocus_gradient &= tilt_axis is not None
948
+ correct_defocus_gradient &= opening_axis is not None
949
+
909
950
  for index, angle in enumerate(angles):
910
- grid = centered_grid(shape=tilt_shape)
911
- grid = np.divide(grid.T, (sampling_rate, sampling_rate)).T
951
+ grid = backend.to_numpy_array(centered_grid(shape=tilt_shape))
952
+ grid = np.divide(grid.T, sampling_rate).T
912
953
 
913
954
  defocus_x, defocus_y = defoci_x[index], defoci_y[index]
914
955
 
915
956
  # This should be done after defocus_x computation
916
- if correct_defocus_gradient and len(shape) == 3:
957
+ if correct_defocus_gradient:
917
958
  angle_rad = np.radians(angle)
918
959
 
919
960
  defocus_gradient = np.multiply(grid[1], np.sin(angle_rad))
@@ -923,13 +964,9 @@ class CTF:
923
964
  )[0]
924
965
 
925
966
  if tilt_axis > remaining_axis:
926
- defocus_x = np.add(
927
- defocus_x, np.multiply(defocus_gradient, np.sin(angle_rad))
928
- )
967
+ defocus_x = np.add(defocus_x, defocus_gradient)
929
968
  elif tilt_axis < remaining_axis and defocus_y is not None:
930
- defocus_y = np.add(
931
- defocus_y, np.multiply(defocus_gradient.T, np.sin(angle_rad))
932
- )
969
+ defocus_y = np.add(defocus_y, defocus_gradient.T)
933
970
 
934
971
  if defocus_y is not None:
935
972
  defocus_sum = np.add(defocus_x, defocus_y)
@@ -946,10 +983,10 @@ class CTF:
946
983
  angle=angle,
947
984
  sampling_rate=1,
948
985
  )
949
-
986
+ frequency_grid *= frequency_grid <= 0.5
950
987
  np.square(frequency_grid, out=frequency_grid)
951
- electron_aberration = spherical_aberration * electron_wavelength**2
952
988
 
989
+ electron_aberration = spherical_aberration * electron_wavelength**2
953
990
  chi = defocus_x - 0.5 * electron_aberration * frequency_grid
954
991
  np.multiply(chi, np.pi * electron_wavelength, out=chi)
955
992
  np.multiply(chi, frequency_grid, out=chi)
@@ -964,4 +1001,17 @@ class CTF:
964
1001
  np.sin(-chi, out=chi)
965
1002
  stack[index] = chi
966
1003
 
1004
+ if flip_phase:
1005
+ np.abs(stack, out=stack)
1006
+
1007
+ np.negative(stack, out=stack)
1008
+ stack = np.squeeze(stack)
1009
+
1010
+ stack = backend.to_backend_array(stack)
1011
+
1012
+ if len(angles) == 1:
1013
+ stack = shift_fourier(data=stack, shape_is_real_fourier=False)
1014
+ if return_real_fourier:
1015
+ stack = crop_real_fourier(stack)
1016
+
967
1017
  return stack
tme/preprocessor.py CHANGED
@@ -1191,6 +1191,9 @@ class Preprocessor:
1191
1191
  if tilt_angles is None:
1192
1192
  tilt_angles = np.arange(-start_tilt, stop_tilt + tilt_step, tilt_step)
1193
1193
 
1194
+ shape = tuple(int(x) for x in shape)
1195
+ opening_axis, tilt_axis = int(opening_axis), int(tilt_axis)
1196
+
1194
1197
  weights = np.asarray(weights)
1195
1198
  weights = np.repeat(weights, tilt_angles.size // weights.size)
1196
1199
  plane = np.zeros((shape[opening_axis], shape[tilt_axis]), dtype=np.float32)
tme/structure.py CHANGED
@@ -480,7 +480,6 @@ class Structure:
480
480
  filename : str
481
481
  The filename of the file to write.
482
482
  """
483
- data_out = []
484
483
  if np.any(np.vectorize(len)(self.chain_identifier) > 2):
485
484
  warnings.warn("Chain identifiers longer than one will be shortened.")
486
485
 
@@ -612,6 +611,9 @@ class Structure:
612
611
 
613
612
  ret = ""
614
613
  for category, subdict in output_data.items():
614
+ if not len(subdict):
615
+ continue
616
+
615
617
  ret += "#\n"
616
618
  is_loop = isinstance(subdict[list(subdict.keys())[0]], list)
617
619
  if not is_loop:
@@ -776,6 +778,7 @@ class Structure:
776
778
 
777
779
  origin : Tuple[float,]
778
780
  The origin of the coordinate system.
781
+
779
782
  Returns
780
783
  -------
781
784
  Tuple[NDArray, List[str], Tuple[int, ], float, Tuple[float,]]
@@ -1,72 +0,0 @@
1
- pytme-0.2.0.data/scripts/estimate_ram_usage.py,sha256=R1NDpFajcF-MonJ4a43SfDlA-nxBYwK7D2quzCdsVFM,2767
2
- pytme-0.2.0.data/scripts/match_template.py,sha256=7MFgUS0W1WKG95FvLLYEJVc-zHt3BKP-R_4pgnY3ijk,35496
3
- pytme-0.2.0.data/scripts/postprocess.py,sha256=mgSkDoW9NNQiYYq8jkJxHRlHUkOkpkwCzxeqwQTZPps,21011
4
- pytme-0.2.0.data/scripts/preprocess.py,sha256=zog-l2Je-GeouJ6SnamOMuHgTn7fFPiGnO5X03y5qSY,2527
5
- pytme-0.2.0.data/scripts/preprocessor_gui.py,sha256=dX8y9FjCqwYIgZZ4G3xaFqIGB6FqY0ohiY9VodMBXBI,35189
6
- scripts/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
- scripts/estimate_ram_usage.py,sha256=rN7haobnHg3YcgGJIp81FNiCzy8-saJGeEurQlmQmNQ,2768
8
- scripts/extract_candidates.py,sha256=L2IXg99hgW8jUBp06e6PEDO-Y5iUhoFuhe0i5B9gcOE,6871
9
- scripts/match_template.py,sha256=s3rbo_qEiN7uMaKLybzI_PLUvUztws8VWysHbEGJFi8,35497
10
- scripts/match_template_filters.py,sha256=u0eqbayRr-rTfag5rVGEMciZ3u6FVMmuwHB847WwRMc,35428
11
- scripts/postprocess.py,sha256=rqsBmbJWX_yG6fUDcwXMjlHorqgetgYcmgzm4yEsj9U,21012
12
- scripts/preprocess.py,sha256=ebJVLxbRlB6TI5YHNr0VavZ4lmaRdf8QVafyiDhh_oU,2528
13
- scripts/preprocessor_gui.py,sha256=3K2PXCboUC2v9u6JyyNzPkAWn_TyMeWhFfshESUNvTk,35190
14
- scripts/refine_matches.py,sha256=zV7piR5tGhrbomYN1tjnFDOfPInU07APU8syciSUZz8,7077
15
- tme/__init__.py,sha256=MGVeRX1f5k6RwExBcffZtCM7igNNtpoIr2G2yJZ4OHI,251
16
- tme/__version__.py,sha256=Zn1KFblwuFHiDRdRAiRnDBRkbPttWh44jKa5zG2ov0E,22
17
- tme/analyzer.py,sha256=-bVqdVdUD2gypS2vLu7NObgaY39KFhyN9rEA0-mSOZQ,55480
18
- tme/density.py,sha256=mKZ8hnOsVzo87jKqoJ8jfE9lLrGvySUCKMLvpk7GGu4,88091
19
- tme/extensions.cpython-311-darwin.so,sha256=jUKGwYCpx9B6DAz3EDL5vPbfoxwQVM2KwQBizMDWkaA,412480
20
- tme/helpers.py,sha256=TMtBuJoZk6q4M_rfkr8yPpGzJD74ycqyN3yXMuU9mr4,23625
21
- tme/matching_constrained.py,sha256=NAJnZpusjQs5rKabHiNyrclXSPm27K0V8HVFjTQ2zB0,6725
22
- tme/matching_data.py,sha256=zR3-iUeE9DJlGSvk71GT2ZI_XpYj1plw2igOvUrgOLo,24218
23
- tme/matching_exhaustive.py,sha256=wvjjc5CcmVg-XOaV6Chcc6CGP0YjfEARPizpinEQ6Hw,58993
24
- tme/matching_memory.py,sha256=bmCAUYyXWEet-1XXhldtc0irio2ytMSsAzWYyFI5LNM,11273
25
- tme/matching_optimization.py,sha256=-Ptd-QxvamHLbsnxY_hBiQModFvYVnnfEkUIEcGmc_Y,41894
26
- tme/matching_utils.py,sha256=qLcRcfMCURsA5vFvJDUBa7xIAHsICWn_PB_jOYK3Pb0,42520
27
- tme/orientations.py,sha256=sEGhwBIE19jeRsMr5OZ1VM5ccRBpN5uThx6xG9obbo0,19118
28
- tme/parser.py,sha256=tA9ABeV95cZn8lJCukVUaocQ9RguR6ZZzQsMXf_-ud0,13887
29
- tme/preprocessor.py,sha256=Yu-YUp5H4Vkdr9mGGEfZse7WzMtR3Sq5t2VY5Xb5Xzw,51111
30
- tme/structure.py,sha256=1Dlh6gFn1VhoIr7H9ZDgOfaPJbVVfKv_c8AA00X_lbQ,52465
31
- tme/types.py,sha256=2Tyh_xnMLxIWYb3aJDAUb6GWpaL6gcYMUm2YNbJlAPI,295
32
- tme/backends/__init__.py,sha256=xB2GBUFRskppvEs6S74VH0Pi-nXnIvu9_QFhESlcl3Y,4366
33
- tme/backends/cupy_backend.py,sha256=4x8vy3eIpHKmfjg5BtqB9J0-gP0fWcT85FY-rFRXgVU,13145
34
- tme/backends/matching_backend.py,sha256=E3cMXnMEazYJUr9RP5Q5rMEAf3vbkiOwzWrx5amt_nI,29311
35
- tme/backends/mlx_backend.py,sha256=MrwICZpUiAcpZXON70r4SH-KsWxfhq1PdHUe80WbT-k,8467
36
- tme/backends/npfftw_backend.py,sha256=BHARQV9lo4OWCaKKo4Q4FkDvYpT12g5fgtQsTo0eTa4,27408
37
- tme/backends/pytorch_backend.py,sha256=0QrWX_MSE8ymhaniAzRBgMVL4h5QBJrbLbMbnnaWveE,18293
38
- tme/data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
39
- tme/data/c48n309.npy,sha256=NwH64mOEbm3tStq5c98o81fY1vMOoq4nvXDAh7Z7iZg,296768
40
- tme/data/c48n527.npy,sha256=saSUMTa1R0MisPvgFL02a7IHQSwEZ-mJu0v3qJjg5AU,506048
41
- tme/data/c48n9.npy,sha256=bDVLV6mWjZHSQfeDc-MOCKKarfc1jaNeVvpoe2xMUy4,8768
42
- tme/data/c48u1.npy,sha256=JeXMFzFITs2ezdc3x5lp3jo1cHHHHVADSA1Tpf77kXs,1088
43
- tme/data/c48u1153.npy,sha256=ECiEximtYDWtIux3Fwe_EJlyn08gUqP85DN9gjkT9_k,1107008
44
- tme/data/c48u1201.npy,sha256=aceC_Jeienz_81X4520nPpZcg5tnRhbW795EqbpWkrg,1153088
45
- tme/data/c48u1641.npy,sha256=p4LwW3LzdTjrUUpA7H53RfNWxYfPX0XjeSwZ39Ac78Q,1575488
46
- tme/data/c48u181.npy,sha256=mLYXrv1YHLH6DsBp5MkxHkxlxgMnj1mw_KKI0udH-FY,173888
47
- tme/data/c48u2219.npy,sha256=p8TQeX8YHu4pdxnwJjEAlQWAPa66W7kpK96iZKZr9JE,2130368
48
- tme/data/c48u27.npy,sha256=k03ZNEsoPwBKCy8IeIa5G0WRZqjGZMtX6Ibu7EpJHvU,26048
49
- tme/data/c48u2947.npy,sha256=icI97ED6ct66y7FIaJAugmjzrIWk7CINCxtO3wDTnrU,2829248
50
- tme/data/c48u3733.npy,sha256=tla-__Pf-hpN6h04vtFIfkkFdCLple11VO06kr1dXkM,3583808
51
- tme/data/c48u4749.npy,sha256=tItOA4oV7SiqCCREwz3fyEpZoxM0lCq_jfEo5_-fp2s,4559168
52
- tme/data/c48u5879.npy,sha256=bFk89MllIFCX_sLXTYWFquSyN1NuahH4wwnEsPJLxzA,5643968
53
- tme/data/c48u7111.npy,sha256=CMy9kI2edH-q9eTIVdgUtXurplYNI7Uqp4dXfkkVdf8,6826688
54
- tme/data/c48u815.npy,sha256=bCuJxLtm0Sjg3GGxtyjGzRYZ1G0Gz79XHI-71GvqQnI,782528
55
- tme/data/c48u83.npy,sha256=7ODJYnsiuDjGbgd9GFopsyIW2IjrYI0J2X2f-cK868U,79808
56
- tme/data/c48u8649.npy,sha256=-IPlpR4zrPQZWhhSPu4zEulFdrCEVgTMFffCB5d-huE,8303168
57
- tme/data/c600v.npy,sha256=JqSu3ALoL1A9iguehc0YGUMFPsh2fprHHp76VXeFXIw,2528
58
- tme/data/c600vc.npy,sha256=Yht-GFXDSjjGvsjFBvyxxEZAI-ODADPd5gEgFNZQVTA,14528
59
- tme/data/metadata.yaml,sha256=fAgX-mEzB0QMHTEtYDG4cSMbJhYxBbDJH3sdvJvL7a8,750
60
- tme/data/quat_to_numpy.py,sha256=-gkDZb10fKBxwfYrSLCUWvMB76TzZWELCeKsYProwws,1333
61
- tme/preprocessing/__init__.py,sha256=7O3vDzJcIfxovJkf7avWSPtzaIVlTbmsW7egQFukC_s,98
62
- tme/preprocessing/_utils.py,sha256=KW8nAQqd7zDMI8IsIwLmGv5vwYuKWulCc0pYfpXmz-c,4833
63
- tme/preprocessing/composable_filter.py,sha256=k85XCxtGaCSMzbbF3KTzWJoMpcEAi4b_4uTNRVnPym0,779
64
- tme/preprocessing/compose.py,sha256=e6RW1Lz1MDq8b1uo0Z1WlPlUE3rWSj9YzlV35ZCwmXg,1321
65
- tme/preprocessing/frequency_filters.py,sha256=q4duOq6jvHMB-0wmyJQbQU41jXAiS-nW0MEMCBMnMyU,10634
66
- tme/preprocessing/tilt_series.py,sha256=_d4ajaJPgcqUT6tlaqvNCHtUqV-P0hebzzSOwKv0tsQ,32661
67
- pytme-0.2.0.dist-info/LICENSE,sha256=K1IUNSVAz8BXbpH5EA8y5FpaHdvFXnAF2zeK95Lr2bY,18467
68
- pytme-0.2.0.dist-info/METADATA,sha256=Wu3iU5wzfD6dVhMJg4ucdkUGBL_XbYaEcwQxI4Tkbrs,2165
69
- pytme-0.2.0.dist-info/WHEEL,sha256=BDgKu9_KNfDn85ptly0T56JpX4avXH07X_ZCqAJnQwY,110
70
- pytme-0.2.0.dist-info/entry_points.txt,sha256=ff3LQL3FCWfCYOwFiP9zatm7laUbnwCkuPELkQVyUO4,241
71
- pytme-0.2.0.dist-info/top_level.txt,sha256=J8FUkazOb2fZ0n_KexnqCGyNOtie2bwisFSUBiM5-0w,12
72
- pytme-0.2.0.dist-info/RECORD,,
File without changes
File without changes