pytme 0.2.0b0__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.0b0.data → pytme-0.2.1.data}/scripts/match_template.py +473 -140
- {pytme-0.2.0b0.data → pytme-0.2.1.data}/scripts/postprocess.py +107 -49
- {pytme-0.2.0b0.data → pytme-0.2.1.data}/scripts/preprocessor_gui.py +4 -1
- {pytme-0.2.0b0.dist-info → pytme-0.2.1.dist-info}/METADATA +2 -2
- pytme-0.2.1.dist-info/RECORD +73 -0
- scripts/extract_candidates.py +117 -85
- scripts/match_template.py +473 -140
- scripts/match_template_filters.py +458 -169
- 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 +278 -148
- 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 +22 -12
- tme/backends/pytorch_backend.py +20 -9
- tme/density.py +85 -64
- tme/extensions.cpython-311-darwin.so +0 -0
- tme/matching_data.py +86 -60
- tme/matching_exhaustive.py +245 -166
- tme/matching_optimization.py +137 -69
- tme/matching_utils.py +1 -1
- tme/orientations.py +175 -55
- tme/preprocessing/__init__.py +2 -0
- tme/preprocessing/_utils.py +188 -0
- tme/preprocessing/composable_filter.py +31 -0
- tme/preprocessing/compose.py +51 -0
- tme/preprocessing/frequency_filters.py +378 -0
- tme/preprocessing/tilt_series.py +1017 -0
- tme/preprocessor.py +17 -7
- tme/structure.py +4 -1
- pytme-0.2.0b0.dist-info/RECORD +0 -66
- {pytme-0.2.0b0.data → pytme-0.2.1.data}/scripts/estimate_ram_usage.py +0 -0
- {pytme-0.2.0b0.data → pytme-0.2.1.data}/scripts/preprocess.py +0 -0
- {pytme-0.2.0b0.dist-info → pytme-0.2.1.dist-info}/LICENSE +0 -0
- {pytme-0.2.0b0.dist-info → pytme-0.2.1.dist-info}/WHEEL +0 -0
- {pytme-0.2.0b0.dist-info → pytme-0.2.1.dist-info}/entry_points.txt +0 -0
- {pytme-0.2.0b0.dist-info → pytme-0.2.1.dist-info}/top_level.txt +0 -0
scripts/extract_candidates.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
#!python3
|
2
|
-
"""
|
2
|
+
""" Prepare orientations stack for refinement.
|
3
3
|
|
4
4
|
Copyright (c) 2023 European Molecular Biology Laboratory
|
5
5
|
|
@@ -12,13 +12,33 @@ import numpy as np
|
|
12
12
|
|
13
13
|
from tme import Density, Orientations
|
14
14
|
from tme.matching_utils import (
|
15
|
-
|
15
|
+
load_pickle,
|
16
16
|
generate_tempfile_name,
|
17
17
|
rotation_aligning_vectors,
|
18
18
|
euler_from_rotationmatrix,
|
19
|
+
euler_to_rotationmatrix,
|
19
20
|
)
|
20
21
|
|
21
22
|
|
23
|
+
class ProgressBar:
|
24
|
+
"""
|
25
|
+
ASCII progress bar.
|
26
|
+
"""
|
27
|
+
|
28
|
+
def __init__(self, message : str, nchars : int, total : int):
|
29
|
+
self._size = nchars - len(message)
|
30
|
+
self._message = message
|
31
|
+
self._total = total
|
32
|
+
|
33
|
+
def update(self, cur):
|
34
|
+
x = int(cur * self._size / self._total)
|
35
|
+
print(
|
36
|
+
"%s[%s%s] %i/%i\r"
|
37
|
+
% (self._message, "#" * x, "." * (self._size - x), cur, self._total),
|
38
|
+
end=''
|
39
|
+
)
|
40
|
+
|
41
|
+
|
22
42
|
def parse_args():
|
23
43
|
parser = argparse.ArgumentParser(
|
24
44
|
description="Extract matching candidates for further refinement."
|
@@ -52,57 +72,61 @@ def parse_args():
|
|
52
72
|
io_group.add_argument(
|
53
73
|
"-o",
|
54
74
|
"--output_file",
|
55
|
-
required=
|
75
|
+
required=True,
|
56
76
|
type=str,
|
57
77
|
help="Path to output HDF5 file.",
|
58
78
|
)
|
59
79
|
|
60
|
-
|
61
|
-
|
62
|
-
"--
|
80
|
+
alignment_group = parser.add_argument_group("Alignment")
|
81
|
+
alignment_group.add_argument(
|
82
|
+
"--align_orientations",
|
83
|
+
action="store_true",
|
63
84
|
required=False,
|
64
|
-
|
65
|
-
|
85
|
+
help="Whether to align extracted orientations based on their angles. Allows "
|
86
|
+
"for efficient subsequent sampling of cone angles.",
|
66
87
|
)
|
67
|
-
|
68
|
-
"--
|
88
|
+
alignment_group.add_argument(
|
89
|
+
"--angles_are_vector",
|
90
|
+
action="store_true",
|
69
91
|
required=False,
|
70
|
-
|
71
|
-
|
72
|
-
"euler_y and euler_x are assumed to be a vector that will be rotated to match "
|
73
|
-
"alignment_vector.",
|
92
|
+
help="Considers euler_z euler_y, euler_x as vector that will be rotated to align "
|
93
|
+
"with the z-axis (1,0,0). Only considered when --align_orientations is set."
|
74
94
|
)
|
75
|
-
|
95
|
+
alignment_group.add_argument(
|
76
96
|
"--interpolation_order",
|
77
97
|
dest="interpolation_order",
|
78
98
|
required=False,
|
79
99
|
type=int,
|
80
100
|
default=1,
|
81
|
-
help="
|
82
|
-
"no interpolation is performed.",
|
101
|
+
help="Interpolation order for alignment, less than zero is no interpolation."
|
83
102
|
)
|
103
|
+
|
104
|
+
extraction_group = parser.add_argument_group("Extraction")
|
84
105
|
extraction_group.add_argument(
|
85
|
-
"--
|
86
|
-
dest="translation_uncertainty",
|
106
|
+
"--box_size",
|
87
107
|
required=False,
|
88
108
|
type=int,
|
89
|
-
|
90
|
-
help="Creates a cented spherical target mask with given radius in voxel.",
|
109
|
+
help="Box size for extraction, defaults to two times the template.",
|
91
110
|
)
|
92
111
|
extraction_group.add_argument(
|
93
|
-
"--
|
94
|
-
|
112
|
+
"--keep_out_of_box",
|
113
|
+
action="store_true",
|
95
114
|
required=False,
|
96
|
-
|
97
|
-
|
98
|
-
help="Path to write spherical mask to, defaults to target_mask.h5.",
|
115
|
+
help="Whether to keep orientations that fall outside the box. If the "
|
116
|
+
"orientations are sensible, it is safe to pass this flag.",
|
99
117
|
)
|
118
|
+
|
100
119
|
args = parser.parse_args()
|
101
120
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
121
|
+
data_present = args.target is not None and args.template is not None
|
122
|
+
if args.input_file is None and not data_present:
|
123
|
+
raise ValueError(
|
124
|
+
"Either --input_file or --target and --template need to be specified."
|
125
|
+
)
|
126
|
+
elif args.input_file is not None and data_present:
|
127
|
+
raise ValueError(
|
128
|
+
"Please specific either --input_file or --target and --template."
|
129
|
+
)
|
106
130
|
|
107
131
|
return args
|
108
132
|
|
@@ -111,57 +135,59 @@ def main():
|
|
111
135
|
args = parse_args()
|
112
136
|
orientations = Orientations.from_file(args.orientations)
|
113
137
|
|
138
|
+
if args.input_file is not None:
|
139
|
+
data = load_pickle(args.input_file)
|
140
|
+
target_origin, _, sampling_rate, cli_args = data[-1]
|
141
|
+
args.target, args.template = cli_args.target, cli_args.template
|
142
|
+
|
114
143
|
target = Density.from_file(args.target, use_memmap=True)
|
115
|
-
template = Density.from_file(args.template)
|
116
144
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
145
|
+
try:
|
146
|
+
template = Density.from_file(args.template)
|
147
|
+
except Exception:
|
148
|
+
template = Density.from_structure(args.template, sampling_rate = target.sampling_rate)
|
149
|
+
|
150
|
+
box_size = args.box_size
|
151
|
+
if box_size is None:
|
152
|
+
box_size = np.multiply(template.shape, 2)
|
153
|
+
box_size = np.array(box_size)
|
154
|
+
box_size = np.repeat(box_size, template.data.ndim // box_size.size).astype(int)
|
155
|
+
|
156
|
+
extraction_shape = np.copy(box_size)
|
157
|
+
if args.align_orientations:
|
158
|
+
extraction_shape[:] = int(np.linalg.norm(box_size) + 1)
|
121
159
|
|
122
|
-
subtomo_shape = np.multiply(box_size, 2).astype(int)
|
123
|
-
extraction_scaling = 3 if args.alignment_vector is not None else 2
|
124
|
-
extraction_shape = np.multiply(box_size, extraction_scaling).astype(int)
|
125
160
|
orientations, cand_slices, obs_slices = orientations.get_extraction_slices(
|
126
161
|
target_shape=target.shape,
|
127
162
|
extraction_shape=extraction_shape,
|
128
|
-
drop_out_of_box=
|
163
|
+
drop_out_of_box=not args.keep_out_of_box,
|
129
164
|
return_orientations=True,
|
130
165
|
)
|
131
166
|
|
167
|
+
if args.align_orientations:
|
168
|
+
orientations.rotations = orientations.rotations.astype(np.float32)
|
169
|
+
for index in range(orientations.rotations.shape[0]):
|
170
|
+
rotation_matrix = euler_to_rotationmatrix(orientations.rotations[index])
|
171
|
+
rotation_matrix = np.linalg.inv(rotation_matrix)
|
172
|
+
if args.angles_are_vector:
|
173
|
+
rotation_matrix = rotation_aligning_vectors(
|
174
|
+
orientations.rotations[index], target_vector=(1,0,0)
|
175
|
+
)
|
176
|
+
orientations.rotations[index] = euler_from_rotationmatrix(rotation_matrix)
|
177
|
+
|
178
|
+
|
132
179
|
filename = generate_tempfile_name()
|
133
180
|
output_dtype = target.data.dtype
|
134
|
-
if args.
|
181
|
+
if args.align_orientations is not None:
|
135
182
|
output_dtype = np.float32
|
136
183
|
|
137
|
-
if args.translation_uncertainty is not None:
|
138
|
-
dens = Density(
|
139
|
-
np.memmap(
|
140
|
-
args.mask_path,
|
141
|
-
mode="w+",
|
142
|
-
shape=(len(obs_slices), *subtomo_shape),
|
143
|
-
dtype=output_dtype,
|
144
|
-
),
|
145
|
-
sampling_rate=(1, *target.sampling_rate),
|
146
|
-
origin=(0, *target.origin),
|
147
|
-
)
|
148
|
-
dens.data[:] = 0
|
149
|
-
mask = create_mask(
|
150
|
-
mask_type="ellipse",
|
151
|
-
center=template.shape,
|
152
|
-
radius=args.translation_uncertainty,
|
153
|
-
shape=subtomo_shape,
|
154
|
-
)
|
155
|
-
dens.data[:] = mask
|
156
|
-
dens.to_file(args.mask_path)
|
157
|
-
|
158
184
|
target.data = target.data.astype(output_dtype)
|
159
185
|
|
160
186
|
dens = Density(
|
161
187
|
np.memmap(
|
162
188
|
filename,
|
163
189
|
mode="w+",
|
164
|
-
shape=(len(obs_slices), *
|
190
|
+
shape=(len(obs_slices), *box_size),
|
165
191
|
dtype=output_dtype,
|
166
192
|
),
|
167
193
|
sampling_rate=(1, *target.sampling_rate),
|
@@ -169,50 +195,56 @@ def main():
|
|
169
195
|
)
|
170
196
|
dens.data[:] = target.metadata["mean"]
|
171
197
|
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
for index, obs_slice in enumerate(obs_slices):
|
179
|
-
print(f"Processing {index:{magnitude}} / {total_slices:{magnitude}}", end="\r")
|
198
|
+
print(target.data.shape)
|
199
|
+
# There appears to be an isseu with the stack creation. Trace this further
|
200
|
+
data_subset = np.zeros(extraction_shape, dtype = target.data.dtype)
|
201
|
+
pbar = ProgressBar(message = "Orientation ", nchars = 80, total = len(obs_slices))
|
202
|
+
for index, (obs_slice, cand_slice) in enumerate(zip(obs_slices, cand_slices)):
|
203
|
+
pbar.update(index + 1)
|
180
204
|
|
205
|
+
data_subset.fill(0)
|
206
|
+
data_subset[cand_slice] = target.data[obs_slice]
|
181
207
|
target_subset = Density(
|
182
|
-
|
208
|
+
data_subset,
|
183
209
|
sampling_rate=target.sampling_rate,
|
184
210
|
origin=target.origin,
|
185
211
|
)
|
186
212
|
|
187
|
-
|
188
|
-
|
189
|
-
normal = orientations.rotations[index]
|
190
|
-
# To visualize only normals were picked we would need to do the opposite
|
191
|
-
# However, this allows us to align everything to the template axis
|
192
|
-
rotation_matrix = rotation_aligning_vectors(
|
193
|
-
normal, target_vector=args.alignment_vector
|
194
|
-
)
|
195
|
-
|
213
|
+
if args.align_orientations:
|
214
|
+
rotation_matrix = euler_to_rotationmatrix(orientations.rotations[index])
|
196
215
|
target_subset = target_subset.rigid_transform(
|
197
216
|
rotation_matrix=rotation_matrix,
|
198
217
|
use_geometric_center=True,
|
199
218
|
order=args.interpolation_order,
|
200
219
|
)
|
201
|
-
target_subset.pad(
|
220
|
+
target_subset.pad(box_size, center=True)
|
221
|
+
|
222
|
+
target_value = target.data[tuple(orientations.translations[index].astype(int))]
|
223
|
+
center = np.divide(target_subset.data.shape, 2).astype(int ) + np.mod(target_subset.shape, 2)
|
224
|
+
print(np.where(target_subset.data == target_value), center)
|
225
|
+
print(target_subset.data[tuple(center.astype(int))],
|
226
|
+
target_value,
|
227
|
+
target_subset.data[tuple(center.astype(int))] == target_value
|
228
|
+
)
|
229
|
+
|
202
230
|
dens.data[index] = target_subset.data
|
203
|
-
|
231
|
+
print("")
|
204
232
|
|
233
|
+
target_meta = {
|
234
|
+
k: v for k, v in target.metadata.items() if k in ("mean", "max", "min", "std")
|
235
|
+
}
|
205
236
|
dens.metadata.update(target_meta)
|
237
|
+
dens.metadata["batch_dimension"] = (0, )
|
238
|
+
|
206
239
|
dens.to_file(args.output_file)
|
207
240
|
orientations.to_file(
|
208
|
-
f"{splitext(args.output_file)}_aligned.tsv",
|
241
|
+
f"{splitext(args.output_file)[0]}_aligned.tsv",
|
209
242
|
file_format="text"
|
210
243
|
)
|
211
244
|
orientations.to_file(
|
212
|
-
f"{splitext(args.output_file)}_aligned.star",
|
245
|
+
f"{splitext(args.output_file)[0]}_aligned.star",
|
213
246
|
file_format="relion"
|
214
247
|
)
|
215
248
|
|
216
|
-
|
217
249
|
if __name__ == "__main__":
|
218
250
|
main()
|