pytme 0.2.2__cp311-cp311-macosx_14_0_arm64.whl → 0.2.4__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 (86) hide show
  1. {pytme-0.2.2.data → pytme-0.2.4.data}/scripts/match_template.py +97 -148
  2. {pytme-0.2.2.data → pytme-0.2.4.data}/scripts/postprocess.py +20 -29
  3. pytme-0.2.4.data/scripts/preprocess.py +148 -0
  4. {pytme-0.2.2.data → pytme-0.2.4.data}/scripts/preprocessor_gui.py +15 -23
  5. {pytme-0.2.2.dist-info → pytme-0.2.4.dist-info}/METADATA +11 -10
  6. pytme-0.2.4.dist-info/RECORD +119 -0
  7. {pytme-0.2.2.dist-info → pytme-0.2.4.dist-info}/WHEEL +1 -1
  8. {pytme-0.2.2.dist-info → pytme-0.2.4.dist-info}/top_level.txt +1 -0
  9. pytme-0.2.2.data/scripts/preprocess.py → scripts/eval.py +1 -1
  10. scripts/match_template.py +97 -148
  11. scripts/postprocess.py +20 -29
  12. scripts/preprocess.py +116 -61
  13. scripts/preprocessor_gui.py +15 -23
  14. tests/__init__.py +0 -0
  15. tests/data/.DS_Store +0 -0
  16. tests/data/Blurring/.DS_Store +0 -0
  17. tests/data/Blurring/blob_width18.npy +0 -0
  18. tests/data/Blurring/edgegaussian_sigma3.npy +0 -0
  19. tests/data/Blurring/gaussian_sigma2.npy +0 -0
  20. tests/data/Blurring/hamming_width6.npy +0 -0
  21. tests/data/Blurring/kaiserb_width18.npy +0 -0
  22. tests/data/Blurring/localgaussian_sigma0510.npy +0 -0
  23. tests/data/Blurring/mean_size5.npy +0 -0
  24. tests/data/Blurring/ntree_sigma0510.npy +0 -0
  25. tests/data/Blurring/rank_rank3.npy +0 -0
  26. tests/data/Maps/.DS_Store +0 -0
  27. tests/data/Maps/emd_8621.mrc.gz +0 -0
  28. tests/data/README.md +2 -0
  29. tests/data/Raw/.DS_Store +0 -0
  30. tests/data/Raw/em_map.map +0 -0
  31. tests/data/Structures/.DS_Store +0 -0
  32. tests/data/Structures/1pdj.cif +3339 -0
  33. tests/data/Structures/1pdj.pdb +1429 -0
  34. tests/data/Structures/5khe.cif +3685 -0
  35. tests/data/Structures/5khe.ent +2210 -0
  36. tests/data/Structures/5khe.pdb +2210 -0
  37. tests/data/Structures/5uz4.cif +70548 -0
  38. tests/preprocessing/__init__.py +0 -0
  39. tests/preprocessing/test_compose.py +76 -0
  40. tests/preprocessing/test_frequency_filters.py +178 -0
  41. tests/preprocessing/test_preprocessor.py +136 -0
  42. tests/preprocessing/test_utils.py +79 -0
  43. tests/test_analyzer.py +310 -0
  44. tests/test_backends.py +375 -0
  45. tests/test_density.py +508 -0
  46. tests/test_extensions.py +130 -0
  47. tests/test_matching_cli.py +283 -0
  48. tests/test_matching_data.py +162 -0
  49. tests/test_matching_exhaustive.py +162 -0
  50. tests/test_matching_memory.py +30 -0
  51. tests/test_matching_optimization.py +276 -0
  52. tests/test_matching_utils.py +326 -0
  53. tests/test_orientations.py +173 -0
  54. tests/test_packaging.py +95 -0
  55. tests/test_parser.py +33 -0
  56. tests/test_structure.py +243 -0
  57. tme/__init__.py +0 -1
  58. tme/__version__.py +1 -1
  59. tme/analyzer.py +9 -6
  60. tme/backends/__init__.py +1 -1
  61. tme/backends/_jax_utils.py +10 -8
  62. tme/backends/cupy_backend.py +2 -7
  63. tme/backends/jax_backend.py +35 -20
  64. tme/backends/npfftw_backend.py +3 -2
  65. tme/backends/pytorch_backend.py +10 -7
  66. tme/data/scattering_factors.pickle +0 -0
  67. tme/density.py +26 -12
  68. tme/extensions.cpython-311-darwin.so +0 -0
  69. tme/external/bindings.cpp +332 -0
  70. tme/matching_data.py +33 -24
  71. tme/matching_exhaustive.py +39 -20
  72. tme/matching_scores.py +5 -2
  73. tme/matching_utils.py +8 -2
  74. tme/orientations.py +26 -9
  75. tme/preprocessing/_utils.py +14 -14
  76. tme/preprocessing/composable_filter.py +5 -4
  77. tme/preprocessing/compose.py +4 -4
  78. tme/preprocessing/frequency_filters.py +32 -35
  79. tme/preprocessing/tilt_series.py +210 -148
  80. tme/preprocessor.py +24 -246
  81. tme/structure.py +14 -14
  82. pytme-0.2.2.dist-info/RECORD +0 -74
  83. tme/matching_memory.py +0 -383
  84. {pytme-0.2.2.data → pytme-0.2.4.data}/scripts/estimate_ram_usage.py +0 -0
  85. {pytme-0.2.2.dist-info → pytme-0.2.4.dist-info}/LICENSE +0 -0
  86. {pytme-0.2.2.dist-info → pytme-0.2.4.dist-info}/entry_points.txt +0 -0
