Source code for ess.imaging.tools.resolution

import scipp as sc


[docs] def maximum_resolution_achievable( events: sc.DataArray, coarse_x_bin_edges: sc.Variable, coarse_y_bin_edges: sc.Variable, time_bin_edges: sc.Variable, max_tries: int = 10, max_pixels_x: int = 2048, max_pixels_y: int = 2048, raise_if_not_maximum: bool = False, ): """ Estimates the maximum resolution achievable given a desired binning in time. The maximum achievable resolution is defined as the resolution in ``xy`` such that there is at least one event in every ``xyt`` pixel. Parameters ------------- events: 1D DataArray containing events with associated x, y, and t coordinates. The names of the coordinates must not be `x`, `y` and `t`, the names of the coordinates are taken from the provided ``bin_edges`` for each respective dimension. coarse_x_bin_edges: Minimum acceptable resolution in ``x``. coarse_y_bin_edges: Minimum acceptable resolution in ``y``. time_bin_edges: Desired resolution in ``t``. max_tries: The maximum number of iterations before giving up. max_pixels_x: The maximum number of pixels in ``x``. max_pixels_y: The maximum number of pixels in ``y``. raise_if_not_maximum: Often it is not important to find the exact maximum resolution. Therefore this parameter is ``False`` by default, and the function returns an estimate of the maximum resolution. If you want the returned resolution to be exactly the maximum resolution, set the value of this parameter to ``True``. Returns ------------- The bin edges in x respectively y that define the maximum achievable resolution. """ lower_nx = coarse_x_bin_edges.size lower_ny = coarse_y_bin_edges.size upper_nx = max_pixels_x upper_ny = max_pixels_y nx = int(2**0.5 * lower_nx) + 1 ny = int(2**0.5 * lower_ny) + 1 events = events.bin({time_bin_edges.dim: time_bin_edges}) for _ in range(max_tries): xbins = sc.linspace( coarse_x_bin_edges.dim, coarse_x_bin_edges[0], coarse_x_bin_edges[-1], nx ) ybins = sc.linspace( coarse_y_bin_edges.dim, coarse_y_bin_edges[0], coarse_y_bin_edges[-1], ny ) min_counts_per_pixel = ( events.bin( { coarse_x_bin_edges.dim: xbins, coarse_y_bin_edges.dim: ybins, } ) .bins.size() .min() ) if min_counts_per_pixel.value > 0: lower_nx = nx lower_ny = ny nx = max(min(round((upper_nx * nx) ** 0.5), nx * 2), lower_nx + 1) ny = max(min(round((upper_ny * ny) ** 0.5), ny * 2), lower_ny + 1) else: upper_nx = nx upper_ny = ny nx = min(round((lower_nx * nx) ** 0.5), upper_nx - 1) ny = min(round((lower_ny * ny) ** 0.5), upper_nx - 1) if upper_nx - lower_nx < 2 and upper_ny - lower_ny < 2: break if raise_if_not_maximum and upper_nx - lower_nx >= 2 and upper_ny - lower_ny >= 2: raise RuntimeError( 'Maximal resolution was not found. Increase `max_tries` to search longer. ' 'Or set `raise_if_not_maximum=False` if it is not necessary to locate the ' 'maximum exactly.' ) return ( sc.linspace( coarse_x_bin_edges.dim, coarse_x_bin_edges[0], coarse_x_bin_edges[-1], lower_nx, ), sc.linspace( coarse_y_bin_edges.dim, coarse_y_bin_edges[0], coarse_y_bin_edges[-1], lower_ny, ), )