Exemple #1
0
def _locate_droplets_in_mask_cylindrical(
    grid: CylindricalSymGrid, mask: np.ndarray
) -> Emulsion:
    """locate droplets in a data set on a (periodic) cylindrical grid

    This function locates droplets respecting periodic boundary conditions.

    Args:
        mask (:class:`~numpy.ndarray`):
            The binary image (or mask) in which the droplets are searched

    Returns:
        :class:`droplets.emulsions.Emulsion`: The discovered spherical droplets
    """
    assert np.all(mask.shape == grid.shape)

    if grid.periodic[1]:
        # locate droplets respecting periodic boundary conditions in z-direction

        # pad the array to simulate periodic boundary conditions
        dim_r, dim_z = grid.shape
        mask_padded = np.pad(mask, [[0, 0], [dim_z, dim_z]], mode="wrap")
        assert mask_padded.shape == (dim_r, 3 * dim_z)

        # locate droplets in the extended image
        candidates = _locate_droplets_in_mask_cylindrical_single(grid, mask_padded)
        grid._logger.info(f"Found {len(candidates)} droplet candidates.")

        # keep droplets that are inside the central area
        droplets = Emulsion(grid=grid)
        for droplet in candidates:
            # correct for the additional padding of the array
            droplet.position[2] -= grid.length
            # check whether the droplet lies in the original box
            if grid.contains_point(droplet.position):
                droplets.append(droplet)

        grid._logger.info(f"Kept {len(droplets)} central droplets.")

        # filter overlapping droplets (e.g. due to duplicates)
        droplets.remove_overlapping()

    else:
        # simply locate droplets in the mask
        droplets = _locate_droplets_in_mask_cylindrical_single(grid, mask)

    return droplets
Exemple #2
0
def _locate_droplets_in_mask_cylindrical_single(
    grid: CylindricalSymGrid, mask: np.ndarray
) -> Emulsion:
    """locate droplets in a data set on a single cylindrical grid

    Args:
        mask (:class:`~numpy.ndarray`):
            The binary image (or mask) in which the droplets are searched

    Returns:
        :class:`droplets.emulsions.Emulsion`: The discovered spherical droplets
    """
    # locate the individual clusters
    labels, num_features = ndimage.label(mask)
    if num_features == 0:
        return Emulsion([], grid=grid)

    # locate clusters on the symmetry axis
    object_slices = ndimage.measurements.find_objects(labels)
    indices = []
    for index, slices in enumerate(object_slices, 1):
        if slices[0].start == 0:  # contains point on symmetry axis
            indices.append(index)
        else:
            logger = logging.getLogger(grid.__class__.__module__)
            logger.warning("Found object not located on symmetry axis")

    # determine position from binary image and scale it to real space
    pos = ndimage.measurements.center_of_mass(mask, labels, index=indices)
    pos = grid.cell_to_point(pos)

    # determine volume from binary image and scale it to real space
    vol_r, dz = grid.cell_volume_data
    cell_volumes = vol_r * dz
    vol = ndimage.measurements.sum(cell_volumes, labels, index=indices)

    # return an emulsion of droplets
    droplets = (
        SphericalDroplet.from_volume(np.array([0, 0, p[2]]), v)
        for p, v in zip(pos, vol)
    )
    return Emulsion(droplets, grid=grid)
def test_localization_cylindrical(periodic):
    """tests simple droplets localization in cylindrical grid"""
    pos = (0, 0, np.random.uniform(-4, 4))
    radius = np.random.uniform(2, 3)
    width = np.random.uniform(0.5, 1.5)
    d1 = DiffuseDroplet(pos, radius, interface_width=width)

    grid_radius = 6 + 2 * np.random.random()
    bounds_z = np.random.uniform(1, 2, size=2) * np.array([-4, 4])
    grid = CylindricalSymGrid(grid_radius, bounds_z, (16, 32), periodic_z=periodic)
    field = d1.get_phase_field(grid)

    emulsion = image_analysis.locate_droplets(field, refine=True)
    assert len(emulsion) == 1
    d2 = emulsion[0]

    np.testing.assert_almost_equal(d1.position, d2.position, decimal=5)
    assert d1.radius == pytest.approx(d2.radius, rel=1e-5)
    assert d1.interface_width == pytest.approx(d2.interface_width)

    emulsion = image_analysis.locate_droplets(ScalarField(grid))
    assert len(emulsion) == 0
    with pytest.raises((ValueError, IndexError)):
        intp(np.array([100, -100]))

    res = f.make_interpolator(backend="numba", fill=45)(np.array([100, -100]))
    np.testing.assert_almost_equal(res, np.full(f.data_shape, 45))


@pytest.mark.slow
@pytest.mark.parametrize(
    "grid",
    [
        UnitGrid((6, )),
        PolarSymGrid(6, 4),
        SphericalSymGrid(7, 4),
        CylindricalSymGrid(6, (0, 8), (7, 8)),
    ],
)
def test_interpolation_to_cartesian(grid):
    """test whether data is interpolated correctly to Cartesian grid"""
    dim = grid.dim
    vf = VectorField(grid, 2)
    sf = vf[0]  # test extraction of fields
    fc = FieldCollection([sf, vf])

    # subset
    grid_cart = UnitGrid([4] * dim)
    for f in [sf, fc]:
        res = f.interpolate_to_grid(grid_cart)
        np.testing.assert_allclose(res.data, 2)
    with pytest.raises((ValueError, IndexError)):
        intp(np.array([100, -100]))

    res = f.make_interpolator(backend="numba", fill=45)(np.array([100, -100]))
    np.testing.assert_almost_equal(res, np.full(f.data_shape, 45))


@pytest.mark.slow
@pytest.mark.parametrize(
    "grid",
    [
        UnitGrid((6,)),
        PolarSymGrid(6, 4),
        SphericalSymGrid(7, 4),
        CylindricalSymGrid(6, (0, 8), (7, 8)),
    ],
)
def test_interpolation_to_cartesian(grid):
    """test whether data is interpolated correctly to Cartesian grid"""
    dim = grid.dim
    vf = VectorField(grid, 2)
    sf = vf[0]  # test extraction of fields
    fc = FieldCollection([sf, vf])

    # subset
    grid_cart = UnitGrid([4] * dim)
    for f in [sf, fc]:
        res = f.interpolate_to_grid(grid_cart)
        np.testing.assert_allclose(res.data, 2)