pytme 0.2.0__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.0.data → pytme-0.2.1.data}/scripts/match_template.py +183 -69
- {pytme-0.2.0.data → pytme-0.2.1.data}/scripts/postprocess.py +107 -49
- {pytme-0.2.0.data → pytme-0.2.1.data}/scripts/preprocessor_gui.py +4 -1
- {pytme-0.2.0.dist-info → pytme-0.2.1.dist-info}/METADATA +1 -1
- pytme-0.2.1.dist-info/RECORD +73 -0
- scripts/extract_candidates.py +117 -85
- scripts/match_template.py +183 -69
- scripts/match_template_filters.py +193 -71
- 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 +259 -117
- 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 +20 -8
- tme/backends/pytorch_backend.py +20 -9
- tme/density.py +79 -60
- tme/extensions.cpython-311-darwin.so +0 -0
- tme/matching_data.py +85 -61
- tme/matching_exhaustive.py +222 -129
- tme/matching_optimization.py +117 -76
- tme/orientations.py +175 -55
- tme/preprocessing/_utils.py +17 -5
- tme/preprocessing/composable_filter.py +2 -1
- tme/preprocessing/compose.py +1 -2
- tme/preprocessing/frequency_filters.py +97 -41
- tme/preprocessing/tilt_series.py +137 -87
- tme/preprocessor.py +3 -0
- tme/structure.py +4 -1
- pytme-0.2.0.dist-info/RECORD +0 -72
- {pytme-0.2.0.data → pytme-0.2.1.data}/scripts/estimate_ram_usage.py +0 -0
- {pytme-0.2.0.data → pytme-0.2.1.data}/scripts/preprocess.py +0 -0
- {pytme-0.2.0.dist-info → pytme-0.2.1.dist-info}/LICENSE +0 -0
- {pytme-0.2.0.dist-info → pytme-0.2.1.dist-info}/WHEEL +0 -0
- {pytme-0.2.0.dist-info → pytme-0.2.1.dist-info}/entry_points.txt +0 -0
- {pytme-0.2.0.dist-info → pytme-0.2.1.dist-info}/top_level.txt +0 -0
@@ -4,13 +4,15 @@
|
|
4
4
|
|
5
5
|
Author: Valentin Maurer <valentin.maurer@embl-hamburg.de>
|
6
6
|
"""
|
7
|
+
from math import log, sqrt
|
7
8
|
from typing import Tuple, Dict
|
8
9
|
|
9
10
|
import numpy as np
|
10
11
|
from numpy.typing import NDArray
|
11
12
|
from scipy.ndimage import mean as ndimean
|
13
|
+
from scipy.ndimage import map_coordinates
|
12
14
|
|
13
|
-
from ._utils import fftfreqn, crop_real_fourier
|
15
|
+
from ._utils import fftfreqn, crop_real_fourier, shift_fourier
|
14
16
|
from ..backends import backend
|
15
17
|
|
16
18
|
|
@@ -87,6 +89,9 @@ class BandPassFilter:
|
|
87
89
|
NDArray
|
88
90
|
The bandpass filter in Fourier space.
|
89
91
|
"""
|
92
|
+
if shape_is_real_fourier:
|
93
|
+
return_real_fourier = False
|
94
|
+
|
90
95
|
grid = fftfreqn(
|
91
96
|
shape=shape,
|
92
97
|
sampling_rate=0.5,
|
@@ -103,15 +108,9 @@ class BandPassFilter:
|
|
103
108
|
lowcut = np.max(2 * sampling_rate / highpass)
|
104
109
|
|
105
110
|
bandpass_filter = ((grid <= highcut) & (grid >= lowcut)) * 1.0
|
106
|
-
shift = backend.add(
|
107
|
-
backend.astype(backend.divide(bandpass_filter.shape, 2), int),
|
108
|
-
backend.mod(bandpass_filter.shape, 2),
|
109
|
-
)
|
110
|
-
if shape_is_real_fourier:
|
111
|
-
shift[-1] = 0
|
112
111
|
|
113
|
-
bandpass_filter =
|
114
|
-
bandpass_filter,
|
112
|
+
bandpass_filter = shift_fourier(
|
113
|
+
data=bandpass_filter, shape_is_real_fourier=shape_is_real_fourier
|
115
114
|
)
|
116
115
|
|
117
116
|
if return_real_fourier:
|
@@ -166,15 +165,15 @@ class BandPassFilter:
|
|
166
165
|
grid = -backend.square(grid)
|
167
166
|
|
168
167
|
lowpass_filter, highpass_filter = 1, 1
|
169
|
-
norm = float(
|
168
|
+
norm = float(sqrt(2 * log(2)))
|
170
169
|
upper_sampling = float(backend.max(backend.multiply(2, sampling_rate)))
|
171
170
|
|
172
171
|
if lowpass is not None:
|
173
172
|
lowpass = float(lowpass)
|
174
|
-
lowpass = backend.maximum(lowpass, backend.eps(
|
173
|
+
lowpass = backend.maximum(lowpass, backend.eps(backend._float_dtype))
|
175
174
|
if highpass is not None:
|
176
175
|
highpass = float(highpass)
|
177
|
-
highpass = backend.maximum(highpass, backend.eps(
|
176
|
+
highpass = backend.maximum(highpass, backend.eps(backend._float_dtype))
|
178
177
|
|
179
178
|
if lowpass is not None:
|
180
179
|
lowpass = upper_sampling / (lowpass * norm)
|
@@ -185,22 +184,15 @@ class BandPassFilter:
|
|
185
184
|
highpass = backend.multiply(2, backend.square(highpass))
|
186
185
|
highpass_filter = 1 - backend.exp(backend.divide(grid, highpass))
|
187
186
|
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
backend.mod(lowpass_filter.shape, 2),
|
192
|
-
)
|
193
|
-
if shape_is_real_fourier:
|
194
|
-
shift[-1] = 0
|
195
|
-
|
196
|
-
lowpass_filter = backend.roll(
|
197
|
-
lowpass_filter, shift, tuple(i for i in range(len(shift)))
|
187
|
+
bandpass_filter = backend.multiply(lowpass_filter, highpass_filter)
|
188
|
+
bandpass_filter = shift_fourier(
|
189
|
+
data=bandpass_filter, shape_is_real_fourier=shape_is_real_fourier
|
198
190
|
)
|
199
191
|
|
200
192
|
if return_real_fourier:
|
201
|
-
|
193
|
+
bandpass_filter = crop_real_fourier(bandpass_filter)
|
202
194
|
|
203
|
-
return
|
195
|
+
return bandpass_filter
|
204
196
|
|
205
197
|
def __call__(self, **kwargs):
|
206
198
|
func_args = vars(self)
|
@@ -228,6 +220,16 @@ class LinearWhiteningFilter:
|
|
228
220
|
-----------
|
229
221
|
**kwargs : Dict, optional
|
230
222
|
Additional keyword arguments.
|
223
|
+
|
224
|
+
|
225
|
+
References
|
226
|
+
----------
|
227
|
+
.. [1] de Teresa-Trueba, I.; Goetz, S. K.; Mattausch, A.; Stojanovska, F.; Zimmerli, C. E.;
|
228
|
+
Toro-Nahuelpan, M.; Cheng, D. W. C.; Tollervey, F.; Pape, C.; Beck, M.; Diz-Munoz,
|
229
|
+
A.; Kreshuk, A.; Mahamid, J.; Zaugg, J. B. Nat. Methods 2023, 20, 284–294.
|
230
|
+
.. [2] M. L. Chaillet, G. van der Schot, I. Gubins, S. Roet,
|
231
|
+
R. C. Veltkamp, and F. Förster, Int. J. Mol. Sci. 24,
|
232
|
+
13375 (2023)
|
231
233
|
"""
|
232
234
|
|
233
235
|
def __init__(self, **kwargs):
|
@@ -235,7 +237,7 @@ class LinearWhiteningFilter:
|
|
235
237
|
|
236
238
|
@staticmethod
|
237
239
|
def _compute_spectrum(
|
238
|
-
data_rfft: NDArray, n_bins: int = None
|
240
|
+
data_rfft: NDArray, n_bins: int = None, batch_dimension: int = None
|
239
241
|
) -> Tuple[NDArray, NDArray]:
|
240
242
|
"""
|
241
243
|
Compute the spectrum of the input data.
|
@@ -246,6 +248,8 @@ class LinearWhiteningFilter:
|
|
246
248
|
The Fourier transform of the input data.
|
247
249
|
n_bins : int, optional
|
248
250
|
The number of bins for computing the spectrum, defaults to None.
|
251
|
+
batch_dimension : int, optional
|
252
|
+
Batch dimension to average over.
|
249
253
|
|
250
254
|
Returns:
|
251
255
|
--------
|
@@ -254,35 +258,70 @@ class LinearWhiteningFilter:
|
|
254
258
|
radial_averages : NDArray
|
255
259
|
Array containing the radial averages of the spectrum.
|
256
260
|
"""
|
257
|
-
|
261
|
+
shape = tuple(x for i, x in enumerate(data_rfft.shape) if i != batch_dimension)
|
262
|
+
|
263
|
+
max_bins = max(max(shape[:-1]) // 2 + 1, shape[-1])
|
258
264
|
n_bins = max_bins if n_bins is None else n_bins
|
259
265
|
n_bins = int(min(n_bins, max_bins))
|
260
266
|
|
261
|
-
|
262
|
-
shape=
|
263
|
-
sampling_rate=
|
267
|
+
bins = fftfreqn(
|
268
|
+
shape=shape,
|
269
|
+
sampling_rate=0.5,
|
264
270
|
shape_is_real_fourier=True,
|
265
271
|
compute_euclidean_norm=True,
|
266
272
|
)
|
267
|
-
|
268
|
-
bins = np.digitize(grid, bins=bin_edges, right=True)
|
273
|
+
bins = backend.to_numpy_array(bins)
|
269
274
|
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
275
|
+
# Implicit lowpass to nyquist
|
276
|
+
bins = np.floor(bins * (n_bins - 1) + 0.5).astype(int)
|
277
|
+
fft_shift_axes = tuple(
|
278
|
+
i for i in range(data_rfft.ndim - 1) if i != batch_dimension
|
279
|
+
)
|
280
|
+
fourier_spectrum = np.fft.fftshift(data_rfft, axes=fft_shift_axes)
|
281
|
+
fourier_spectrum = np.abs(fourier_spectrum)
|
282
|
+
np.square(fourier_spectrum, out=fourier_spectrum)
|
274
283
|
|
284
|
+
radial_averages = ndimean(
|
285
|
+
fourier_spectrum, labels=bins, index=np.arange(n_bins)
|
286
|
+
)
|
275
287
|
np.sqrt(radial_averages, out=radial_averages)
|
276
288
|
np.reciprocal(radial_averages, out=radial_averages)
|
277
289
|
np.divide(radial_averages, radial_averages.max(), out=radial_averages)
|
278
290
|
|
279
291
|
return bins, radial_averages
|
280
292
|
|
293
|
+
@staticmethod
|
294
|
+
def _interpolate_spectrum(
|
295
|
+
spectrum: NDArray,
|
296
|
+
shape: Tuple[int],
|
297
|
+
shape_is_real_fourier: bool = True,
|
298
|
+
order: int = 1,
|
299
|
+
) -> NDArray:
|
300
|
+
"""
|
301
|
+
References
|
302
|
+
----------
|
303
|
+
.. [1] M. L. Chaillet, G. van der Schot, I. Gubins, S. Roet,
|
304
|
+
R. C. Veltkamp, and F. Förster, Int. J. Mol. Sci. 24,
|
305
|
+
13375 (2023)
|
306
|
+
"""
|
307
|
+
grid = fftfreqn(
|
308
|
+
shape=shape,
|
309
|
+
sampling_rate=.5,
|
310
|
+
shape_is_real_fourier=shape_is_real_fourier,
|
311
|
+
compute_euclidean_norm=True,
|
312
|
+
)
|
313
|
+
grid = backend.to_numpy_array(grid)
|
314
|
+
np.multiply(grid, (spectrum.shape[0] - 1), out = grid) + 0.5
|
315
|
+
spectrum = map_coordinates(spectrum, grid.reshape(1, -1), order=order)
|
316
|
+
return spectrum.reshape(grid.shape)
|
317
|
+
|
281
318
|
def __call__(
|
282
319
|
self,
|
283
320
|
data: NDArray = None,
|
284
321
|
data_rfft: NDArray = None,
|
285
322
|
n_bins: int = None,
|
323
|
+
batch_dimension: int = None,
|
324
|
+
order: int = 1,
|
286
325
|
**kwargs: Dict,
|
287
326
|
) -> Dict:
|
288
327
|
"""
|
@@ -296,27 +335,44 @@ class LinearWhiteningFilter:
|
|
296
335
|
The Fourier transform of the input data, defaults to None.
|
297
336
|
n_bins : int, optional
|
298
337
|
The number of bins for computing the spectrum, defaults to None.
|
338
|
+
batch_dimension : int, optional
|
339
|
+
Batch dimension to average over.
|
340
|
+
order : int, optional
|
341
|
+
Interpolation order to use.
|
299
342
|
**kwargs : Dict
|
300
343
|
Additional keyword arguments.
|
301
344
|
|
302
345
|
Returns:
|
303
346
|
--------
|
304
347
|
Dict
|
305
|
-
|
306
|
-
about the filter being a multiplicative filter.
|
348
|
+
Filter data and associated parameters.
|
307
349
|
"""
|
308
350
|
if data_rfft is None:
|
309
351
|
data_rfft = np.fft.rfftn(backend.to_numpy_array(data))
|
310
352
|
|
311
353
|
data_rfft = backend.to_numpy_array(data_rfft)
|
312
354
|
|
313
|
-
bins, radial_averages = self._compute_spectrum(
|
355
|
+
bins, radial_averages = self._compute_spectrum(
|
356
|
+
data_rfft, n_bins, batch_dimension
|
357
|
+
)
|
314
358
|
|
315
|
-
|
316
|
-
|
359
|
+
if order is None:
|
360
|
+
cutoff = bins < radial_averages.size
|
361
|
+
filter_mask = np.zeros(data_rfft.shape, radial_averages.dtype)
|
362
|
+
filter_mask[cutoff] = radial_averages[bins[cutoff]]
|
363
|
+
else:
|
364
|
+
filter_mask = self._interpolate_spectrum(
|
365
|
+
spectrum=radial_averages,
|
366
|
+
shape=data_rfft.shape,
|
367
|
+
shape_is_real_fourier=True,
|
368
|
+
)
|
369
|
+
|
370
|
+
filter_mask = np.fft.ifftshift(
|
371
|
+
filter_mask,
|
372
|
+
axes=tuple(i for i in range(data_rfft.ndim - 1) if i != batch_dimension)
|
317
373
|
)
|
318
374
|
|
319
375
|
return {
|
320
|
-
"data": backend.to_backend_array(
|
376
|
+
"data": backend.to_backend_array(filter_mask),
|
321
377
|
"is_multiplicative_filter": True,
|
322
378
|
}
|