Source code for tme.filters.curve

"""
Curve maps a precomputed 1D radial profile onto an Fourier grid.

Copyright (c) 2024 European Molecular Biology Laboratory

Author: Valentin Maurer <valentin.maurer@embl-hamburg.de>
"""

from typing import Tuple, Dict
from dataclasses import dataclass

import numpy as np

from ._utils import fftfreqn
from ..types import BackendArray
from ..backends import backend as be
from .compose import ComposableFilter

__all__ = ["Curve"]


[docs] @dataclass class Curve(ComposableFilter): """Interpolate a 1D radial profile onto an nD Fourier grid.""" #: 1D radial profile from DC to Nyquist. spectrum: BackendArray = None def _evaluate(self, shape: Tuple[int, ...], **kwargs: Dict) -> Dict: spectrum = be.to_numpy_array(self.spectrum) bin_centers = fftfreqn( shape=(spectrum.shape[0],), sampling_rate=0.5, compute_euclidean_norm=True, shape_is_real_fourier=True, fftshift=False, ) ret = _interpolate_spectrum( bin_centers=bin_centers, spectrum=spectrum, shape=shape, shape_is_real_fourier=False, ) return {"data": be.to_backend_array(ret), "shape": shape}
def _interpolate_spectrum( bin_centers: BackendArray, spectrum: BackendArray, shape: Tuple[int], shape_is_real_fourier: bool = True, ) -> BackendArray: """ Interpolate a 1D radial spectrum onto an nD frequency grid. Parameters ---------- bin_centers : BackendArray Frequency values corresponding to each spectrum entry. spectrum : BackendArray 1D radial spectrum values. shape : Tuple[int] Shape of the output grid. shape_is_real_fourier : bool, optional Whether shape corresponds to a real Fourier transform. Returns ------- BackendArray The spectrum mapped onto the nD frequency grid. """ from scipy.interpolate import PchipInterpolator grid = fftfreqn( shape=shape, sampling_rate=0.5, compute_euclidean_norm=True, shape_is_real_fourier=shape_is_real_fourier, fftshift=False, ) # Shape-preserving interpolation with hard Nyquist cutoff interpolator = PchipInterpolator(bin_centers, spectrum, extrapolate=False) ret = interpolator(grid.ravel()).reshape(grid.shape) ret[np.isnan(ret)] = 0 return np.fmax(ret, 0, out=ret)