pytme 0.3b0.post1__cp311-cp311-macosx_15_0_arm64.whl → 0.3.1.dev20250731__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.3.1.dev20250731.data/scripts/estimate_ram_usage.py +97 -0
- {pytme-0.3b0.post1.data → pytme-0.3.1.dev20250731.data}/scripts/match_template.py +30 -41
- {pytme-0.3b0.post1.data → pytme-0.3.1.dev20250731.data}/scripts/postprocess.py +35 -21
- {pytme-0.3b0.post1.data → pytme-0.3.1.dev20250731.data}/scripts/preprocessor_gui.py +96 -24
- pytme-0.3.1.dev20250731.data/scripts/pytme_runner.py +1223 -0
- {pytme-0.3b0.post1.dist-info → pytme-0.3.1.dev20250731.dist-info}/METADATA +5 -7
- {pytme-0.3b0.post1.dist-info → pytme-0.3.1.dev20250731.dist-info}/RECORD +59 -49
- scripts/estimate_ram_usage.py +97 -0
- scripts/extract_candidates.py +118 -99
- scripts/match_template.py +30 -41
- scripts/match_template_devel.py +1339 -0
- scripts/postprocess.py +35 -21
- scripts/preprocessor_gui.py +96 -24
- scripts/pytme_runner.py +644 -190
- scripts/refine_matches.py +158 -390
- tests/data/.DS_Store +0 -0
- tests/data/Blurring/.DS_Store +0 -0
- tests/data/Maps/.DS_Store +0 -0
- tests/data/Raw/.DS_Store +0 -0
- tests/data/Structures/.DS_Store +0 -0
- tests/preprocessing/test_utils.py +18 -0
- tests/test_analyzer.py +2 -3
- tests/test_backends.py +3 -9
- tests/test_density.py +0 -1
- tests/test_extensions.py +0 -1
- tests/test_matching_utils.py +10 -60
- tests/test_orientations.py +0 -12
- tests/test_rotations.py +1 -1
- tme/__version__.py +1 -1
- tme/analyzer/_utils.py +4 -4
- tme/analyzer/aggregation.py +35 -15
- tme/analyzer/peaks.py +11 -10
- tme/backends/_jax_utils.py +64 -18
- tme/backends/_numpyfftw_utils.py +270 -0
- tme/backends/cupy_backend.py +16 -55
- tme/backends/jax_backend.py +79 -40
- tme/backends/matching_backend.py +17 -51
- tme/backends/mlx_backend.py +1 -27
- tme/backends/npfftw_backend.py +71 -65
- tme/backends/pytorch_backend.py +1 -26
- tme/density.py +58 -5
- tme/extensions.cpython-311-darwin.so +0 -0
- tme/filters/ctf.py +22 -21
- tme/filters/wedge.py +10 -7
- tme/mask.py +341 -0
- tme/matching_data.py +31 -19
- tme/matching_exhaustive.py +37 -47
- tme/matching_optimization.py +2 -1
- tme/matching_scores.py +229 -411
- tme/matching_utils.py +73 -422
- tme/memory.py +1 -1
- tme/orientations.py +24 -13
- tme/rotations.py +1 -1
- pytme-0.3b0.post1.data/scripts/pytme_runner.py +0 -769
- {pytme-0.3b0.post1.data → pytme-0.3.1.dev20250731.data}/scripts/estimate_memory_usage.py +0 -0
- {pytme-0.3b0.post1.data → pytme-0.3.1.dev20250731.data}/scripts/preprocess.py +0 -0
- {pytme-0.3b0.post1.dist-info → pytme-0.3.1.dev20250731.dist-info}/WHEEL +0 -0
- {pytme-0.3b0.post1.dist-info → pytme-0.3.1.dev20250731.dist-info}/entry_points.txt +0 -0
- {pytme-0.3b0.post1.dist-info → pytme-0.3.1.dev20250731.dist-info}/licenses/LICENSE +0 -0
- {pytme-0.3b0.post1.dist-info → pytme-0.3.1.dev20250731.dist-info}/top_level.txt +0 -0
scripts/refine_matches.py
CHANGED
@@ -1,34 +1,42 @@
|
|
1
1
|
#!python3
|
2
|
-
"""
|
2
|
+
"""Iterative template matching parameter tuning.
|
3
3
|
|
4
|
-
|
4
|
+
Copyright (c) 2024 European Molecular Biology Laboratory
|
5
5
|
|
6
|
-
|
6
|
+
Author: Valentin Maurer <valentin.maurer@embl-hamburg.de>
|
7
7
|
"""
|
8
8
|
import argparse
|
9
9
|
import subprocess
|
10
10
|
from sys import exit
|
11
|
+
from os import unlink
|
11
12
|
from time import time
|
12
|
-
from shutil import copyfile
|
13
13
|
from typing import Tuple, List, Dict
|
14
14
|
|
15
15
|
import numpy as np
|
16
|
-
from scipy import optimize
|
17
16
|
from sklearn.metrics import roc_auc_score
|
18
17
|
|
19
18
|
from tme import Orientations, Density
|
20
|
-
from tme.
|
19
|
+
from tme.backends import backend as be
|
20
|
+
from tme.matching_utils import generate_tempfile_name, create_mask
|
21
21
|
from tme.matching_exhaustive import MATCHING_EXHAUSTIVE_REGISTER
|
22
22
|
|
23
|
-
|
24
|
-
|
23
|
+
|
24
|
+
def parse_range(x: str):
|
25
|
+
start, stop, step = x.split(":")
|
25
26
|
return range(int(start), int(stop), int(step))
|
26
27
|
|
28
|
+
|
27
29
|
def parse_args():
|
28
30
|
parser = argparse.ArgumentParser(
|
29
31
|
description="Refine template matching candidates using deep matching.",
|
30
32
|
)
|
31
33
|
io_group = parser.add_argument_group("Input / Output")
|
34
|
+
io_group.add_argument(
|
35
|
+
"--target",
|
36
|
+
required=True,
|
37
|
+
type=str,
|
38
|
+
help="Image stack created using extract_candidates.py.",
|
39
|
+
)
|
32
40
|
io_group.add_argument(
|
33
41
|
"--orientations",
|
34
42
|
required=True,
|
@@ -38,72 +46,52 @@ def parse_args():
|
|
38
46
|
" for available options.",
|
39
47
|
)
|
40
48
|
io_group.add_argument(
|
41
|
-
"--
|
49
|
+
"--output-prefix", required=True, type=str, help="Path to write output to."
|
42
50
|
)
|
43
51
|
io_group.add_argument(
|
44
|
-
"--
|
45
|
-
|
46
|
-
default=
|
47
|
-
|
48
|
-
help="Number of refinement iterations to perform.",
|
52
|
+
"--save-pickles",
|
53
|
+
action="store_true",
|
54
|
+
default=False,
|
55
|
+
help="Save intermediate results as pickle files in output directory.",
|
49
56
|
)
|
50
57
|
io_group.add_argument(
|
51
|
-
"--
|
58
|
+
"--save-orientations",
|
52
59
|
action="store_true",
|
53
60
|
default=False,
|
54
|
-
help="
|
61
|
+
help="Save orientation results in output directory.",
|
55
62
|
)
|
56
63
|
matching_group = parser.add_argument_group("Template Matching")
|
57
|
-
matching_group.add_argument(
|
58
|
-
"--input_file",
|
59
|
-
required=False,
|
60
|
-
type=str,
|
61
|
-
help="Path to the output of match_template.py.",
|
62
|
-
)
|
63
|
-
matching_group.add_argument(
|
64
|
-
"-m",
|
65
|
-
"--target",
|
66
|
-
dest="target",
|
67
|
-
type=str,
|
68
|
-
required=False,
|
69
|
-
help="Path to a target in CCP4/MRC, EM, H5 or another format supported by "
|
70
|
-
"tme.density.Density.from_file "
|
71
|
-
"https://kosinskilab.github.io/pyTME/reference/api/tme.density.Density.from_file.html",
|
72
|
-
)
|
73
|
-
matching_group.add_argument(
|
74
|
-
"--target_mask",
|
75
|
-
dest="target_mask",
|
76
|
-
type=str,
|
77
|
-
required=False,
|
78
|
-
help="Path to a mask for the target in a supported format (see target).",
|
79
|
-
)
|
80
64
|
matching_group.add_argument(
|
81
65
|
"-i",
|
82
66
|
"--template",
|
83
|
-
dest="template",
|
84
67
|
type=str,
|
85
|
-
required=
|
68
|
+
required=True,
|
86
69
|
help="Path to a template in PDB/MMCIF or other supported formats (see target).",
|
87
70
|
)
|
88
71
|
matching_group.add_argument(
|
89
|
-
"--
|
90
|
-
dest="template_mask",
|
72
|
+
"--template-mask",
|
91
73
|
type=str,
|
92
74
|
required=False,
|
93
75
|
help="Path to a mask for the template in a supported format (see target).",
|
94
76
|
)
|
95
77
|
matching_group.add_argument(
|
96
|
-
"--
|
97
|
-
|
78
|
+
"--ctf-file",
|
79
|
+
type=str,
|
80
|
+
required=False,
|
81
|
+
default=None,
|
82
|
+
help="Path to a file with CTF parameters. This can be a Warp/M XML file "
|
83
|
+
"a GCTF/Relion STAR file, an MDOC file, or the output of CTFFIND4. If the file "
|
84
|
+
" does not specify tilt angles, --tilt-angles are used.",
|
85
|
+
)
|
86
|
+
matching_group.add_argument(
|
87
|
+
"--invert-target-contrast",
|
98
88
|
action="store_true",
|
99
89
|
default=False,
|
100
|
-
help="Invert the target's contrast
|
101
|
-
"This option is intended for targets where templates to-be-matched have "
|
90
|
+
help="Invert the target's contrast for cases where templates to-be-matched have "
|
102
91
|
"negative values, e.g. tomograms.",
|
103
92
|
)
|
104
93
|
matching_group.add_argument(
|
105
|
-
"--
|
106
|
-
dest="angular_sampling",
|
94
|
+
"--angular-sampling",
|
107
95
|
required=True,
|
108
96
|
default=None,
|
109
97
|
help="Angular sampling rate using optimized rotational sets."
|
@@ -111,13 +99,15 @@ def parse_args():
|
|
111
99
|
)
|
112
100
|
matching_group.add_argument(
|
113
101
|
"-s",
|
114
|
-
|
102
|
+
"--score",
|
115
103
|
type=str,
|
116
|
-
default="
|
104
|
+
default="batchFLCSphericalMask",
|
117
105
|
choices=list(MATCHING_EXHAUSTIVE_REGISTER.keys()),
|
118
106
|
help="Template matching scoring function.",
|
119
107
|
)
|
120
|
-
|
108
|
+
|
109
|
+
computation_group = parser.add_argument_group("Computation")
|
110
|
+
computation_group.add_argument(
|
121
111
|
"-n",
|
122
112
|
dest="cores",
|
123
113
|
required=False,
|
@@ -125,113 +115,44 @@ def parse_args():
|
|
125
115
|
default=4,
|
126
116
|
help="Number of cores used for template matching.",
|
127
117
|
)
|
128
|
-
|
129
|
-
"--
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
help="Whether to perform computations on the GPU.",
|
134
|
-
)
|
135
|
-
matching_group.add_argument(
|
136
|
-
"--no_centering",
|
137
|
-
dest="no_centering",
|
138
|
-
action="store_true",
|
139
|
-
help="Assumes the template is already centered and omits centering.",
|
140
|
-
)
|
141
|
-
matching_group.add_argument(
|
142
|
-
"--no_edge_padding",
|
143
|
-
dest="no_edge_padding",
|
144
|
-
action="store_true",
|
145
|
-
default=False,
|
146
|
-
help="Whether to not pad the edges of the target. Can be set if the target"
|
147
|
-
" has a well defined bounding box, e.g. a masked reconstruction.",
|
148
|
-
)
|
149
|
-
matching_group.add_argument(
|
150
|
-
"--no_fourier_padding",
|
151
|
-
dest="no_fourier_padding",
|
152
|
-
action="store_true",
|
153
|
-
default=False,
|
154
|
-
help="Whether input arrays should not be zero-padded to full convolution shape "
|
155
|
-
"for numerical stability. When working with very large targets, e.g. tomograms, "
|
156
|
-
"it is safe to use this flag and benefit from the performance gain.",
|
157
|
-
)
|
158
|
-
|
159
|
-
peak_group = parser.add_argument_group("Peak Calling")
|
160
|
-
peak_group.add_argument(
|
161
|
-
"--number_of_peaks",
|
162
|
-
type=int,
|
163
|
-
default=100,
|
164
|
-
required=False,
|
165
|
-
help="Upper limit of peaks to call, subject to filtering parameters. Default 1000. "
|
166
|
-
"If minimum_score is provided all peaks scoring higher will be reported.",
|
167
|
-
)
|
168
|
-
extraction_group = parser.add_argument_group("Extraction")
|
169
|
-
extraction_group.add_argument(
|
170
|
-
"--keep_out_of_box",
|
171
|
-
action="store_true",
|
172
|
-
required=False,
|
173
|
-
help="Whether to keep orientations that fall outside the box. If the "
|
174
|
-
"orientations are sensible, it is safe to pass this flag.",
|
118
|
+
computation_group.add_argument(
|
119
|
+
"--backend",
|
120
|
+
default=be._backend_name,
|
121
|
+
choices=be.available_backends(),
|
122
|
+
help="Set computation backend.",
|
175
123
|
)
|
176
124
|
|
177
125
|
optimization_group = parser.add_argument_group("Optimization")
|
178
|
-
optimization_group.add_argument(
|
179
|
-
"--lowpass",
|
180
|
-
dest="lowpass",
|
181
|
-
action="store_true",
|
182
|
-
default=False,
|
183
|
-
help="Optimize template matching lowpass filter cutoff.",
|
184
|
-
)
|
185
|
-
optimization_group.add_argument(
|
186
|
-
"--highpass",
|
187
|
-
dest="highpass",
|
188
|
-
action="store_true",
|
189
|
-
default=False,
|
190
|
-
help="Optimize template matching highpass filter cutoff.",
|
191
|
-
)
|
192
126
|
optimization_group.add_argument(
|
193
127
|
"--lowpass-range",
|
194
|
-
dest="lowpass_range",
|
195
128
|
type=str,
|
196
129
|
default="0:50:5",
|
197
130
|
help="Optimize template matching lowpass filter cutoff.",
|
198
131
|
)
|
199
132
|
optimization_group.add_argument(
|
200
133
|
"--highpass-range",
|
201
|
-
dest="highpass_range",
|
202
134
|
type=str,
|
203
135
|
default="0:50:5",
|
204
136
|
help="Optimize template matching highpass filter cutoff.",
|
205
137
|
)
|
206
138
|
optimization_group.add_argument(
|
207
139
|
"--translation-uncertainty",
|
208
|
-
dest="translation_uncertainty",
|
209
140
|
type=int,
|
210
|
-
default=
|
211
|
-
help="
|
141
|
+
default=8,
|
142
|
+
help="Translational uncertainty for masking, defaults to 8.",
|
212
143
|
)
|
213
144
|
|
214
|
-
|
215
145
|
args = parser.parse_args()
|
216
146
|
|
217
|
-
|
218
|
-
if args.input_file is None and not data_present:
|
219
|
-
raise ValueError(
|
220
|
-
"Either --input_file or --target and --template need to be specified."
|
221
|
-
)
|
222
|
-
elif args.input_file is not None and data_present:
|
223
|
-
raise ValueError(
|
224
|
-
"Please specific either --input_file or --target and --template."
|
225
|
-
)
|
226
|
-
|
147
|
+
args.target_mask = None
|
227
148
|
if args.lowpass_range != "None":
|
228
149
|
args.lowpass_range = parse_range(args.lowpass_range)
|
229
150
|
else:
|
230
|
-
args.lowpass_range = (None,
|
151
|
+
args.lowpass_range = (None,)
|
231
152
|
if args.highpass_range != "None":
|
232
153
|
args.highpass_range = parse_range(args.highpass_range)
|
233
154
|
else:
|
234
|
-
args.highpass_range = (None,
|
155
|
+
args.highpass_range = (None,)
|
235
156
|
return args
|
236
157
|
|
237
158
|
|
@@ -250,6 +171,7 @@ def argdict_to_command(input_args: Dict, executable: str) -> List:
|
|
250
171
|
ret.insert(0, executable)
|
251
172
|
return " ".join(ret)
|
252
173
|
|
174
|
+
|
253
175
|
def run_command(command):
|
254
176
|
ret = subprocess.run(command, capture_output=True, shell=True)
|
255
177
|
if ret.returncode != 0:
|
@@ -260,52 +182,42 @@ def run_command(command):
|
|
260
182
|
|
261
183
|
return None
|
262
184
|
|
263
|
-
def create_stacking_argdict(args) -> Dict:
|
264
|
-
arg_dict = {
|
265
|
-
"--target": args.target,
|
266
|
-
"--template": args.template,
|
267
|
-
"--orientations": args.orientations,
|
268
|
-
"--output_file": args.candidate_stack_path,
|
269
|
-
"--keep_out_of_box": args.keep_out_of_box,
|
270
|
-
}
|
271
|
-
return arg_dict
|
272
|
-
|
273
185
|
|
274
186
|
def create_matching_argdict(args) -> Dict:
|
275
187
|
arg_dict = {
|
276
188
|
"--target": args.target,
|
277
189
|
"--template": args.template,
|
278
|
-
"--
|
279
|
-
"
|
190
|
+
"--template-mask": args.template_mask,
|
191
|
+
"--output": args.match_template_path,
|
280
192
|
"-a": args.angular_sampling,
|
281
193
|
"-s": args.score,
|
282
|
-
"--no_fourier_padding": True,
|
283
|
-
"--no_edge_padding": True,
|
284
|
-
"--no_centering": args.no_centering,
|
285
194
|
"-n": args.cores,
|
286
|
-
"--
|
287
|
-
"--
|
195
|
+
"--ctf-file": args.ctf_file,
|
196
|
+
"--invert-target-contrast": args.invert_target_contrast,
|
197
|
+
"--backend" : args.backend,
|
288
198
|
}
|
289
199
|
return arg_dict
|
290
200
|
|
291
201
|
|
292
202
|
def create_postprocessing_argdict(args) -> Dict:
|
293
203
|
arg_dict = {
|
294
|
-
"--
|
295
|
-
"--
|
296
|
-
"--
|
297
|
-
"--
|
298
|
-
"--
|
299
|
-
"--
|
300
|
-
"--
|
204
|
+
"--input-file": args.match_template_path,
|
205
|
+
"--target-mask": args.target_mask,
|
206
|
+
"--output-prefix": args.new_orientations_path,
|
207
|
+
"--peak-caller": "PeakCallerMaximumFilter",
|
208
|
+
"--num-peaks": 1,
|
209
|
+
"--output-format": "orientations",
|
210
|
+
"--mask-edges": True,
|
301
211
|
}
|
302
212
|
if args.target_mask is not None:
|
303
|
-
arg_dict["--
|
213
|
+
arg_dict["--mask-edges"] = False
|
304
214
|
return arg_dict
|
305
215
|
|
306
216
|
|
307
|
-
def update_orientations(
|
308
|
-
|
217
|
+
def update_orientations(
|
218
|
+
old: Orientations, new: Orientations, args, **kwargs
|
219
|
+
) -> Orientations:
|
220
|
+
stack_shape = Density.from_file(args.target, use_memmap=True).shape
|
309
221
|
stack_center = np.add(np.divide(stack_shape, 2).astype(int), np.mod(stack_shape, 2))
|
310
222
|
|
311
223
|
peak_number = new.translations[:, 0].astype(int)
|
@@ -315,34 +227,44 @@ def update_orientations(old : Orientations, new : Orientations, args, **kwargs)
|
|
315
227
|
)
|
316
228
|
ret = old.copy()
|
317
229
|
ret.scores[:] = 0
|
230
|
+
|
318
231
|
ret.scores[peak_number] = new.scores
|
319
232
|
ret.translations[peak_number] = new_translations
|
320
233
|
|
321
|
-
# The effect of --align_orientations should be handled
|
234
|
+
# The effect of --align_orientations should be handled here
|
235
|
+
ret.rotations[peak_number] = new.rotations
|
322
236
|
return ret
|
323
237
|
|
324
238
|
|
325
239
|
class DeepMatcher:
|
326
|
-
def __init__(self, args, margin
|
240
|
+
def __init__(self, args, margin: float = 0.5):
|
327
241
|
self.args = args
|
328
242
|
self.margin = margin
|
329
243
|
self.orientations = Orientations.from_file(args.orientations)
|
330
244
|
|
331
245
|
match_template_args = create_matching_argdict(args)
|
332
|
-
match_template_args["--target"] = args.
|
246
|
+
match_template_args["--target"] = args.target
|
333
247
|
self.match_template_args = match_template_args
|
334
248
|
|
335
249
|
self.filter_parameters = {}
|
336
|
-
if args.
|
250
|
+
if args.lowpass_range:
|
337
251
|
self.filter_parameters["--lowpass"] = 0
|
338
|
-
if args.
|
339
|
-
self.filter_parameters["--highpass"] =
|
340
|
-
# self.filter_parameters["--whiten"] = False
|
341
|
-
self.filter_parameters["--no_filter_target"] = False
|
342
|
-
|
252
|
+
if args.highpass_range:
|
253
|
+
self.filter_parameters["--highpass"] = 0
|
343
254
|
|
344
255
|
self.postprocess_args = create_postprocessing_argdict(args)
|
345
|
-
self.
|
256
|
+
self.log_file = f"{args.output_prefix}_optimization_log.txt"
|
257
|
+
|
258
|
+
header = [
|
259
|
+
"mean_score_positive",
|
260
|
+
"mean_score_negative",
|
261
|
+
"lowpass",
|
262
|
+
"highpass",
|
263
|
+
"auc_score",
|
264
|
+
"duration",
|
265
|
+
]
|
266
|
+
with open(self.log_file, mode="w", encoding="utf-8") as f:
|
267
|
+
_ = f.write(",".join(header) + "\n")
|
346
268
|
|
347
269
|
def get_initial_values(self) -> Tuple[float]:
|
348
270
|
ret = tuple(float(x) for x in self.filter_parameters.values())
|
@@ -356,269 +278,115 @@ class DeepMatcher:
|
|
356
278
|
ret[key] = value > 0.5
|
357
279
|
return ret
|
358
280
|
|
359
|
-
def forward(self, x
|
360
|
-
|
361
|
-
|
281
|
+
def forward(self, x: Tuple[float]):
|
362
282
|
# Label 1 -> True positive, label 0 -> false positive
|
363
283
|
orientations_new = self(x)
|
364
284
|
label, score = orientations_new.details, orientations_new.scores
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
loss = roc_auc_score(label, score)
|
374
|
-
# print(
|
375
|
-
# np.mean(score[label == 1]), np.mean(score[label == 0]),
|
376
|
-
# *x, loss, time()
|
377
|
-
# )
|
378
|
-
|
285
|
+
loss = np.add(
|
286
|
+
(1 - label) * np.square(score),
|
287
|
+
label * np.square(np.fmax(self.margin - score, 0.0)),
|
288
|
+
)
|
289
|
+
loss = loss.mean()
|
379
290
|
return loss
|
380
291
|
|
381
292
|
def __call__(self, x: Tuple[float]):
|
293
|
+
start = time()
|
382
294
|
filter_parameters = self.format_parameters(x)
|
383
295
|
self.match_template_args.update(filter_parameters)
|
384
|
-
match_template = argdict_to_command(
|
385
|
-
self.match_template_args,
|
386
|
-
executable="python3 $HOME/src/pytme/scripts/match_template_filters.py",
|
387
|
-
)
|
388
|
-
run_command(match_template)
|
389
296
|
|
390
|
-
|
391
|
-
|
392
|
-
self.postprocess_args,
|
393
|
-
executable="python3 $HOME/src/pytme/scripts/postprocess.py",
|
394
|
-
)
|
395
|
-
run_command(postprocess)
|
297
|
+
if self.args.save_pickles or self.args.save_orientations:
|
298
|
+
prefix = "_".join([str(y) for y in x])
|
396
299
|
|
397
|
-
|
398
|
-
f"{self.
|
399
|
-
|
400
|
-
|
401
|
-
new=orientations_new,
|
402
|
-
old=self.orientations,
|
403
|
-
args=self.args
|
404
|
-
)
|
405
|
-
|
406
|
-
label, score = orientations_new.details, orientations_new.scores
|
407
|
-
loss = roc_auc_score(label, score)
|
408
|
-
print(
|
409
|
-
np.mean(score[label == 1]), np.mean(score[label == 0]),
|
410
|
-
*x, 0, loss, time()
|
411
|
-
)
|
300
|
+
if self.args.save_pickles:
|
301
|
+
pickle_path = f"{self.args.output_prefix}_{prefix}.pickle"
|
302
|
+
self.match_template_args["--output"] = pickle_path
|
303
|
+
self.postprocess_args["--input-file"] = pickle_path
|
412
304
|
|
305
|
+
if self.args.save_orientations:
|
306
|
+
orientation_path = f"{self.args.output_prefix}_{prefix}"
|
413
307
|
|
414
|
-
# Rerun with noise correction
|
415
|
-
temp_args = self.match_template_args.copy()
|
416
|
-
background_file = generate_tempfile_name(".pickle")
|
417
|
-
temp_args["--scramble_phases"] = True
|
418
|
-
temp_args["-o"] = background_file
|
419
308
|
match_template = argdict_to_command(
|
420
|
-
|
421
|
-
executable="
|
309
|
+
self.match_template_args,
|
310
|
+
executable="match_template",
|
422
311
|
)
|
423
312
|
run_command(match_template)
|
424
|
-
|
425
|
-
|
313
|
+
|
314
|
+
# Assume we get a new peak for each input in the same order
|
426
315
|
postprocess = argdict_to_command(
|
427
316
|
self.postprocess_args,
|
428
|
-
executable="
|
317
|
+
executable="postprocess",
|
429
318
|
)
|
430
319
|
run_command(postprocess)
|
431
320
|
|
432
321
|
orientations_new = Orientations.from_file(
|
433
|
-
f"{self.postprocess_args['--
|
322
|
+
f"{self.postprocess_args['--output-prefix']}.tsv"
|
434
323
|
)
|
435
324
|
orientations_new = update_orientations(
|
436
|
-
new=orientations_new,
|
437
|
-
old=self.orientations,
|
438
|
-
args=self.args
|
325
|
+
new=orientations_new, old=self.orientations, args=self.args
|
439
326
|
)
|
440
327
|
|
328
|
+
if self.args.save_orientations:
|
329
|
+
orientations_new.to_file(f"{orientation_path}.tsv")
|
330
|
+
|
441
331
|
label, score = orientations_new.details, orientations_new.scores
|
442
332
|
loss = roc_auc_score(label, score)
|
443
|
-
print(
|
444
|
-
np.mean(score[label == 1]), np.mean(score[label == 0]),
|
445
|
-
*x, 1, loss, time()
|
446
|
-
)
|
447
333
|
|
448
|
-
|
334
|
+
mean_true = np.mean(score[label == 1])
|
335
|
+
mean_false = np.mean(score[label == 0])
|
336
|
+
params = ",".join([str(y) for y in x])
|
449
337
|
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
# self.match_template_args.update(filter_parameters)
|
454
|
-
# match_template = argdict_to_command(
|
455
|
-
# self.match_template_args,
|
456
|
-
# executable="python3 $HOME/src/pytme/scripts/match_template_filters.py",
|
457
|
-
# )
|
458
|
-
# run_command(match_template)
|
459
|
-
|
460
|
-
# data = load_pickle(self.args.match_template_path)
|
461
|
-
# temp_args = self.match_template_args.copy()
|
462
|
-
# temp_args["--scramble_phases"] = True
|
463
|
-
# # write_pickle(data, "/home/vmaurer/deep_matching/t.pickle")
|
464
|
-
|
465
|
-
# match_template = argdict_to_command(
|
466
|
-
# temp_args,
|
467
|
-
# executable="python3 $HOME/src/pytme/scripts/match_template_filters.py",
|
468
|
-
# )
|
469
|
-
# run_command(match_template)
|
470
|
-
# data_norm = load_pickle(self.args.match_template_path)
|
471
|
-
# # write_pickle(data_norm, "/home/vmaurer/deep_matching/noise.pickle")
|
472
|
-
|
473
|
-
# data[0] = (data[0] - data_norm[0]) / (1 - data_norm[0])
|
474
|
-
# data[0] = np.fmax(data[0], 0)
|
475
|
-
# write_pickle(data, self.args.match_template_path)
|
476
|
-
|
477
|
-
# # Assume we get a new peak for each input in the same order
|
478
|
-
# postprocess = argdict_to_command(
|
479
|
-
# self.postprocess_args,
|
480
|
-
# executable="python3 $HOME/src/pytme/scripts/postprocess.py",
|
481
|
-
# )
|
482
|
-
# run_command(postprocess)
|
483
|
-
|
484
|
-
# orientations_new = Orientations.from_file(
|
485
|
-
# f"{self.postprocess_args['--output_prefix']}.tsv"
|
486
|
-
# )
|
487
|
-
# orientations_new = update_orientations(
|
488
|
-
# new=orientations_new,
|
489
|
-
# old=self.orientations,
|
490
|
-
# args=self.args
|
491
|
-
# )
|
492
|
-
|
493
|
-
# return orientations_new
|
338
|
+
with open(self.log_file, mode="a", encoding="utf-8") as f:
|
339
|
+
_ = f.write(f"{mean_true},{mean_false},{params},{loss},{time()-start}\n")
|
340
|
+
return orientations_new
|
494
341
|
|
495
342
|
|
496
343
|
def main():
|
497
344
|
args = parse_args()
|
498
345
|
|
499
|
-
if args.input_file is not None:
|
500
|
-
data = load_pickle(args.input_file)
|
501
|
-
target_origin, _, sampling_rate, cli_args = data[-1]
|
502
|
-
args.target, args.template = cli_args.target, cli_args.template
|
503
|
-
|
504
|
-
args.candidate_stack_path = generate_tempfile_name(suffix=".h5")
|
505
346
|
args.new_orientations_path = generate_tempfile_name()
|
506
347
|
args.match_template_path = generate_tempfile_name()
|
507
348
|
|
508
|
-
|
509
|
-
initial_values = match_deep.get_initial_values()
|
510
|
-
|
511
|
-
# Do a single pass over the data
|
512
|
-
if len(initial_values) == 0:
|
513
|
-
create_image_stack = create_stacking_argdict(args)
|
514
|
-
create_image_stack = argdict_to_command(
|
515
|
-
create_image_stack,
|
516
|
-
executable="python3 $HOME/src/pytme/scripts/extract_candidates.py",
|
517
|
-
)
|
518
|
-
run_command(create_image_stack)
|
519
|
-
|
520
|
-
print("Created image stack")
|
521
|
-
if args.verbose:
|
522
|
-
copyfile(args.candidate_stack_path, f"{args.output_prefix}_stack.h5")
|
523
|
-
|
524
|
-
print("Starting matching")
|
525
|
-
orientations = match_deep(x=())
|
526
|
-
|
527
|
-
if args.verbose:
|
528
|
-
copyfile(args.match_template_path, f"{args.output_prefix}_stack.pickle")
|
529
|
-
print("Completed matching")
|
530
|
-
orientations.to_file(f"{args.output_prefix}.tsv")
|
531
|
-
exit(0)
|
349
|
+
args.box_size = np.max(Density.from_file(args.template, use_memmap=True).shape)
|
532
350
|
|
351
|
+
args.target_mask = None
|
533
352
|
if args.translation_uncertainty is not None:
|
534
353
|
args.target_mask = generate_tempfile_name(suffix=".h5")
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
540
|
-
|
354
|
+
dens = Density.from_file(args.target)
|
355
|
+
stack_center = np.add(
|
356
|
+
np.divide(dens.data.shape, 2).astype(int), np.mod(dens.data.shape, 2)
|
357
|
+
).astype(int)[1:]
|
358
|
+
|
359
|
+
out = dens.empty
|
360
|
+
out.data[..., :] = create_mask(
|
361
|
+
mask_type="ellipse",
|
362
|
+
center=stack_center,
|
363
|
+
radius=args.translation_uncertainty,
|
364
|
+
shape=dens.data.shape[1:],
|
541
365
|
)
|
542
|
-
|
543
|
-
|
544
|
-
|
545
|
-
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
# for whiten in (False, True):
|
567
|
-
# loss = match_deep.forward((lowpass, highpass, whiten))
|
568
|
-
# # print((lowpass, highpass), loss)
|
569
|
-
# if min_loss is None:
|
570
|
-
# min_loss = loss
|
571
|
-
# if loss < min_loss:
|
572
|
-
# min_loss = loss
|
573
|
-
# parameters = (lowpass, highpass, whiten),
|
574
|
-
|
575
|
-
# for lowpass in (10, 50, 100, 200):
|
576
|
-
# for highpass in (10, 50, 100, 200):
|
577
|
-
for lowpass in args.lowpass_range:
|
578
|
-
for highpass in args.highpass_range:
|
579
|
-
if lowpass is not None and highpass is not None:
|
580
|
-
if lowpass >= highpass:
|
581
|
-
continue
|
582
|
-
for no_filter_target in (True, False):
|
583
|
-
loss = match_deep.forward((lowpass, highpass, no_filter_target))
|
584
|
-
if min_loss is None:
|
585
|
-
min_loss = loss
|
586
|
-
if loss < min_loss:
|
587
|
-
min_loss = loss
|
588
|
-
parameters = (lowpass, highpass, no_filter_target)
|
589
|
-
|
590
|
-
# print("Final output", min_loss, parameters)
|
591
|
-
import sys
|
592
|
-
sys.exit(0)
|
593
|
-
|
594
|
-
# parameters = optimize.minimize(
|
595
|
-
# x0=match_deep.get_initial_values(),
|
596
|
-
# fun=match_deep.forward,
|
597
|
-
# method="L-BFGS-B",
|
598
|
-
# options={"maxiter": 100}
|
599
|
-
# )
|
600
|
-
parameter_dict = match_deep.format_parameters(parameters)
|
601
|
-
print("Converged with parameters", parameters)
|
602
|
-
|
603
|
-
match_template = create_matching_argdict(args)
|
604
|
-
match_template.update(parameter_dict)
|
605
|
-
match_template = argdict_to_command(
|
606
|
-
match_template,
|
607
|
-
executable="python3 $HOME/src/pytme/scripts/match_template_filters.py",
|
608
|
-
)
|
609
|
-
_ = subprocess.run(match_template, capture_output=True, shell=True)
|
610
|
-
|
611
|
-
# Some form of labelling is necessary for these matches
|
612
|
-
# 1. All of them are true positives
|
613
|
-
# 2. All of them are true positives up to a certain threshold
|
614
|
-
# 3. Kernel fitting
|
615
|
-
# 4. Perhaps also sensible to include a certain percentage of low scores as true negatives
|
616
|
-
postprocess = create_postprocessing_argdict(args)
|
617
|
-
postprocess = argdict_to_command(postprocess, executable="postprocess.py")
|
618
|
-
_ = subprocess.run(postprocess, capture_output=True, shell=True)
|
619
|
-
args.orientations = f"{args.new_orientations_path}.tsv"
|
620
|
-
orientations = Orientations.from_file(args.orientations)
|
621
|
-
orientations.to_file(f"{args.output_prefix}_{current_iteration}.tsv")
|
366
|
+
out.to_file(args.target_mask)
|
367
|
+
|
368
|
+
# Perhaps we need a different optimizer here to use sensible steps for each parameter
|
369
|
+
parameters, min_loss = (), None
|
370
|
+
match_deep = DeepMatcher(args)
|
371
|
+
for lowpass in args.lowpass_range:
|
372
|
+
for highpass in args.highpass_range:
|
373
|
+
if lowpass is not None and highpass is not None:
|
374
|
+
if lowpass >= highpass:
|
375
|
+
continue
|
376
|
+
parameters = (lowpass, highpass)
|
377
|
+
loss = match_deep.forward(parameters)
|
378
|
+
if min_loss is None:
|
379
|
+
min_loss, best_params = loss, parameters
|
380
|
+
|
381
|
+
if loss < min_loss:
|
382
|
+
min_loss, best_params = loss, parameters
|
383
|
+
|
384
|
+
unlink(args.target_mask)
|
385
|
+
unlink(args.new_orientations_path)
|
386
|
+
|
387
|
+
if not args.save_pickles:
|
388
|
+
unlink(args.match_template_path)
|
389
|
+
print("Final output", min_loss, best_params)
|
622
390
|
|
623
391
|
|
624
392
|
if __name__ == "__main__":
|