pytme 0.1.9__cp311-cp311-macosx_14_0_arm64.whl → 0.2.0__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/scripts/match_template.py +1019 -0
- pytme-0.2.0.data/scripts/postprocess.py +570 -0
- {pytme-0.1.9.data → pytme-0.2.0.data}/scripts/preprocessor_gui.py +244 -60
- {pytme-0.1.9.dist-info → pytme-0.2.0.dist-info}/METADATA +3 -1
- pytme-0.2.0.dist-info/RECORD +72 -0
- {pytme-0.1.9.dist-info → pytme-0.2.0.dist-info}/WHEEL +1 -1
- scripts/extract_candidates.py +218 -0
- scripts/match_template.py +459 -218
- pytme-0.1.9.data/scripts/match_template.py → scripts/match_template_filters.py +459 -218
- scripts/postprocess.py +380 -435
- scripts/preprocessor_gui.py +244 -60
- scripts/refine_matches.py +218 -0
- tme/__init__.py +2 -1
- tme/__version__.py +1 -1
- tme/analyzer.py +533 -78
- tme/backends/cupy_backend.py +80 -15
- tme/backends/npfftw_backend.py +35 -6
- tme/backends/pytorch_backend.py +15 -7
- tme/density.py +173 -78
- tme/extensions.cpython-311-darwin.so +0 -0
- tme/matching_constrained.py +195 -0
- tme/matching_data.py +76 -33
- tme/matching_exhaustive.py +354 -225
- tme/matching_memory.py +1 -0
- tme/matching_optimization.py +753 -649
- tme/matching_utils.py +152 -8
- tme/orientations.py +561 -0
- tme/preprocessing/__init__.py +2 -0
- tme/preprocessing/_utils.py +176 -0
- tme/preprocessing/composable_filter.py +30 -0
- tme/preprocessing/compose.py +52 -0
- tme/preprocessing/frequency_filters.py +322 -0
- tme/preprocessing/tilt_series.py +967 -0
- tme/preprocessor.py +35 -25
- tme/structure.py +2 -37
- pytme-0.1.9.data/scripts/postprocess.py +0 -625
- pytme-0.1.9.dist-info/RECORD +0 -61
- {pytme-0.1.9.data → pytme-0.2.0.data}/scripts/estimate_ram_usage.py +0 -0
- {pytme-0.1.9.data → pytme-0.2.0.data}/scripts/preprocess.py +0 -0
- {pytme-0.1.9.dist-info → pytme-0.2.0.dist-info}/LICENSE +0 -0
- {pytme-0.1.9.dist-info → pytme-0.2.0.dist-info}/entry_points.txt +0 -0
- {pytme-0.1.9.dist-info → pytme-0.2.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,218 @@
|
|
1
|
+
#!python3
|
2
|
+
""" CLI to simplify analysing the output of match_template.py.
|
3
|
+
|
4
|
+
Copyright (c) 2023 European Molecular Biology Laboratory
|
5
|
+
|
6
|
+
Author: Valentin Maurer <valentin.maurer@embl-hamburg.de>
|
7
|
+
"""
|
8
|
+
import argparse
|
9
|
+
from os.path import splitext
|
10
|
+
|
11
|
+
import numpy as np
|
12
|
+
|
13
|
+
from tme import Density, Orientations
|
14
|
+
from tme.matching_utils import (
|
15
|
+
create_mask,
|
16
|
+
generate_tempfile_name,
|
17
|
+
rotation_aligning_vectors,
|
18
|
+
euler_from_rotationmatrix,
|
19
|
+
)
|
20
|
+
|
21
|
+
|
22
|
+
def parse_args():
|
23
|
+
parser = argparse.ArgumentParser(
|
24
|
+
description="Extract matching candidates for further refinement."
|
25
|
+
)
|
26
|
+
|
27
|
+
io_group = parser.add_argument_group("Input / Output")
|
28
|
+
io_group.add_argument(
|
29
|
+
"--input_file",
|
30
|
+
required=False,
|
31
|
+
type=str,
|
32
|
+
help="Path to the output of match_template.py.",
|
33
|
+
)
|
34
|
+
io_group.add_argument(
|
35
|
+
"--orientations",
|
36
|
+
required=True,
|
37
|
+
type=str,
|
38
|
+
help="Path to file generated by postprocess.py using output_format orientations.",
|
39
|
+
)
|
40
|
+
io_group.add_argument(
|
41
|
+
"--target",
|
42
|
+
required=False,
|
43
|
+
type=str,
|
44
|
+
help="Extract candidates from this target, can be at different sampling rate.",
|
45
|
+
)
|
46
|
+
io_group.add_argument(
|
47
|
+
"--template",
|
48
|
+
required=False,
|
49
|
+
type=str,
|
50
|
+
help="Extract candidates from this target, can be at different sampling rate.",
|
51
|
+
)
|
52
|
+
io_group.add_argument(
|
53
|
+
"-o",
|
54
|
+
"--output_file",
|
55
|
+
required=False,
|
56
|
+
type=str,
|
57
|
+
help="Path to output HDF5 file.",
|
58
|
+
)
|
59
|
+
|
60
|
+
extraction_group = parser.add_argument_group("Extraction")
|
61
|
+
extraction_group.add_argument(
|
62
|
+
"--box_size",
|
63
|
+
required=False,
|
64
|
+
type=int,
|
65
|
+
help="Box size for extraction, defaults to two times the template box.",
|
66
|
+
)
|
67
|
+
extraction_group.add_argument(
|
68
|
+
"--alignment_vector",
|
69
|
+
required=False,
|
70
|
+
type=str,
|
71
|
+
help="Vector to align extracted coordinate to e.g. '1,0,0'. If provided, euler_z"
|
72
|
+
"euler_y and euler_x are assumed to be a vector that will be rotated to match "
|
73
|
+
"alignment_vector.",
|
74
|
+
)
|
75
|
+
extraction_group.add_argument(
|
76
|
+
"--interpolation_order",
|
77
|
+
dest="interpolation_order",
|
78
|
+
required=False,
|
79
|
+
type=int,
|
80
|
+
default=1,
|
81
|
+
help="Spline interpolation used for template rotations. If less than zero "
|
82
|
+
"no interpolation is performed.",
|
83
|
+
)
|
84
|
+
extraction_group.add_argument(
|
85
|
+
"--translation_uncertainty",
|
86
|
+
dest="translation_uncertainty",
|
87
|
+
required=False,
|
88
|
+
type=int,
|
89
|
+
default=None,
|
90
|
+
help="Creates a cented spherical target mask with given radius in voxel.",
|
91
|
+
)
|
92
|
+
extraction_group.add_argument(
|
93
|
+
"--mask_path",
|
94
|
+
dest="mask_path",
|
95
|
+
required=False,
|
96
|
+
type=str,
|
97
|
+
default="target_mask.h5",
|
98
|
+
help="Path to write spherical mask to, defaults to target_mask.h5.",
|
99
|
+
)
|
100
|
+
args = parser.parse_args()
|
101
|
+
|
102
|
+
if args.alignment_vector is not None:
|
103
|
+
args.alignment_vector = [float(x) for x in args.alignment_vector.split(",")]
|
104
|
+
if len(args.alignment_vector) != 3:
|
105
|
+
raise ValueError("Only three-dimensional vectors are supported")
|
106
|
+
|
107
|
+
return args
|
108
|
+
|
109
|
+
|
110
|
+
def main():
|
111
|
+
args = parse_args()
|
112
|
+
orientations = Orientations.from_file(args.orientations)
|
113
|
+
|
114
|
+
target = Density.from_file(args.target, use_memmap=True)
|
115
|
+
template = Density.from_file(args.template)
|
116
|
+
|
117
|
+
box_size = template.shape
|
118
|
+
if args.box_size is not None:
|
119
|
+
args.box_size = args.box_size // 2
|
120
|
+
box_size = np.full(template.data.ndim, fill_value=args.box_size, dtype=int)
|
121
|
+
|
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
|
+
orientations, cand_slices, obs_slices = orientations.get_extraction_slices(
|
126
|
+
target_shape=target.shape,
|
127
|
+
extraction_shape=extraction_shape,
|
128
|
+
drop_out_of_box=True,
|
129
|
+
return_orientations=True,
|
130
|
+
)
|
131
|
+
|
132
|
+
filename = generate_tempfile_name()
|
133
|
+
output_dtype = target.data.dtype
|
134
|
+
if args.alignment_vector is not None:
|
135
|
+
output_dtype = np.float32
|
136
|
+
|
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
|
+
target.data = target.data.astype(output_dtype)
|
159
|
+
|
160
|
+
dens = Density(
|
161
|
+
np.memmap(
|
162
|
+
filename,
|
163
|
+
mode="w+",
|
164
|
+
shape=(len(obs_slices), *subtomo_shape),
|
165
|
+
dtype=output_dtype,
|
166
|
+
),
|
167
|
+
sampling_rate=(1, *target.sampling_rate),
|
168
|
+
origin=(0, *target.origin),
|
169
|
+
)
|
170
|
+
dens.data[:] = target.metadata["mean"]
|
171
|
+
|
172
|
+
target_meta = {
|
173
|
+
k: v for k, v in target.metadata.items() if k in ("mean", "max", "min", "std")
|
174
|
+
}
|
175
|
+
|
176
|
+
total_slices = len(obs_slices)
|
177
|
+
magnitude = len(str(total_slices))
|
178
|
+
for index, obs_slice in enumerate(obs_slices):
|
179
|
+
print(f"Processing {index:{magnitude}} / {total_slices:{magnitude}}", end="\r")
|
180
|
+
|
181
|
+
target_subset = Density(
|
182
|
+
target.data[obs_slice],
|
183
|
+
sampling_rate=target.sampling_rate,
|
184
|
+
origin=target.origin,
|
185
|
+
)
|
186
|
+
|
187
|
+
rotation_matrix = np.eye(target_subset.data.ndim)
|
188
|
+
if args.alignment_vector is not None:
|
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
|
+
|
196
|
+
target_subset = target_subset.rigid_transform(
|
197
|
+
rotation_matrix=rotation_matrix,
|
198
|
+
use_geometric_center=True,
|
199
|
+
order=args.interpolation_order,
|
200
|
+
)
|
201
|
+
target_subset.pad(subtomo_shape, center=True)
|
202
|
+
dens.data[index] = target_subset.data
|
203
|
+
orientations.rotations[index] = euler_from_rotationmatrix(rotation_matrix)
|
204
|
+
|
205
|
+
dens.metadata.update(target_meta)
|
206
|
+
dens.to_file(args.output_file)
|
207
|
+
orientations.to_file(
|
208
|
+
f"{splitext(args.output_file)}_aligned.tsv",
|
209
|
+
file_format="text"
|
210
|
+
)
|
211
|
+
orientations.to_file(
|
212
|
+
f"{splitext(args.output_file)}_aligned.star",
|
213
|
+
file_format="relion"
|
214
|
+
)
|
215
|
+
|
216
|
+
|
217
|
+
if __name__ == "__main__":
|
218
|
+
main()
|