pytme 0.1.8__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.
Files changed (42) hide show
  1. pytme-0.2.0.data/scripts/match_template.py +1019 -0
  2. pytme-0.2.0.data/scripts/postprocess.py +570 -0
  3. {pytme-0.1.8.data → pytme-0.2.0.data}/scripts/preprocessor_gui.py +244 -60
  4. {pytme-0.1.8.dist-info → pytme-0.2.0.dist-info}/METADATA +3 -1
  5. pytme-0.2.0.dist-info/RECORD +72 -0
  6. {pytme-0.1.8.dist-info → pytme-0.2.0.dist-info}/WHEEL +1 -1
  7. scripts/extract_candidates.py +218 -0
  8. scripts/match_template.py +459 -218
  9. pytme-0.1.8.data/scripts/match_template.py → scripts/match_template_filters.py +459 -218
  10. scripts/postprocess.py +380 -435
  11. scripts/preprocessor_gui.py +244 -60
  12. scripts/refine_matches.py +218 -0
  13. tme/__init__.py +2 -1
  14. tme/__version__.py +1 -1
  15. tme/analyzer.py +533 -78
  16. tme/backends/cupy_backend.py +80 -15
  17. tme/backends/npfftw_backend.py +35 -6
  18. tme/backends/pytorch_backend.py +15 -7
  19. tme/density.py +173 -78
  20. tme/extensions.cpython-311-darwin.so +0 -0
  21. tme/matching_constrained.py +195 -0
  22. tme/matching_data.py +78 -32
  23. tme/matching_exhaustive.py +369 -221
  24. tme/matching_memory.py +1 -0
  25. tme/matching_optimization.py +753 -649
  26. tme/matching_utils.py +152 -8
  27. tme/orientations.py +561 -0
  28. tme/preprocessing/__init__.py +2 -0
  29. tme/preprocessing/_utils.py +176 -0
  30. tme/preprocessing/composable_filter.py +30 -0
  31. tme/preprocessing/compose.py +52 -0
  32. tme/preprocessing/frequency_filters.py +322 -0
  33. tme/preprocessing/tilt_series.py +967 -0
  34. tme/preprocessor.py +35 -25
  35. tme/structure.py +2 -37
  36. pytme-0.1.8.data/scripts/postprocess.py +0 -625
  37. pytme-0.1.8.dist-info/RECORD +0 -61
  38. {pytme-0.1.8.data → pytme-0.2.0.data}/scripts/estimate_ram_usage.py +0 -0
  39. {pytme-0.1.8.data → pytme-0.2.0.data}/scripts/preprocess.py +0 -0
  40. {pytme-0.1.8.dist-info → pytme-0.2.0.dist-info}/LICENSE +0 -0
  41. {pytme-0.1.8.dist-info → pytme-0.2.0.dist-info}/entry_points.txt +0 -0
  42. {pytme-0.1.8.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()