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
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)