pytme 0.2.3__cp311-cp311-macosx_14_0_arm64.whl → 0.2.5__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.3.data → pytme-0.2.5.data}/scripts/match_template.py +8 -8
- {pytme-0.2.3.data → pytme-0.2.5.data}/scripts/preprocess.py +22 -6
- {pytme-0.2.3.data → pytme-0.2.5.data}/scripts/preprocessor_gui.py +9 -14
- {pytme-0.2.3.dist-info → pytme-0.2.5.dist-info}/METADATA +1 -1
- pytme-0.2.5.dist-info/RECORD +119 -0
- {pytme-0.2.3.dist-info → pytme-0.2.5.dist-info}/WHEEL +1 -1
- {pytme-0.2.3.dist-info → pytme-0.2.5.dist-info}/top_level.txt +1 -0
- scripts/match_template.py +8 -8
- scripts/preprocess.py +22 -6
- scripts/preprocessor_gui.py +9 -14
- tests/__init__.py +0 -0
- tests/data/.DS_Store +0 -0
- tests/data/Blurring/.DS_Store +0 -0
- tests/data/Blurring/blob_width18.npy +0 -0
- tests/data/Blurring/edgegaussian_sigma3.npy +0 -0
- tests/data/Blurring/gaussian_sigma2.npy +0 -0
- tests/data/Blurring/hamming_width6.npy +0 -0
- tests/data/Blurring/kaiserb_width18.npy +0 -0
- tests/data/Blurring/localgaussian_sigma0510.npy +0 -0
- tests/data/Blurring/mean_size5.npy +0 -0
- tests/data/Blurring/ntree_sigma0510.npy +0 -0
- tests/data/Blurring/rank_rank3.npy +0 -0
- tests/data/Maps/.DS_Store +0 -0
- tests/data/Maps/emd_8621.mrc.gz +0 -0
- tests/data/README.md +2 -0
- tests/data/Raw/.DS_Store +0 -0
- tests/data/Raw/em_map.map +0 -0
- tests/data/Structures/.DS_Store +0 -0
- tests/data/Structures/1pdj.cif +3339 -0
- tests/data/Structures/1pdj.pdb +1429 -0
- tests/data/Structures/5khe.cif +3685 -0
- tests/data/Structures/5khe.ent +2210 -0
- tests/data/Structures/5khe.pdb +2210 -0
- tests/data/Structures/5uz4.cif +70548 -0
- tests/preprocessing/__init__.py +0 -0
- tests/preprocessing/test_compose.py +76 -0
- tests/preprocessing/test_frequency_filters.py +178 -0
- tests/preprocessing/test_preprocessor.py +136 -0
- tests/preprocessing/test_utils.py +79 -0
- tests/test_analyzer.py +310 -0
- tests/test_backends.py +375 -0
- tests/test_density.py +508 -0
- tests/test_extensions.py +130 -0
- tests/test_matching_cli.py +283 -0
- tests/test_matching_data.py +162 -0
- tests/test_matching_exhaustive.py +162 -0
- tests/test_matching_memory.py +30 -0
- tests/test_matching_optimization.py +226 -0
- tests/test_matching_utils.py +326 -0
- tests/test_orientations.py +173 -0
- tests/test_packaging.py +95 -0
- tests/test_parser.py +33 -0
- tests/test_structure.py +243 -0
- tme/__init__.py +0 -1
- tme/__version__.py +1 -1
- tme/backends/jax_backend.py +3 -9
- tme/data/scattering_factors.pickle +0 -0
- tme/density.py +14 -10
- tme/external/bindings.cpp +332 -0
- tme/matching_data.py +14 -12
- tme/matching_exhaustive.py +17 -15
- tme/matching_optimization.py +215 -208
- tme/matching_utils.py +1 -0
- tme/preprocessing/_utils.py +14 -14
- tme/preprocessing/composable_filter.py +0 -2
- tme/preprocessing/compose.py +4 -4
- tme/preprocessing/frequency_filters.py +32 -35
- tme/preprocessing/tilt_series.py +198 -117
- tme/preprocessor.py +24 -246
- tme/structure.py +22 -22
- pytme-0.2.3.dist-info/RECORD +0 -75
- tme/matching_memory.py +0 -383
- {pytme-0.2.3.data → pytme-0.2.5.data}/scripts/estimate_ram_usage.py +0 -0
- {pytme-0.2.3.data → pytme-0.2.5.data}/scripts/postprocess.py +0 -0
- {pytme-0.2.3.dist-info → pytme-0.2.5.dist-info}/LICENSE +0 -0
- {pytme-0.2.3.dist-info → pytme-0.2.5.dist-info}/entry_points.txt +0 -0
tme/preprocessing/tilt_series.py
CHANGED
@@ -10,11 +10,11 @@ from dataclasses import dataclass
|
|
10
10
|
|
11
11
|
import numpy as np
|
12
12
|
|
13
|
-
from .. import Preprocessor
|
14
13
|
from ..types import NDArray
|
15
14
|
from ..backends import backend as be
|
16
|
-
from ..matching_utils import euler_to_rotationmatrix
|
15
|
+
from ..matching_utils import euler_to_rotationmatrix, centered
|
17
16
|
from ._utils import (
|
17
|
+
centered_grid,
|
18
18
|
frequency_grid_at_angle,
|
19
19
|
compute_tilt_shape,
|
20
20
|
crop_real_fourier,
|
@@ -90,12 +90,8 @@ def create_reconstruction_filter(
|
|
90
90
|
tilt_angles = kwargs.get("tilt_angles", False)
|
91
91
|
if tilt_angles is False:
|
92
92
|
raise ValueError("'ramp' filter requires specifying tilt angles.")
|
93
|
-
size
|
94
|
-
ret =
|
95
|
-
ret /= size // 2
|
96
|
-
ret *= 0.5
|
97
|
-
np.abs(ret, out=ret)
|
98
|
-
|
93
|
+
size = filter_shape[0]
|
94
|
+
ret = fftfreqn((size,), sampling_rate=1, compute_euclidean_norm=True)
|
99
95
|
min_increment = np.radians(np.min(np.abs(np.diff(np.sort(tilt_angles)))))
|
100
96
|
ret *= min_increment * size
|
101
97
|
np.fmin(ret, 1, out=ret)
|
@@ -164,8 +160,8 @@ class ReconstructFromTilt:
|
|
164
160
|
"""
|
165
161
|
Reconstruct a volume from a tilt series.
|
166
162
|
|
167
|
-
Parameters
|
168
|
-
|
163
|
+
Parameters
|
164
|
+
----------
|
169
165
|
data : NDArray
|
170
166
|
The tilt series data.
|
171
167
|
shape : tuple of int
|
@@ -177,15 +173,15 @@ class ReconstructFromTilt:
|
|
177
173
|
tilt_axis : int
|
178
174
|
Axis the plane is tilted over.
|
179
175
|
interpolation_order : int, optional
|
180
|
-
Interpolation order used for rotation,
|
176
|
+
Interpolation order used for rotation, defaults to 1.
|
181
177
|
return_real_fourier : bool, optional
|
182
178
|
Whether to return a shape compliant with rfftn, defaults to True.
|
183
179
|
reconstruction_filter : bool, optional
|
184
180
|
Filter window applied during reconstruction.
|
185
181
|
See :py:meth:`create_reconstruction_filter` for available options.
|
186
182
|
|
187
|
-
Returns
|
188
|
-
|
183
|
+
Returns
|
184
|
+
-------
|
189
185
|
NDArray
|
190
186
|
The reconstructed volume.
|
191
187
|
"""
|
@@ -197,7 +193,7 @@ class ReconstructFromTilt:
|
|
197
193
|
volume_temp_rotated = be.zeros(shape, dtype=be._float_dtype)
|
198
194
|
volume = be.zeros(shape, dtype=be._float_dtype)
|
199
195
|
|
200
|
-
slices = tuple(slice(a, a + 1) for a in
|
196
|
+
slices = tuple(slice(a // 2, (a // 2) + 1) for a in shape)
|
201
197
|
subset = tuple(
|
202
198
|
slice(None) if i != opening_axis else slices[opening_axis]
|
203
199
|
for i in range(len(shape))
|
@@ -224,6 +220,7 @@ class ReconstructFromTilt:
|
|
224
220
|
rec_filter = be.to_backend_array(rec_filter)
|
225
221
|
rec_filter = be.reshape(rec_filter, wedges[0].shape)
|
226
222
|
|
223
|
+
angles = be.to_backend_array(angles)
|
227
224
|
for index in range(len(angles)):
|
228
225
|
be.fill(angles_loop, 0)
|
229
226
|
be.fill(volume_temp, 0)
|
@@ -257,8 +254,8 @@ class Wedge:
|
|
257
254
|
"""
|
258
255
|
Generate wedge mask for tomographic data.
|
259
256
|
|
260
|
-
Parameters
|
261
|
-
|
257
|
+
Parameters
|
258
|
+
----------
|
262
259
|
shape : tuple of int
|
263
260
|
The shape of the reconstruction volume.
|
264
261
|
tilt_axis : int
|
@@ -272,10 +269,10 @@ class Wedge:
|
|
272
269
|
weight_type : str, optional
|
273
270
|
The type of weighting to apply, defaults to None.
|
274
271
|
frequency_cutoff : float, optional
|
275
|
-
|
272
|
+
Frequency cutoff for created mask. Nyquist 0.5 by default.
|
276
273
|
|
277
|
-
Returns
|
278
|
-
|
274
|
+
Returns
|
275
|
+
-------
|
279
276
|
Dict
|
280
277
|
A dictionary containing weighted wedges and related information.
|
281
278
|
"""
|
@@ -303,13 +300,13 @@ class Wedge:
|
|
303
300
|
Generate a :py:class:`Wedge` instance by reading tilt angles and weights
|
304
301
|
from a tab-separated text file.
|
305
302
|
|
306
|
-
Parameters
|
307
|
-
|
303
|
+
Parameters
|
304
|
+
----------
|
308
305
|
filename : str
|
309
306
|
The path to the file containing tilt angles and weights.
|
310
307
|
|
311
|
-
Returns
|
312
|
-
|
308
|
+
Returns
|
309
|
+
-------
|
313
310
|
:py:class:`Wedge`
|
314
311
|
Class instance instance initialized with angles and weights from the file.
|
315
312
|
"""
|
@@ -338,15 +335,15 @@ class Wedge:
|
|
338
335
|
"""
|
339
336
|
Read column data from a text file.
|
340
337
|
|
341
|
-
Parameters
|
342
|
-
|
338
|
+
Parameters
|
339
|
+
----------
|
343
340
|
filename : str
|
344
341
|
The path to the text file.
|
345
342
|
delimiter : str, optional
|
346
343
|
The delimiter used in the file, defaults to '\t'.
|
347
344
|
|
348
|
-
Returns
|
349
|
-
|
345
|
+
Returns
|
346
|
+
-------
|
350
347
|
Dict
|
351
348
|
A dictionary with one key for each column.
|
352
349
|
"""
|
@@ -380,6 +377,19 @@ class Wedge:
|
|
380
377
|
func_args["weights"] = np.cos(np.radians(self.angles))
|
381
378
|
|
382
379
|
ret = weight_types[weight_type](**func_args)
|
380
|
+
|
381
|
+
frequency_cutoff = func_args.get("frequency_cutoff", None)
|
382
|
+
if frequency_cutoff is not None:
|
383
|
+
for index, angle in enumerate(self.angles):
|
384
|
+
frequency_grid = frequency_grid_at_angle(
|
385
|
+
shape=func_args["shape"],
|
386
|
+
opening_axis=self.opening_axis,
|
387
|
+
tilt_axis=self.tilt_axis,
|
388
|
+
angle=angle,
|
389
|
+
sampling_rate=1,
|
390
|
+
)
|
391
|
+
ret[index] = np.multiply(ret[index], frequency_grid <= frequency_cutoff)
|
392
|
+
|
383
393
|
ret = be.astype(be.to_backend_array(ret), be._float_dtype)
|
384
394
|
|
385
395
|
return {
|
@@ -413,46 +423,47 @@ class Wedge:
|
|
413
423
|
|
414
424
|
return wedges
|
415
425
|
|
416
|
-
def weight_relion(
|
426
|
+
def weight_relion(
|
427
|
+
self, shape: Tuple[int], opening_axis: int, tilt_axis: int, **kwargs
|
428
|
+
) -> NDArray:
|
417
429
|
"""
|
418
430
|
Generate weighted wedges based on the RELION 1.4 formalism, weighting each
|
419
431
|
angle using the cosine of the angle and a Gaussian lowpass filter computed
|
420
432
|
with respect to the exposure per angstrom.
|
421
433
|
|
422
|
-
Returns
|
423
|
-
|
434
|
+
Returns
|
435
|
+
-------
|
424
436
|
NDArray
|
425
437
|
Weighted wedges.
|
426
438
|
"""
|
427
439
|
tilt_shape = compute_tilt_shape(
|
428
|
-
shape=
|
440
|
+
shape=shape, opening_axis=opening_axis, reduce_dim=True
|
429
441
|
)
|
430
442
|
|
431
443
|
wedges = np.zeros((len(self.angles), *tilt_shape))
|
432
444
|
for index, angle in enumerate(self.angles):
|
433
445
|
frequency_grid = frequency_grid_at_angle(
|
434
|
-
shape=
|
435
|
-
opening_axis=
|
436
|
-
tilt_axis=
|
446
|
+
shape=shape,
|
447
|
+
opening_axis=opening_axis,
|
448
|
+
tilt_axis=tilt_axis,
|
437
449
|
angle=angle,
|
438
450
|
sampling_rate=1,
|
439
451
|
)
|
440
|
-
# frequency_mask = frequency_grid <= self.frequency_cutoff
|
441
|
-
|
442
452
|
sigma = np.sqrt(self.weights[index] * 4 / (8 * np.pi**2))
|
443
453
|
sigma = -2 * np.pi**2 * sigma**2
|
444
454
|
np.square(frequency_grid, out=frequency_grid)
|
445
455
|
np.multiply(sigma, frequency_grid, out=frequency_grid)
|
446
456
|
np.exp(frequency_grid, out=frequency_grid)
|
447
457
|
np.multiply(frequency_grid, np.cos(np.radians(angle)), out=frequency_grid)
|
448
|
-
# np.multiply(frequency_grid, frequency_mask, out=frequency_grid)
|
449
|
-
|
450
458
|
wedges[index] = frequency_grid
|
451
459
|
|
452
460
|
return wedges
|
453
461
|
|
454
462
|
def weight_grigorieff(
|
455
463
|
self,
|
464
|
+
shape: Tuple[int],
|
465
|
+
opening_axis: int,
|
466
|
+
tilt_axis: int,
|
456
467
|
amplitude: float = 0.245,
|
457
468
|
power: float = -1.665,
|
458
469
|
offset: float = 2.81,
|
@@ -461,31 +472,28 @@ class Wedge:
|
|
461
472
|
"""
|
462
473
|
Generate weighted wedges based on the formalism introduced in [1]_.
|
463
474
|
|
464
|
-
Returns
|
465
|
-
|
475
|
+
Returns
|
476
|
+
-------
|
466
477
|
NDArray
|
467
478
|
Weighted wedges.
|
468
479
|
|
469
480
|
References
|
470
481
|
----------
|
471
|
-
.. [1] Timothy
|
482
|
+
.. [1] Timothy Grant, Nikolaus Grigorieff (2015), eLife 4:e06980.
|
472
483
|
"""
|
473
484
|
tilt_shape = compute_tilt_shape(
|
474
|
-
shape=
|
475
|
-
opening_axis=self.opening_axis,
|
476
|
-
reduce_dim=True,
|
485
|
+
shape=shape, opening_axis=opening_axis, reduce_dim=True
|
477
486
|
)
|
478
487
|
|
479
488
|
wedges = np.zeros((len(self.angles), *tilt_shape), dtype=be._float_dtype)
|
480
489
|
for index, angle in enumerate(self.angles):
|
481
490
|
frequency_grid = frequency_grid_at_angle(
|
482
|
-
shape=
|
483
|
-
opening_axis=
|
484
|
-
tilt_axis=
|
491
|
+
shape=shape,
|
492
|
+
opening_axis=opening_axis,
|
493
|
+
tilt_axis=tilt_axis,
|
485
494
|
angle=angle,
|
486
495
|
sampling_rate=1,
|
487
496
|
)
|
488
|
-
# frequency_mask = frequency_grid <= self.frequency_cutoff
|
489
497
|
|
490
498
|
with np.errstate(divide="ignore"):
|
491
499
|
np.power(frequency_grid, power, out=frequency_grid)
|
@@ -498,10 +506,7 @@ class Wedge:
|
|
498
506
|
out=frequency_grid,
|
499
507
|
)
|
500
508
|
|
501
|
-
np.exp(frequency_grid
|
502
|
-
# np.multiply(frequency_grid, frequency_mask, out=frequency_grid)
|
503
|
-
|
504
|
-
wedges[index] = frequency_grid
|
509
|
+
wedges[index] = np.exp(frequency_grid)
|
505
510
|
|
506
511
|
return wedges
|
507
512
|
|
@@ -510,14 +515,24 @@ class WedgeReconstructed:
|
|
510
515
|
"""
|
511
516
|
Initialize :py:class:`WedgeReconstructed`.
|
512
517
|
|
513
|
-
Parameters
|
514
|
-
|
515
|
-
angles :
|
518
|
+
Parameters
|
519
|
+
----------
|
520
|
+
angles :tuple of float, optional
|
516
521
|
The tilt angles, defaults to None.
|
517
522
|
opening_axis : int, optional
|
518
523
|
The axis around which the wedge is opened, defaults to 0.
|
519
524
|
tilt_axis : int, optional
|
520
525
|
The axis along which the tilt is applied, defaults to 2.
|
526
|
+
weights : tuple of float, optional
|
527
|
+
Weights to assign to individual wedge components.
|
528
|
+
weight_wedge : bool, optional
|
529
|
+
Whether individual wedge components should be weighted. If True and weights
|
530
|
+
is None, uses the cosine of the angle otherwise weights.
|
531
|
+
create_continuous_wedge: bool, optional
|
532
|
+
Whether to create a continous wedge or a per-component wedge. Weights are only
|
533
|
+
considered for non-continuous wedges.
|
534
|
+
frequency_cutoff : float, optional
|
535
|
+
Filter window applied during reconstruction.
|
521
536
|
**kwargs : Dict
|
522
537
|
Additional keyword arguments.
|
523
538
|
"""
|
@@ -525,33 +540,37 @@ class WedgeReconstructed:
|
|
525
540
|
def __init__(
|
526
541
|
self,
|
527
542
|
angles: Tuple[float] = None,
|
528
|
-
start_tilt: float = None,
|
529
|
-
stop_tilt: float = None,
|
530
543
|
opening_axis: int = 0,
|
531
544
|
tilt_axis: int = 2,
|
545
|
+
weights: Tuple[float] = None,
|
532
546
|
weight_wedge: bool = False,
|
533
547
|
create_continuous_wedge: bool = False,
|
548
|
+
frequency_cutoff: float = 0.5,
|
549
|
+
reconstruction_filter: str = None,
|
534
550
|
**kwargs: Dict,
|
535
551
|
):
|
536
552
|
self.angles = angles
|
537
553
|
self.opening_axis = opening_axis
|
538
554
|
self.tilt_axis = tilt_axis
|
555
|
+
self.weights = weights
|
539
556
|
self.weight_wedge = weight_wedge
|
557
|
+
self.reconstruction_filter = reconstruction_filter
|
540
558
|
self.create_continuous_wedge = create_continuous_wedge
|
559
|
+
self.frequency_cutoff = frequency_cutoff
|
541
560
|
|
542
561
|
def __call__(self, shape: Tuple[int], **kwargs: Dict) -> Dict:
|
543
562
|
"""
|
544
563
|
Generate the reconstructed wedge.
|
545
564
|
|
546
|
-
Parameters
|
547
|
-
|
565
|
+
Parameters
|
566
|
+
----------
|
548
567
|
shape : tuple of int
|
549
568
|
The shape of the reconstruction volume.
|
550
569
|
**kwargs : Dict
|
551
570
|
Additional keyword arguments.
|
552
571
|
|
553
|
-
Returns
|
554
|
-
|
572
|
+
Returns
|
573
|
+
-------
|
555
574
|
Dict
|
556
575
|
A dictionary containing the reconstructed wedge and related information.
|
557
576
|
"""
|
@@ -559,15 +578,39 @@ class WedgeReconstructed:
|
|
559
578
|
func_args.update(kwargs)
|
560
579
|
|
561
580
|
if kwargs.get("is_fourier_shape", False):
|
562
|
-
print("Cannot create continuous wedge mask
|
581
|
+
print("Cannot create continuous wedge mask based on real fourier shape.")
|
563
582
|
|
564
583
|
func = self.step_wedge
|
565
584
|
if func_args.get("create_continuous_wedge", False):
|
566
585
|
func = self.continuous_wedge
|
567
586
|
|
587
|
+
weight_wedge = func_args.get("weight_wedge", False)
|
588
|
+
if func_args.get("wedge_weights") is None and weight_wedge:
|
589
|
+
func_args["weights"] = np.cos(
|
590
|
+
np.radians(be.to_numpy_array(func_args.get("angles", (0,))))
|
591
|
+
)
|
592
|
+
|
568
593
|
ret = func(shape=shape, **func_args)
|
594
|
+
|
595
|
+
frequency_cutoff = func_args.get("frequency_cutoff", None)
|
596
|
+
if frequency_cutoff is not None:
|
597
|
+
frequency_mask = fftfreqn(
|
598
|
+
shape=shape,
|
599
|
+
sampling_rate=1,
|
600
|
+
compute_euclidean_norm=True,
|
601
|
+
shape_is_real_fourier=False,
|
602
|
+
)
|
603
|
+
ret = np.multiply(ret, frequency_mask <= frequency_cutoff, out=ret)
|
604
|
+
|
605
|
+
if not weight_wedge:
|
606
|
+
ret = (ret > 0) * 1.0
|
607
|
+
|
569
608
|
ret = be.astype(be.to_backend_array(ret), be._float_dtype)
|
570
609
|
|
610
|
+
ret = shift_fourier(data=ret, shape_is_real_fourier=False)
|
611
|
+
if func_args.get("return_real_fourier", False):
|
612
|
+
ret = crop_real_fourier(ret)
|
613
|
+
|
571
614
|
return {
|
572
615
|
"data": ret,
|
573
616
|
"shape_is_real_fourier": func_args["return_real_fourier"],
|
@@ -584,14 +627,13 @@ class WedgeReconstructed:
|
|
584
627
|
angles: Tuple[float],
|
585
628
|
opening_axis: int,
|
586
629
|
tilt_axis: int,
|
587
|
-
return_real_fourier: bool,
|
588
630
|
**kwargs: Dict,
|
589
631
|
) -> NDArray:
|
590
632
|
"""
|
591
|
-
Generate a
|
633
|
+
Generate a continous wedge mask with DC component at the center.
|
592
634
|
|
593
|
-
Parameters
|
594
|
-
|
635
|
+
Parameters
|
636
|
+
----------
|
595
637
|
shape : tuple of int
|
596
638
|
The shape of the reconstruction volume.
|
597
639
|
angles : tuple of float
|
@@ -600,27 +642,28 @@ class WedgeReconstructed:
|
|
600
642
|
The axis around which the wedge is opened.
|
601
643
|
tilt_axis : int
|
602
644
|
The axis along which the tilt is applied.
|
603
|
-
return_real_fourier : bool
|
604
|
-
Whether to return the real part of the Fourier transform.
|
605
645
|
|
606
|
-
Returns
|
607
|
-
|
646
|
+
Returns
|
647
|
+
-------
|
608
648
|
NDArray
|
609
|
-
|
649
|
+
Wedge mask.
|
610
650
|
"""
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
651
|
+
start_radians = np.tan(np.radians(90 - angles[0]))
|
652
|
+
stop_radians = np.tan(np.radians(-1 * (90 - angles[1])))
|
653
|
+
|
654
|
+
grid = centered_grid(shape)
|
655
|
+
with np.errstate(divide="ignore", invalid="ignore"):
|
656
|
+
ratios = np.where(
|
657
|
+
grid[opening_axis] == 0,
|
658
|
+
np.tan(np.radians(90)) + 1,
|
659
|
+
grid[tilt_axis] / grid[opening_axis],
|
660
|
+
)
|
661
|
+
|
662
|
+
wedge = np.logical_or(start_radians <= ratios, stop_radians >= ratios).astype(
|
663
|
+
np.float32
|
621
664
|
)
|
622
665
|
|
623
|
-
return
|
666
|
+
return wedge
|
624
667
|
|
625
668
|
@staticmethod
|
626
669
|
def step_wedge(
|
@@ -628,15 +671,15 @@ class WedgeReconstructed:
|
|
628
671
|
angles: Tuple[float],
|
629
672
|
opening_axis: int,
|
630
673
|
tilt_axis: int,
|
631
|
-
|
632
|
-
|
674
|
+
weights: Tuple[float] = None,
|
675
|
+
reconstruction_filter: str = None,
|
633
676
|
**kwargs: Dict,
|
634
677
|
) -> NDArray:
|
635
678
|
"""
|
636
|
-
Generate a
|
679
|
+
Generate a per-angle wedge shape with DC component at the center.
|
637
680
|
|
638
|
-
Parameters
|
639
|
-
|
681
|
+
Parameters
|
682
|
+
----------
|
640
683
|
shape : tuple of int
|
641
684
|
The shape of the reconstruction volume.
|
642
685
|
angles : tuple of float
|
@@ -645,38 +688,76 @@ class WedgeReconstructed:
|
|
645
688
|
The axis around which the wedge is opened.
|
646
689
|
tilt_axis : int
|
647
690
|
The axis along which the tilt is applied.
|
648
|
-
|
649
|
-
|
650
|
-
|
651
|
-
|
691
|
+
reconstruction_filter : str
|
692
|
+
Filter used during reconstruction.
|
693
|
+
weights : tuple of float, optional
|
694
|
+
Weights to assign to individual tilts. Defaults to 1.
|
652
695
|
|
653
|
-
Returns
|
654
|
-
|
696
|
+
Returns
|
697
|
+
-------
|
655
698
|
NDArray
|
656
|
-
|
699
|
+
Wege mask.
|
657
700
|
"""
|
658
|
-
|
701
|
+
from ..backends import NumpyFFTWBackend
|
659
702
|
|
660
703
|
angles = np.asarray(be.to_numpy_array(angles))
|
661
|
-
|
662
|
-
if
|
663
|
-
weights = np.
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
opening_axis
|
672
|
-
|
673
|
-
omit_negative_frequencies=return_real_fourier,
|
704
|
+
|
705
|
+
if weights is None:
|
706
|
+
weights = np.ones(angles.size)
|
707
|
+
weights = np.asarray(weights)
|
708
|
+
|
709
|
+
shape = tuple(int(x) for x in shape)
|
710
|
+
opening_axis, tilt_axis = int(opening_axis), int(tilt_axis)
|
711
|
+
|
712
|
+
weights = np.repeat(weights, angles.size // weights.size)
|
713
|
+
plane = np.zeros(
|
714
|
+
(shape[opening_axis], shape[tilt_axis] + (1 - shape[tilt_axis] % 2)),
|
715
|
+
dtype=np.float32,
|
674
716
|
)
|
675
717
|
|
676
|
-
|
677
|
-
ret = (ret > 0) * 1.0
|
718
|
+
# plane = np.zeros((shape[opening_axis], int(2 * np.max(shape)) + 1), dtype=np.float32)
|
678
719
|
|
679
|
-
|
720
|
+
rec_filter = 1
|
721
|
+
if reconstruction_filter is not None:
|
722
|
+
rec_filter = create_reconstruction_filter(
|
723
|
+
plane.shape[::-1], filter_type=reconstruction_filter, tilt_angles=angles
|
724
|
+
).T
|
725
|
+
|
726
|
+
subset = tuple(
|
727
|
+
slice(None) if i != 0 else slice(x // 2, x // 2 + 1)
|
728
|
+
for i, x in enumerate(plane.shape)
|
729
|
+
)
|
730
|
+
plane_rotated, wedge_volume = np.zeros_like(plane), np.zeros_like(plane)
|
731
|
+
for index in range(angles.shape[0]):
|
732
|
+
plane_rotated.fill(0)
|
733
|
+
plane[subset] = 1
|
734
|
+
rotation_matrix = euler_to_rotationmatrix((angles[index], 0))
|
735
|
+
rotation_matrix = rotation_matrix[np.ix_((0, 1), (0, 1))]
|
736
|
+
|
737
|
+
NumpyFFTWBackend().rigid_transform(
|
738
|
+
arr=plane * rec_filter,
|
739
|
+
rotation_matrix=rotation_matrix,
|
740
|
+
out=plane_rotated,
|
741
|
+
use_geometric_center=True,
|
742
|
+
order=1,
|
743
|
+
)
|
744
|
+
wedge_volume += plane_rotated * weights[index]
|
745
|
+
|
746
|
+
wedge_volume = centered(wedge_volume, (shape[opening_axis], shape[tilt_axis]))
|
747
|
+
np.fmin(wedge_volume, np.max(weights), wedge_volume)
|
748
|
+
|
749
|
+
if opening_axis > tilt_axis:
|
750
|
+
wedge_volume = np.moveaxis(wedge_volume, 1, 0)
|
751
|
+
|
752
|
+
reshape_dimensions = tuple(
|
753
|
+
x if i in (opening_axis, tilt_axis) else 1 for i, x in enumerate(shape)
|
754
|
+
)
|
755
|
+
|
756
|
+
wedge_volume = wedge_volume.reshape(reshape_dimensions)
|
757
|
+
tile_dimensions = np.divide(shape, reshape_dimensions).astype(int)
|
758
|
+
wedge_volume = np.tile(wedge_volume, tile_dimensions)
|
759
|
+
|
760
|
+
return wedge_volume
|
680
761
|
|
681
762
|
|
682
763
|
@dataclass
|
@@ -726,8 +807,8 @@ class CTF:
|
|
726
807
|
"""
|
727
808
|
Initialize :py:class:`CTF` from file.
|
728
809
|
|
729
|
-
Parameters
|
730
|
-
|
810
|
+
Parameters
|
811
|
+
----------
|
731
812
|
filename : str
|
732
813
|
The path to a file with ctf parameters. Supports the following formats:
|
733
814
|
- CTFFIND4
|
@@ -857,8 +938,8 @@ class CTF:
|
|
857
938
|
"""
|
858
939
|
Compute the CTF weight tilt stack.
|
859
940
|
|
860
|
-
Parameters
|
861
|
-
|
941
|
+
Parameters
|
942
|
+
----------
|
862
943
|
shape : tuple of int
|
863
944
|
The shape of the CTF.
|
864
945
|
defocus_x : tuple of float
|
@@ -890,8 +971,8 @@ class CTF:
|
|
890
971
|
**kwargs : Dict
|
891
972
|
Additional keyword arguments.
|
892
973
|
|
893
|
-
Returns
|
894
|
-
|
974
|
+
Returns
|
975
|
+
-------
|
895
976
|
NDArray
|
896
977
|
A stack containing the CTF weight.
|
897
978
|
"""
|