Source code for ewoksfluo.tests.test_regrid

import numpy
import pytest

from ..math.regular_grid import ScatterDataInterpolator


[docs] @pytest.mark.parametrize( "ndim, ndatadim, units, unit_conv, degenerate_dim", [ pytest.param( 2, 0, ["um", "um"], [1.0, 1.0], None, id="2D_homogeneous_0Ddata", ), pytest.param( 2, 1, ["um", "um"], [1.0, 1.0], None, id="2D_homogeneous_1Ddata", ), pytest.param( 2, 2, ["um", "um"], [1.0, 1.0], None, id="2D_homogeneous_2Ddata", ), pytest.param( 2, 1, ["um", "um"], [1.0, 1.0], None, id="2D_homogeneous_3Ddata", ), pytest.param( 3, 0, ["um", "um", "um"], [1.0, 1.0, 1.0], None, id="3D_homogeneous_0Ddata", ), pytest.param( 2, 0, ["um", "mm"], [1.0, 1e3], None, id="2D_heterogeneous_0Ddata", ), pytest.param( 3, 0, ["um", "um", "mm"], [1.0, 1.0, 1e3], None, id="3D_heterogeneous_0Ddata", ), pytest.param( 3, 1, ["um", "um", "mm"], [1.0, 1.0, 1e3], None, id="3D_heterogeneous_1Ddata", ), pytest.param( 4, 0, ["um", "mm", "deg", "rad"], [1.0, 1e3, 1.0, 180 / numpy.pi], None, id="4D_mixed_0Ddata", ), pytest.param( 2, 0, ["um", "um"], [1.0, 1.0], 1, id="2D_degenerate_axis_0Ddata", ), pytest.param( 3, 1, ["um", "um", "mm"], [1.0, 1.0, 1e3], 2, id="3D_degenerate_axis_1Ddata", ), pytest.param( 4, 0, ["um", "mm", "deg", "rad"], [1.0, 1e3, 1.0, 180 / numpy.pi], 3, id="4D_degenerate_axis_mixed_units", ), ], ) def test_regular_regridding_mixed_scaled( ndim, ndatadim, units, unit_conv, degenerate_dim ): # Generate raw scatter coordinates state = numpy.random.RandomState(42) N_points = 100 scatter_coords = [state.uniform(-10, 10, N_points) for _ in units] # Collapse one axis to a constant value if degenerate_dim is not None: scatter_coords[degenerate_dim] = numpy.full( N_points, 3.141592653589793, ) # Arbitrary linear relationship between values and coordinates coeffs = [i + 1 for i in range(ndim)] offset = 5 values = ( sum(c * x * uc for c, x, uc in zip(coeffs, scatter_coords, unit_conv)) + offset ) # Add extra data dimensions for each scatter point data_shape = tuple(range(10, 10 + ndatadim)) values = _add_data_dimensions(values, data_shape) # Create interpolator with raw coordinates names = [f"dim{i}" for i in range(ndim)] interpolator = ScatterDataInterpolator( scatter_coords, names, units, method="linear", reference_units="first", scale_method="range", ) interpolated = interpolator.regrid(values) # Interpolated values as expected from the # - linear relationship between values and coordinates # - and linear interpolation in scaled space. grid_coords = interpolator.expanded_grid_coordinates.T expected = sum(c * x for c, x in zip(coeffs, grid_coords)) + offset expected = _add_data_dimensions(expected, data_shape) expected = expected.reshape(interpolated.shape) # Validate interpolation assert numpy.nanmax(numpy.abs(interpolated - expected)) < 1e-9 # Validate degenerate axis behavior if degenerate_dim is not None: axis = interpolator.grid_axes[degenerate_dim] # Degenerate axis should collapse to a single value assert numpy.allclose(axis, axis[0]) # Should contain either one or repeated identical points assert len(numpy.unique(axis)) == 1
def _add_data_dimensions(array: numpy.ndarray, data_shape: tuple) -> numpy.ndarray: """ Expand a 1D array to include additional detector/data dimensions. :param array: Input 1D array of shape (N,). :param data_shape: Tuple representing the shape of additional data dimensions to add. :returns: Array of shape (N, *data_shape), where the original array is broadcasted along the new dimensions. """ reshaped_array = array[(...,) + (numpy.newaxis,) * len(data_shape)] return numpy.tile(reshaped_array, data_shape)