pytme 0.3b0__cp311-cp311-macosx_15_0_arm64.whl → 0.3b0.post1__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.
- {pytme-0.3b0.data → pytme-0.3b0.post1.data}/scripts/estimate_memory_usage.py +1 -5
- {pytme-0.3b0.data → pytme-0.3b0.post1.data}/scripts/match_template.py +163 -201
- {pytme-0.3b0.data → pytme-0.3b0.post1.data}/scripts/postprocess.py +48 -39
- {pytme-0.3b0.data → pytme-0.3b0.post1.data}/scripts/preprocess.py +10 -23
- {pytme-0.3b0.data → pytme-0.3b0.post1.data}/scripts/preprocessor_gui.py +3 -4
- pytme-0.3b0.post1.data/scripts/pytme_runner.py +769 -0
- {pytme-0.3b0.dist-info → pytme-0.3b0.post1.dist-info}/METADATA +14 -14
- {pytme-0.3b0.dist-info → pytme-0.3b0.post1.dist-info}/RECORD +54 -50
- {pytme-0.3b0.dist-info → pytme-0.3b0.post1.dist-info}/entry_points.txt +1 -0
- pytme-0.3b0.post1.dist-info/licenses/LICENSE +339 -0
- scripts/estimate_memory_usage.py +1 -5
- scripts/eval.py +93 -0
- scripts/match_template.py +163 -201
- scripts/match_template_filters.py +1200 -0
- scripts/postprocess.py +48 -39
- scripts/preprocess.py +10 -23
- scripts/preprocessor_gui.py +3 -4
- scripts/pytme_runner.py +769 -0
- scripts/refine_matches.py +0 -1
- tests/preprocessing/test_frequency_filters.py +19 -10
- tests/test_analyzer.py +122 -122
- tests/test_backends.py +1 -0
- tests/test_matching_cli.py +30 -30
- tests/test_matching_data.py +5 -5
- tests/test_matching_utils.py +1 -1
- tme/__version__.py +1 -1
- tme/analyzer/__init__.py +1 -1
- tme/analyzer/_utils.py +1 -4
- tme/analyzer/aggregation.py +15 -6
- tme/analyzer/base.py +25 -36
- tme/analyzer/peaks.py +39 -113
- tme/analyzer/proxy.py +1 -0
- tme/backends/_jax_utils.py +16 -15
- tme/backends/cupy_backend.py +9 -13
- tme/backends/jax_backend.py +19 -16
- tme/backends/npfftw_backend.py +27 -25
- tme/backends/pytorch_backend.py +4 -0
- tme/density.py +5 -4
- tme/filters/__init__.py +2 -2
- tme/filters/_utils.py +32 -7
- tme/filters/bandpass.py +225 -186
- tme/filters/ctf.py +117 -67
- tme/filters/reconstruction.py +38 -9
- tme/filters/wedge.py +88 -105
- tme/filters/whitening.py +1 -6
- tme/matching_data.py +24 -36
- tme/matching_exhaustive.py +14 -11
- tme/matching_scores.py +21 -12
- tme/matching_utils.py +13 -6
- tme/orientations.py +13 -3
- tme/parser.py +109 -29
- tme/preprocessor.py +2 -2
- pytme-0.3b0.dist-info/licenses/LICENSE +0 -153
- {pytme-0.3b0.dist-info → pytme-0.3b0.post1.dist-info}/WHEEL +0 -0
- {pytme-0.3b0.dist-info → pytme-0.3b0.post1.dist-info}/top_level.txt +0 -0
tme/filters/ctf.py
CHANGED
@@ -7,7 +7,6 @@ Author: Valentin Maurer <valentin.maurer@embl-hamburg.de>
|
|
7
7
|
"""
|
8
8
|
|
9
9
|
import re
|
10
|
-
import warnings
|
11
10
|
from typing import Tuple, Dict
|
12
11
|
from dataclasses import dataclass
|
13
12
|
|
@@ -16,13 +15,14 @@ import numpy as np
|
|
16
15
|
from ..types import NDArray
|
17
16
|
from ..backends import backend as be
|
18
17
|
from .compose import ComposableFilter
|
19
|
-
from ..parser import StarParser, XMLParser
|
18
|
+
from ..parser import StarParser, XMLParser, MDOCParser
|
20
19
|
from ._utils import (
|
21
20
|
frequency_grid_at_angle,
|
22
21
|
compute_tilt_shape,
|
23
22
|
crop_real_fourier,
|
24
23
|
fftfreqn,
|
25
24
|
shift_fourier,
|
25
|
+
pad_to_length,
|
26
26
|
)
|
27
27
|
|
28
28
|
__all__ = ["CTF", "CTFReconstructed", "create_ctf"]
|
@@ -34,39 +34,39 @@ class CTF(ComposableFilter):
|
|
34
34
|
Generate a per-tilt contrast transfer function mask.
|
35
35
|
"""
|
36
36
|
|
37
|
-
#: The shape of the to-be
|
37
|
+
#: The shape of the to-be created mask.
|
38
38
|
shape: Tuple[int] = None
|
39
|
-
#: The defocus value in x direction.
|
40
|
-
defocus_x: float = None
|
39
|
+
#: The defocus value in x direction (in units of sampling rate).
|
40
|
+
defocus_x: Tuple[float] = None
|
41
41
|
#: The tilt angles.
|
42
42
|
angles: Tuple[float] = None
|
43
|
-
#: The microscope projection axis, defaults to
|
43
|
+
#: The microscope projection axis, defaults to 2 (z).
|
44
44
|
opening_axis: int = 2
|
45
|
-
#: The axis along which the tilt is applied, defaults to
|
45
|
+
#: The axis along which the tilt is applied, defaults to 0 (x).
|
46
46
|
tilt_axis: int = 0
|
47
|
-
#: Whether to correct defocus gradient, defaults
|
47
|
+
#: Whether to correct defocus gradient, defaults False.
|
48
48
|
correct_defocus_gradient: bool = False
|
49
|
-
#: The sampling rate, defaults to 1
|
49
|
+
#: The sampling rate, defaults to 1 Ångstrom / voxel.
|
50
50
|
sampling_rate: Tuple[float] = 1
|
51
51
|
#: The acceleration voltage in Volts, defaults to 300e3.
|
52
|
-
acceleration_voltage: float = 300e3
|
53
|
-
#: The spherical aberration
|
54
|
-
spherical_aberration: float = 2.7e7
|
52
|
+
acceleration_voltage: Tuple[float] = 300e3
|
53
|
+
#: The spherical aberration, defaults to 2.7e7 (in units of sampling rate).
|
54
|
+
spherical_aberration: Tuple[float] = 2.7e7
|
55
55
|
#: The amplitude contrast, defaults to 0.07.
|
56
|
-
amplitude_contrast: float = 0.07
|
56
|
+
amplitude_contrast: Tuple[float] = 0.07
|
57
57
|
#: The phase shift in degrees, defaults to 0.
|
58
|
-
phase_shift: float = 0
|
58
|
+
phase_shift: Tuple[float] = 0
|
59
59
|
#: The defocus angle in degrees, defaults to 0.
|
60
|
-
defocus_angle: float = 0
|
61
|
-
#: The defocus value in y direction, defaults to None.
|
62
|
-
defocus_y: float = None
|
63
|
-
#: Whether the returned CTF should be phase-flipped.
|
60
|
+
defocus_angle: Tuple[float] = 0
|
61
|
+
#: The defocus value in y direction, defaults to None (in units of sampling rate).
|
62
|
+
defocus_y: Tuple[float] = None
|
63
|
+
#: Whether the returned CTF should be phase-flipped, defaults to True.
|
64
64
|
flip_phase: bool = True
|
65
|
-
#: Whether to return a
|
65
|
+
#: Whether to return a ctf mask for rfft (for :py:class:`CTFReconstructed`).
|
66
66
|
return_real_fourier: bool = False
|
67
67
|
|
68
68
|
@classmethod
|
69
|
-
def from_file(cls, filename: str) -> "CTF":
|
69
|
+
def from_file(cls, filename: str, **kwargs) -> "CTF":
|
70
70
|
"""
|
71
71
|
Initialize :py:class:`CTF` from file.
|
72
72
|
|
@@ -80,36 +80,50 @@ class CTF(ComposableFilter):
|
|
80
80
|
+-------+---------------------------------------------------------+
|
81
81
|
| .xml | WARP/M XML file |
|
82
82
|
+-------+---------------------------------------------------------+
|
83
|
+
| .mdoc | SerialEM file |
|
84
|
+
+-------+---------------------------------------------------------+
|
83
85
|
| .* | CTFFIND4 file |
|
84
86
|
+-------+---------------------------------------------------------+
|
87
|
+
**kwargs : optional
|
88
|
+
Overwrite fields that cannot be extracted from input file.
|
85
89
|
"""
|
86
90
|
func = _from_ctffind
|
87
91
|
if filename.lower().endswith("star"):
|
88
|
-
func =
|
92
|
+
func = _from_star
|
89
93
|
elif filename.lower().endswith("xml"):
|
90
94
|
func = _from_xml
|
95
|
+
elif filename.lower().endswith("mdoc"):
|
96
|
+
func = _from_mdoc
|
91
97
|
|
92
98
|
data = func(filename=filename)
|
93
99
|
|
94
100
|
# Pixel size needs to be overwritten by pixel size the ctf is generated for
|
95
|
-
|
96
|
-
shape
|
97
|
-
angles
|
98
|
-
defocus_x
|
99
|
-
sampling_rate
|
100
|
-
acceleration_voltage
|
101
|
-
spherical_aberration
|
102
|
-
amplitude_contrast
|
103
|
-
phase_shift
|
104
|
-
defocus_angle
|
105
|
-
defocus_y
|
106
|
-
|
101
|
+
init_kwargs = {
|
102
|
+
"shape": None,
|
103
|
+
"angles": data.get("angles", None),
|
104
|
+
"defocus_x": data["defocus_1"],
|
105
|
+
"sampling_rate": data["pixel_size"],
|
106
|
+
"acceleration_voltage": np.multiply(data["acceleration_voltage"], 1e3),
|
107
|
+
"spherical_aberration": data.get("spherical_aberration"),
|
108
|
+
"amplitude_contrast": data.get("amplitude_contrast"),
|
109
|
+
"phase_shift": data.get("additional_phase_shift"),
|
110
|
+
"defocus_angle": data.get("azimuth_astigmatism"),
|
111
|
+
"defocus_y": data["defocus_2"],
|
112
|
+
}
|
113
|
+
for k, v in kwargs.items():
|
114
|
+
if k in init_kwargs and init_kwargs.get(k) is None:
|
115
|
+
init_kwargs[k] = v
|
116
|
+
init_kwargs = {k: v for k, v in init_kwargs.items() if v is not None}
|
117
|
+
return cls(**init_kwargs)
|
107
118
|
|
108
119
|
def __post_init__(self):
|
109
120
|
self.defocus_angle = np.radians(self.defocus_angle)
|
110
121
|
self.phase_shift = np.radians(self.phase_shift)
|
111
122
|
|
112
123
|
def __call__(self, **kwargs) -> NDArray:
|
124
|
+
"""
|
125
|
+
Returns a CTF stack of chosen parameters with DC component in the center.
|
126
|
+
"""
|
113
127
|
func_args = vars(self).copy()
|
114
128
|
func_args.update(kwargs)
|
115
129
|
|
@@ -122,11 +136,6 @@ class CTF(ComposableFilter):
|
|
122
136
|
"is_multiplicative_filter": True,
|
123
137
|
}
|
124
138
|
|
125
|
-
@staticmethod
|
126
|
-
def _pad_to_length(arr, length: int):
|
127
|
-
ret = np.atleast_1d(arr)
|
128
|
-
return np.repeat(ret, length // ret.size)
|
129
|
-
|
130
139
|
def weight(
|
131
140
|
self,
|
132
141
|
shape: Tuple[int],
|
@@ -134,7 +143,7 @@ class CTF(ComposableFilter):
|
|
134
143
|
angles: Tuple[float],
|
135
144
|
opening_axis: int = 2,
|
136
145
|
tilt_axis: int = 0,
|
137
|
-
amplitude_contrast: float = 0.07,
|
146
|
+
amplitude_contrast: Tuple[float] = 0.07,
|
138
147
|
phase_shift: Tuple[float] = 0,
|
139
148
|
defocus_angle: Tuple[float] = 0,
|
140
149
|
defocus_y: Tuple[float] = None,
|
@@ -162,7 +171,7 @@ class CTF(ComposableFilter):
|
|
162
171
|
The axis around which the wedge is opened, defaults to 2.
|
163
172
|
tilt_axis : int, optional
|
164
173
|
The axis along which the tilt is applied, defaults to 0.
|
165
|
-
amplitude_contrast : float, optional
|
174
|
+
amplitude_contrast : tuple of float, optional
|
166
175
|
The amplitude contrast, defaults to 0.07.
|
167
176
|
phase_shift : tuple of float, optional
|
168
177
|
The phase shift in radians, defaults to 0.
|
@@ -179,7 +188,7 @@ class CTF(ComposableFilter):
|
|
179
188
|
spherical_aberration : float, optional
|
180
189
|
The spherical aberration coefficient, defaults to 2.7e3.
|
181
190
|
flip_phase : bool, optional
|
182
|
-
Whether the returned CTF should be phase-flipped.
|
191
|
+
Whether the returned CTF should be phase-flipped, defaults to True.
|
183
192
|
**kwargs : Dict
|
184
193
|
Additional keyword arguments.
|
185
194
|
|
@@ -189,12 +198,13 @@ class CTF(ComposableFilter):
|
|
189
198
|
A stack containing the CTF weight.
|
190
199
|
"""
|
191
200
|
angles = np.atleast_1d(angles)
|
192
|
-
defoci_x =
|
193
|
-
defoci_y =
|
194
|
-
phase_shift =
|
195
|
-
defocus_angle =
|
196
|
-
spherical_aberration =
|
197
|
-
amplitude_contrast =
|
201
|
+
defoci_x = pad_to_length(defocus_x, angles.size)
|
202
|
+
defoci_y = pad_to_length(defocus_y, angles.size)
|
203
|
+
phase_shift = pad_to_length(phase_shift, angles.size)
|
204
|
+
defocus_angle = pad_to_length(defocus_angle, angles.size)
|
205
|
+
spherical_aberration = pad_to_length(spherical_aberration, angles.size)
|
206
|
+
amplitude_contrast = pad_to_length(amplitude_contrast, angles.size)
|
207
|
+
acceleration_voltage = pad_to_length(acceleration_voltage, angles.size)
|
198
208
|
|
199
209
|
sampling_rate = np.max(sampling_rate)
|
200
210
|
ctf_shape = compute_tilt_shape(
|
@@ -218,7 +228,7 @@ class CTF(ComposableFilter):
|
|
218
228
|
defocus_x=defocus_x,
|
219
229
|
defocus_y=defocus_y,
|
220
230
|
sampling_rate=sampling_rate,
|
221
|
-
acceleration_voltage=
|
231
|
+
acceleration_voltage=acceleration_voltage[index],
|
222
232
|
correct_defocus_gradient=correction,
|
223
233
|
spherical_aberration=spherical_aberration[index],
|
224
234
|
cutoff_frequency=cutoff_frequency,
|
@@ -325,7 +335,7 @@ class CTFReconstructed(CTF):
|
|
325
335
|
return stack
|
326
336
|
|
327
337
|
|
328
|
-
def _from_xml(filename: str):
|
338
|
+
def _from_xml(filename: str) -> Dict:
|
329
339
|
data = XMLParser(filename)
|
330
340
|
|
331
341
|
params = {
|
@@ -353,6 +363,7 @@ def _from_xml(filename: str):
|
|
353
363
|
params["PhaseShift"] = [
|
354
364
|
ctf_phase[i]["@attributes"]["Value"] for i in range(len(ctf_phase))
|
355
365
|
]
|
366
|
+
params["PhaseShift"] = np.degrees(params["PhaseShift"])
|
356
367
|
ctf_ast = data["GridCTFDefocusAngle"]["Node"]
|
357
368
|
params["DefocusAngle"] = [
|
358
369
|
ctf_ast[i]["@attributes"]["Value"] for i in range(len(ctf_ast))
|
@@ -384,7 +395,7 @@ def _from_xml(filename: str):
|
|
384
395
|
return {k: params[v] for k, v in mapping.items()}
|
385
396
|
|
386
397
|
|
387
|
-
def _from_ctffind(filename: str):
|
398
|
+
def _from_ctffind(filename: str) -> Dict:
|
388
399
|
parameter_regex = {
|
389
400
|
"pixel_size": r"Pixel size: ([0-9.]+) Angstroms",
|
390
401
|
"acceleration_voltage": r"acceleration voltage: ([0-9.]+) keV",
|
@@ -428,15 +439,58 @@ def _from_ctffind(filename: str):
|
|
428
439
|
return output
|
429
440
|
|
430
441
|
|
431
|
-
def
|
442
|
+
def _from_star(filename: str) -> Dict:
|
432
443
|
parser = StarParser(filename)
|
433
|
-
|
444
|
+
|
445
|
+
if "data_stopgap_wedgelist" in parser:
|
446
|
+
key = "data_stopgap_wedgelist"
|
447
|
+
mapping = {
|
448
|
+
"angles": ("_tilt_angle", float, 1),
|
449
|
+
"defocus_1": ("_defocus", float, 1e4),
|
450
|
+
"defocus_2": (None, float, 1e4),
|
451
|
+
"pixel_size": ("_pixelsize", float, 1),
|
452
|
+
"acceleration_voltage": ("_voltage", float, 1),
|
453
|
+
"spherical_aberration": ("_cs", float, 1e7),
|
454
|
+
"amplitude_contrast": ("_amp_contrast", float, 1),
|
455
|
+
"additional_phase_shift": (None, float, 1),
|
456
|
+
"azimuth_astigmatism": (None, float, 1),
|
457
|
+
}
|
458
|
+
else:
|
459
|
+
key = "data_"
|
460
|
+
mapping = {
|
461
|
+
"defocus_1": ("_rlnDefocusU", float, 1),
|
462
|
+
"defocus_2": ("_rlnDefocusV", float, 1),
|
463
|
+
"pixel_size": ("_rlnDetectorPixelSize", float, 1),
|
464
|
+
"acceleration_voltage": ("_rlnVoltage", float, 1),
|
465
|
+
"spherical_aberration": ("_rlnSphericalAberration", float, 1),
|
466
|
+
"amplitude_contrast": ("_rlnAmplitudeContrast", float, 1),
|
467
|
+
"additional_phase_shift": (None, float, 1),
|
468
|
+
"azimuth_astigmatism": ("_rlnDefocusAngle", float, 1),
|
469
|
+
}
|
470
|
+
|
471
|
+
output = {}
|
472
|
+
ctf_data = parser[key]
|
473
|
+
for out_key, (key, key_dtype, scale) in mapping.items():
|
474
|
+
key_value = ctf_data.get(key)
|
475
|
+
if key_value is not None:
|
476
|
+
try:
|
477
|
+
key_value = [key_dtype(x) * scale for x in key_value]
|
478
|
+
except Exception:
|
479
|
+
pass
|
480
|
+
output[out_key] = key_value
|
481
|
+
return output
|
482
|
+
|
483
|
+
|
484
|
+
def _from_mdoc(filename: str) -> Dict:
|
485
|
+
parser = MDOCParser(filename)
|
434
486
|
|
435
487
|
mapping = {
|
436
|
-
"
|
437
|
-
"
|
488
|
+
"angles": ("TiltAngle", float),
|
489
|
+
"defocus_1": ("Defocus", float),
|
490
|
+
"acceleration_voltage": ("Voltage", float),
|
491
|
+
# These will be None, but on purpose
|
438
492
|
"pixel_size": ("_rlnDetectorPixelSize", float),
|
439
|
-
"
|
493
|
+
"defocus_2": ("Defocus2", float),
|
440
494
|
"spherical_aberration": ("_rlnSphericalAberration", float),
|
441
495
|
"amplitude_contrast": ("_rlnAmplitudeContrast", float),
|
442
496
|
"additional_phase_shift": (None, float),
|
@@ -444,14 +498,10 @@ def _from_gctf(filename: str):
|
|
444
498
|
}
|
445
499
|
output = {}
|
446
500
|
for out_key, (key, key_dtype) in mapping.items():
|
447
|
-
|
448
|
-
warnings.warn(f"ctf_data is missing key {key}.")
|
449
|
-
|
450
|
-
key_value = ctf_data.get(key, [0])
|
451
|
-
output[out_key] = [key_dtype(x) for x in key_value]
|
501
|
+
output[out_key] = parser.get(key, None)
|
452
502
|
|
453
|
-
|
454
|
-
output =
|
503
|
+
# Adjust convention and convert to Angstrom
|
504
|
+
output["defocus_1"] = np.multiply(output["defocus_1"], -1e4)
|
455
505
|
return output
|
456
506
|
|
457
507
|
|
@@ -589,10 +639,10 @@ def create_ctf(
|
|
589
639
|
frequency_mask = frequency_grid < cutoff_frequency
|
590
640
|
|
591
641
|
# k^2*π*λ(dx - 0.5 * sph_abb * λ^2 * k^2) + phase_shift + ampl_contrast_term)
|
592
|
-
np.square(frequency_grid, out=frequency_grid)
|
642
|
+
frequency_grid = np.square(frequency_grid, out=frequency_grid)
|
593
643
|
chi = defocus_x - 0.5 * aberration * frequency_grid
|
594
|
-
np.multiply(chi, np.pi * electron_wavelength, out=chi)
|
595
|
-
np.multiply(chi, frequency_grid, out=chi)
|
644
|
+
chi = np.multiply(chi, np.pi * electron_wavelength, out=chi)
|
645
|
+
chi = np.multiply(chi, frequency_grid, out=chi)
|
596
646
|
chi += phase_shift
|
597
647
|
chi += np.arctan(
|
598
648
|
np.divide(
|
@@ -600,6 +650,6 @@ def create_ctf(
|
|
600
650
|
np.sqrt(1 - np.square(amplitude_contrast)),
|
601
651
|
)
|
602
652
|
)
|
603
|
-
np.sin(-chi, out=chi)
|
604
|
-
np.multiply(chi, frequency_mask, out=chi)
|
653
|
+
chi = np.sin(-chi, out=chi)
|
654
|
+
chi = np.multiply(chi, frequency_mask, out=chi)
|
605
655
|
return chi
|
tme/filters/reconstruction.py
CHANGED
@@ -11,14 +11,14 @@ from dataclasses import dataclass
|
|
11
11
|
|
12
12
|
import numpy as np
|
13
13
|
|
14
|
-
from ..types import NDArray
|
15
14
|
from ..backends import backend as be
|
15
|
+
from ..types import NDArray, BackendArray
|
16
16
|
|
17
17
|
from .compose import ComposableFilter
|
18
18
|
from ..rotations import euler_to_rotationmatrix
|
19
19
|
from ._utils import crop_real_fourier, shift_fourier, create_reconstruction_filter
|
20
20
|
|
21
|
-
__all__ = ["ReconstructFromTilt"]
|
21
|
+
__all__ = ["ReconstructFromTilt", "ShiftFourier"]
|
22
22
|
|
23
23
|
|
24
24
|
@dataclass
|
@@ -52,7 +52,9 @@ class ReconstructFromTilt(ComposableFilter):
|
|
52
52
|
shape : tuple of int
|
53
53
|
The shape of the reconstruction volume.
|
54
54
|
data : BackendArray
|
55
|
-
D-dimensional image stack with shape (n, ...)
|
55
|
+
D-dimensional image stack with shape (n, ...). The data is assumed to be
|
56
|
+
a Fourier transform of the stack you are trying to reconstruct with
|
57
|
+
DC component in the center.
|
56
58
|
angles : tuple of float
|
57
59
|
Angle of each individual tilt.
|
58
60
|
return_real_fourier : bool, optional
|
@@ -87,13 +89,14 @@ class ReconstructFromTilt(ComposableFilter):
|
|
87
89
|
|
88
90
|
ret = self.reconstruct(**func_args)
|
89
91
|
|
92
|
+
ret = shift_fourier(data=ret, shape_is_real_fourier=False)
|
90
93
|
if return_real_fourier:
|
91
94
|
ret = crop_real_fourier(ret)
|
92
95
|
|
93
96
|
return {
|
94
97
|
"data": ret,
|
95
98
|
"shape": func_args["shape"],
|
96
|
-
"
|
99
|
+
"return_real_fourier": return_real_fourier,
|
97
100
|
"is_multiplicative_filter": False,
|
98
101
|
}
|
99
102
|
|
@@ -114,7 +117,7 @@ class ReconstructFromTilt(ComposableFilter):
|
|
114
117
|
Parameters
|
115
118
|
----------
|
116
119
|
data : NDArray
|
117
|
-
The tilt series data.
|
120
|
+
The Fourier transform of tilt series data.
|
118
121
|
shape : tuple of int
|
119
122
|
Shape of the reconstruction.
|
120
123
|
angles : tuple of float
|
@@ -138,9 +141,9 @@ class ReconstructFromTilt(ComposableFilter):
|
|
138
141
|
return data
|
139
142
|
|
140
143
|
data = be.to_backend_array(data)
|
141
|
-
volume_temp = be.zeros(shape, dtype=
|
142
|
-
volume_temp_rotated = be.zeros(shape, dtype=
|
143
|
-
volume = be.zeros(shape, dtype=
|
144
|
+
volume_temp = be.zeros(shape, dtype=data.dtype)
|
145
|
+
volume_temp_rotated = be.zeros(shape, dtype=data.dtype)
|
146
|
+
volume = be.zeros(shape, dtype=data.dtype)
|
144
147
|
|
145
148
|
slices = tuple(slice(a // 2, (a // 2) + 1) for a in shape)
|
146
149
|
subset = tuple(
|
@@ -187,4 +190,30 @@ class ReconstructFromTilt(ComposableFilter):
|
|
187
190
|
)
|
188
191
|
volume = be.add(volume, volume_temp_rotated, out=volume)
|
189
192
|
|
190
|
-
return
|
193
|
+
return volume
|
194
|
+
|
195
|
+
|
196
|
+
class ShiftFourier(ComposableFilter):
|
197
|
+
def __call__(
|
198
|
+
self,
|
199
|
+
data: BackendArray,
|
200
|
+
shape_is_real_fourier: bool = False,
|
201
|
+
return_real_fourier: bool = True,
|
202
|
+
**kwargs,
|
203
|
+
):
|
204
|
+
ret = []
|
205
|
+
for index in range(data.shape[0]):
|
206
|
+
mask = be.to_numpy_array(data[index])
|
207
|
+
|
208
|
+
mask = shift_fourier(data=mask, shape_is_real_fourier=shape_is_real_fourier)
|
209
|
+
if return_real_fourier:
|
210
|
+
mask = crop_real_fourier(mask)
|
211
|
+
ret.append(mask[None])
|
212
|
+
ret = np.concatenate(ret, axis=0)
|
213
|
+
|
214
|
+
return {
|
215
|
+
"data": ret,
|
216
|
+
"shape": kwargs.get("shape"),
|
217
|
+
"return_real_fourier": return_real_fourier,
|
218
|
+
"is_multiplicative_filter": False,
|
219
|
+
}
|