scripts/preprocess.py CHANGED
@@ -1,92 +1,147 @@
1
1
  #!python3
2
- """ Apply tme.preprocessor.Preprocessor methods to an input file based
3
- on a provided yaml configuration obtaiend from preprocessor_gui.py.
2
+ """ Preprocessing routines for template matching.
4
3
 
5
4
  Copyright (c) 2023 European Molecular Biology Laboratory
6
5
 
7
6
  Author: Valentin Maurer <valentin.maurer@embl-hamburg.de>
8
7
  """
9
- import yaml
8
+ import warnings
10
9
  import argparse
11
- import textwrap
12
- from tme import Preprocessor, Density
10
+ import numpy as np
11
+
12
+ from tme import Density, Structure
13
+ from tme.backends import backend as be
14
+ from tme.preprocessing.frequency_filters import BandPassFilter
13
15
 
14
16
 
15
17
  def parse_args():
16
18
  parser = argparse.ArgumentParser(
17
- description=textwrap.dedent(
18
- """
19
- Apply preprocessing to an input file based on a provided YAML configuration.
20
-
21
- Expected YAML file format:
22
- ```yaml
23
- <method_name>:
24
- <parameter1>: <value1>
25
- <parameter2>: <value2>
26
- ...
27
- ```
28
- """
29
- ),
30
- formatter_class=argparse.RawDescriptionHelpFormatter,
19
+ description="Perform template matching preprocessing.",
20
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter,
31
21
  )
32
- parser.add_argument(
33
- "-i",
34
- "--input_file",
22
+
23
+ io_group = parser.add_argument_group("Input / Output")
24
+ io_group.add_argument(
25
+ "-m",
26
+ "--data",
27
+ dest="data",
35
28
  type=str,
36
29
  required=True,
37
- help="Path to the input data file in CCP4/MRC format.",
30
+ help="Path to a file in PDB/MMCIF, CCP4/MRC, EM, H5 or a format supported by "
31
+ "tme.density.Density.from_file "
32
+ "https://kosinskilab.github.io/pyTME/reference/api/tme.density.Density.from_file.html",
38
33
  )
39
- parser.add_argument(
40
- "-y",
41
- "--yaml_file",
34
+ io_group.add_argument(
35
+ "-o",
36
+ "--output",
37
+ dest="output",
42
38
  type=str,
43
39
  required=True,
44
- help="Path to the YAML configuration file.",
40
+ help="Path the output should be written to.",
45
41
  )
46
- parser.add_argument(
47
- "-o",
48
- "--output_file",
49
- type=str,
42
+
43
+ box_group = parser.add_argument_group("Box")
44
+ box_group.add_argument(
45
+ "--box_size",
46
+ dest="box_size",
47
+ type=int,
50
48
  required=True,
51
- help="Path to output file in CPP4/MRC format..",
49
+ help="Box size of the output",
52
50
  )
53
- parser.add_argument(
54
- "--compress", action="store_true", help="Compress the output file using gzip."
51
+ box_group.add_argument(
52
+ "--sampling_rate",
53
+ dest="sampling_rate",
54
+ type=float,
55
+ required=True,
56
+ help="Sampling rate of the output file.",
55
57
  )
56
58
 
59
+ modulation_group = parser.add_argument_group("Modulation")
60
+ modulation_group.add_argument(
61
+ "--invert_contrast",
62
+ dest="invert_contrast",
63
+ action="store_true",
64
+ required=False,
65
+ help="Inverts the template contrast.",
66
+ )
67
+ modulation_group.add_argument(
68
+ "--lowpass",
69
+ dest="lowpass",
70
+ type=float,
71
+ required=False,
72
+ default=None,
73
+ help="Lowpass filter the template to the given resolution. Nyquist by default. "
74
+ "A value of 0 disables the filter.",
75
+ )
76
+ modulation_group.add_argument(
77
+ "--no_centering",
78
+ dest="no_centering",
79
+ action="store_true",
80
+ help="Assumes the template is already centered and omits centering.",
81
+ )
82
+ modulation_group.add_argument(
83
+ "--backend",
84
+ dest="backend",
85
+ type=str,
86
+ default=None,
87
+ choices=be.available_backends(),
88
+ help="Determines more suitable box size for the given compute backend.",
89
+ )
57
90
  args = parser.parse_args()
58
-
59
91
  return args
60
92
 
61
93
 
62
94
  def main():
63
95
  args = parse_args()
64
- with open(args.yaml_file, "r") as f:
65
- preprocess_settings = yaml.safe_load(f)
66
-
67
- if len(preprocess_settings) > 1:
68
- raise NotImplementedError(
69
- "Multiple preprocessing methods specified. "
70
- "The script currently supports one method at a time."
71
- )
72
-
73
- method_name = list(preprocess_settings.keys())[0]
74
- if not hasattr(Preprocessor, method_name):
75
- raise ValueError(f"Method {method_name} does not exist in Preprocessor.")
76
-
77
- density = Density.from_file(args.input_file)
78
- output = density.empty
79
-
80
- method_params = preprocess_settings[method_name]
81
- preprocessor = Preprocessor()
82
- method = getattr(preprocessor, method_name, None)
83
- if not method:
84
- raise ValueError(
85
- f"{method} does not exist in dge.preprocessor.Preprocessor class."
86
- )
87
-
88
- output.data = method(template=density.data, **method_params)
89
- output.to_file(args.output_file, gzip=args.compress)
96
+
97
+ try:
98
+ data = Structure.from_file(args.data)
99
+ data = Density.from_structure(data, sampling_rate=args.sampling_rate)
100
+ except NotImplementedError:
101
+ data = Density.from_file(args.data)
102
+
103
+ if not args.no_centering:
104
+ data, _ = data.centered(0)
105
+
106
+ for name in be.available_backends():
107
+ be.change_backend(name, device="cpu")
108
+ box = be.compute_convolution_shapes([args.box_size], [1])[1][0]
109
+ if box != args.box_size and args.backend is None:
110
+ print(f"Consider --box_size {box} instead of {args.box_size} for {name}.")
111
+
112
+ if args.backend is not None:
113
+ be.change_backend(name, device="cpu")
114
+ box = be.compute_convolution_shapes([args.box_size], [1])[1][0]
115
+ if box != args.box_size:
116
+ print(f"Changed --box_size from {args.box_size} to {box}.")
117
+ args.box_size = box
118
+
119
+ data.pad(
120
+ np.multiply(args.box_size, np.divide(args.sampling_rate, data.sampling_rate)),
121
+ center=True,
122
+ )
123
+
124
+ bpf_mask = 1
125
+ lowpass = 2 * args.sampling_rate if args.lowpass is None else args.lowpass
126
+ if args.lowpass != 0:
127
+ bpf_mask = BandPassFilter(
128
+ lowpass=lowpass,
129
+ highpass=None,
130
+ use_gaussian=True,
131
+ return_real_fourier=True,
132
+ shape_is_real_fourier=False,
133
+ )(shape=data.shape)["data"]
134
+
135
+ data_ft = np.fft.rfftn(data.data, s=data.shape)
136
+ data_ft = np.multiply(data_ft, bpf_mask, out=data_ft)
137
+ data.data = np.fft.irfftn(data_ft, s=data.shape).real
138
+
139
+ data = data.resample(args.sampling_rate, method="spline", order=3)
140
+
141
+ if args.invert_contrast:
142
+ data.data = data.data * -1
143
+
144
+ data.to_file(args.output)
90
145
 
91
146
 
92
147
  if __name__ == "__main__":
@@ -132,14 +132,6 @@ def local_gaussian_filter(
132
132
  )
133
133
 
134
134
 
135
- def ntree(
136
- template: NDArray,
137
- sigma_range: Tuple[float, float],
138
- **kwargs: dict,
139
- ) -> NDArray:
140
- return preprocessor.ntree_filter(template=template, sigma_range=sigma_range)
141
-
142
-
143
135
  def mean(
144
136
  template: NDArray,
145
137
  width: int,
@@ -155,9 +147,7 @@ def wedge(
155
147
  tilt_step: float = 0,
156
148
  opening_axis: int = 0,
157
149
  tilt_axis: int = 1,
158
- gaussian_sigma: float = 0,
159
150
  omit_negative_frequencies: bool = True,
160
- extrude_plane: bool = True,
161
151
  infinite_plane: bool = True,
162
152
  ) -> NDArray:
163
153
  template_ft = np.fft.rfftn(template)
@@ -169,9 +159,7 @@ def wedge(
169
159
  tilt_axis=tilt_axis,
170
160
  opening_axis=opening_axis,
171
161
  shape=template.shape,
172
- sigma=gaussian_sigma,
173
162
  omit_negative_frequencies=omit_negative_frequencies,
174
- extrude_plane=extrude_plane,
175
163
  infinite_plane=infinite_plane,
176
164
  )
177
165
  np.multiply(template_ft, wedge_mask, out=template_ft)
@@ -185,7 +173,6 @@ def wedge(
185
173
  tilt_step=tilt_step,
186
174
  opening_axis=opening_axis,
187
175
  shape=template.shape,
188
- sigma=gaussian_sigma,
189
176
  omit_negative_frequencies=omit_negative_frequencies,
190
177
  )
191
178
  np.multiply(template_ft, wedge_mask, out=template_ft)
@@ -197,6 +184,10 @@ def compute_power_spectrum(template: NDArray) -> NDArray:
197
184
  return np.fft.fftshift(np.log(np.abs(np.fft.fftn(template))))
198
185
 
199
186
 
187
+ def invert_contrast(template: NDArray) -> NDArray:
188
+ return template * -1
189
+
190
+
200
191
  def widgets_from_function(function: Callable, exclude_params: List = ["self"]):
201
192
  """
