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.
- {pytme-0.2.0.data → pytme-0.2.1.data}/scripts/match_template.py +183 -69
- {pytme-0.2.0.data → pytme-0.2.1.data}/scripts/postprocess.py +107 -49
- {pytme-0.2.0.data → pytme-0.2.1.data}/scripts/preprocessor_gui.py +4 -1
- {pytme-0.2.0.dist-info → pytme-0.2.1.dist-info}/METADATA +1 -1
- pytme-0.2.1.dist-info/RECORD +73 -0
- scripts/extract_candidates.py +117 -85
- scripts/match_template.py +183 -69
- scripts/match_template_filters.py +193 -71
- scripts/postprocess.py +107 -49
- scripts/preprocessor_gui.py +4 -1
- scripts/refine_matches.py +364 -160
- tme/__version__.py +1 -1
- tme/analyzer.py +259 -117
- tme/backends/__init__.py +1 -0
- tme/backends/cupy_backend.py +20 -13
- tme/backends/jax_backend.py +218 -0
- tme/backends/matching_backend.py +25 -10
- tme/backends/mlx_backend.py +13 -9
- tme/backends/npfftw_backend.py +20 -8
- tme/backends/pytorch_backend.py +20 -9
- tme/density.py +79 -60
- tme/extensions.cpython-311-darwin.so +0 -0
- tme/matching_data.py +85 -61
- tme/matching_exhaustive.py +222 -129
- tme/matching_optimization.py +117 -76
- tme/orientations.py +175 -55
- tme/preprocessing/_utils.py +17 -5
- tme/preprocessing/composable_filter.py +2 -1
- tme/preprocessing/compose.py +1 -2
- tme/preprocessing/frequency_filters.py +97 -41
- tme/preprocessing/tilt_series.py +137 -87
- tme/preprocessor.py +3 -0
- tme/structure.py +4 -1
- pytme-0.2.0.dist-info/RECORD +0 -72
- {pytme-0.2.0.data → pytme-0.2.1.data}/scripts/estimate_ram_usage.py +0 -0
- {pytme-0.2.0.data → pytme-0.2.1.data}/scripts/preprocess.py +0 -0
- {pytme-0.2.0.dist-info → pytme-0.2.1.dist-info}/LICENSE +0 -0
- {pytme-0.2.0.dist-info → pytme-0.2.1.dist-info}/WHEEL +0 -0
- {pytme-0.2.0.dist-info → pytme-0.2.1.dist-info}/entry_points.txt +0 -0
- {pytme-0.2.0.dist-info → pytme-0.2.1.dist-info}/top_level.txt +0 -0
tme/preprocessing/tilt_series.py
CHANGED
@@ -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(
|
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
|
38
|
+
The type of created filter, available options are:
|
36
39
|
|
37
40
|
+---------------+----------------------------------------------------+
|
38
|
-
|
|
41
|
+
| ram-lak | Returns |w| |
|
39
42
|
+---------------+----------------------------------------------------+
|
40
|
-
|
|
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
|
-
|
|
46
|
+
| ramp | Like ramp-cont but considering tilt angles |
|
44
47
|
+---------------+----------------------------------------------------+
|
45
|
-
|
|
48
|
+
| shepp-logan | |w| * sinc(|w| / 2) [2]_ |
|
46
49
|
+---------------+----------------------------------------------------+
|
47
|
-
|
|
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
|
69
|
+
freq = fftfreqn(filter_shape, sampling_rate=0.5, compute_euclidean_norm=True)
|
62
70
|
|
63
|
-
if filter_type ==
|
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 ==
|
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 ==
|
110
|
+
elif filter_type == "cosine":
|
87
111
|
ret = freq * np.cos(freq * np.pi / 2)
|
88
|
-
elif filter_type ==
|
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
|
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
|
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.
|
174
|
-
volume_temp_rotated = backend.zeros(shape, dtype=backend.
|
175
|
-
volume = backend.zeros(shape, dtype=backend.
|
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(
|
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
|
191
|
-
filter_shape
|
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
|
-
|
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,
|
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.
|
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
|
475
|
-
np.multiply(amplitude, frequency_grid, out
|
476
|
-
np.add(frequency_grid, offset, out
|
477
|
-
np.multiply(-2, frequency_grid, out
|
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
|
516
|
-
create_continuous_wedge
|
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"
|
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.
|
693
|
-
spherical_aberration: float = 2.
|
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
|
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
|
-
|
908
|
-
|
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,
|
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
|
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,]]
|
pytme-0.2.0.dist-info/RECORD
DELETED
@@ -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
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|