202
193
  Creates list of magicui widgets by inspecting function typing ann
@@ -252,13 +243,13 @@ WRAPPED_FUNCTIONS = {
252
243
  "gaussian_filter": gaussian_filter,
253
244
  "bandpass_filter": bandpass_filter,
254
245
  "edge_gaussian_filter": edge_gaussian_filter,
255
- "ntree_filter": ntree,
256
246
  "local_gaussian_filter": local_gaussian_filter,
257
247
  "difference_of_gaussian_filter": difference_of_gaussian_filter,
258
248
  "mean_filter": mean,
259
249
  "wedge_filter": wedge,
260
250
  "power_spectrum": compute_power_spectrum,
261
251
  "ctf": ctf_filter,
252
+ "invert_contrast": invert_contrast,
262
253
  }
263
254
 
264
255
  EXCLUDED_FUNCTIONS = [
@@ -487,10 +478,9 @@ def wedge_mask(
487
478
  tilt_step: float = 0,
488
479
  opening_axis: int = 0,
489
480
  tilt_axis: int = 2,
490
- gaussian_sigma: float = 0,
491
481
  omit_negative_frequencies: bool = False,
492
- extrude_plane: bool = True,
493
- infinite_plane: bool = True,
482
+ infinite_plane: bool = False,
483
+ weight_angle: bool = False,
494
484
  **kwargs,
495
485
  ) -> NDArray:
496
486
  if tilt_step <= 0:
@@ -500,22 +490,23 @@ def wedge_mask(
500
490
  tilt_axis=tilt_axis,
501
491
  opening_axis=opening_axis,
502
492
  shape=template.shape,
503
- sigma=gaussian_sigma,
504
493
  omit_negative_frequencies=omit_negative_frequencies,
505
- extrude_plane=extrude_plane,
506
494
  infinite_plane=infinite_plane,
507
495
  )
508
496
  wedge_mask = np.fft.fftshift(wedge_mask)
509
497
  return wedge_mask
510
498
 
499
+ weights = None
500
+ tilt_angles = np.arange(-tilt_start, tilt_stop + tilt_step, tilt_step)
501
+ if weight_angle:
502
+ weights = np.cos(np.radians(tilt_angles))
503
+
511
504
  wedge_mask = preprocessor.step_wedge_mask(
512
- start_tilt=tilt_start,
513
- stop_tilt=tilt_stop,
505
+ tilt_angles=tilt_angles,
514
506
  tilt_axis=tilt_axis,
515
- tilt_step=tilt_step,
516
507
  opening_axis=opening_axis,
517
508
  shape=template.shape,
518
- sigma=gaussian_sigma,
509
+ weights=weights,
519
510
  omit_negative_frequencies=omit_negative_frequencies,
520
511
  )
521
512
 
@@ -634,6 +625,7 @@ class MaskWidget(widgets.Container):
634
625
 
635
626
  data = active_layer.data.copy()
636
627
  cutoff = np.quantile(data, self.percentile_range_edit.value / 100)
628
+ cutoff = max(cutoff, np.finfo(np.float32).resolution)
637
629
  data[data < cutoff] = 0
638
630
 
639
631
  center_of_mass = Density.center_of_mass(np.abs(data), 0)
tests/__init__.py ADDED
File without changes
tests/data/.DS_Store ADDED
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
tests/data/README.md ADDED
@@ -0,0 +1,2 @@
1
+ Test data was derived from EMD-8249
2
+ https://www.ebi.ac.uk/pdbe/entry/emdb/EMD-8249
Binary file
Binary file
Binary file