Example #1
0
def test_display_progress(capsys):
    """ test whether this works """
    for _ in output.display_progress(range(2)):
        pass
    out, err = capsys.readouterr()
    assert out == ""
    assert len(err) > 0
Example #2
0
def get_performance_data(periodic=False):
    """ obtain the data used in the performance plot
    
    Args:
        periodic (bool): The boundary conditions of the underlying grid
        
    Returns:
        dict: The durations of calculating the Laplacian on different grids
        using different methods
    """
    sizes = 2**np.arange(3, 13)

    statistics = {}
    for size in display_progress(sizes):
        data = {}
        grid = UnitGrid([size] * 2, periodic=periodic)
        test_data = np.random.randn(*grid.shape)

        for method in ["numba", "scipy"]:
            op = grid.get_operator("laplace", bc="natural", method=method)
            data[method] = time_function(op, test_data)

        if opencv_laplace:
            data["opencv"] = time_function(opencv_laplace, test_data)

        statistics[int(size)] = data

    return statistics
Example #3
0
    def from_file(cls,
                  filename: str,
                  progress: bool = True) -> "EmulsionTimeCourse":
        """create emulsion time course by reading file

        Args:
            filename (str): The filename from which the emulsion is read
            progress (bool): Whether to show the progress of the process

        Returns:
            EmulsionTimeCourse: an instance describing the emulsion time course
        """
        import h5py

        obj = cls()
        with h5py.File(filename, "r") as fp:
            # read grid
            if "grid" in fp.attrs:
                grid: Optional[GridBase] = GridBase.from_state(
                    fp.attrs["grid"])
            else:
                grid = None

            # load the actual emulsion data and iterate in the right order
            for key in display_progress(sorted(fp.keys()),
                                        total=len(fp),
                                        enabled=progress):
                dataset = fp[key]
                obj.append(
                    Emulsion._from_hdf_dataset(dataset, grid),
                    time=dataset.attrs["time"],
                )
        return obj
Example #4
0
    def from_storage(cls,
                     storage: StorageBase,
                     refine: bool = False,
                     progress: bool = None,
                     **kwargs) -> "EmulsionTimeCourse":
        r"""create an emulsion time course from a stored phase field

        Args:
            storage (:class:`~pde.storage.base.StorageBase`):
                The phase fields for many time instances
            refine (bool):
                Flag determining whether the droplet properties should be refined
                using fitting. This is a potentially slow procedure.
            progress (bool):
                Whether to show the progress of the process. If `None`, the progress is
                only shown when `refine` is `True`.
            \**kwargs:
                All other parameters are forwarded to the
                :meth:`~droplets.image_analysis.locate_droplets`.

        Returns:
            EmulsionTimeCourse: an instance describing the emulsion time course
        """
        from .image_analysis import locate_droplets

        if progress is None:
            progress = refine  # show progress only when refining by default

        # obtain the emulsion data for all frames
        emulsions = (locate_droplets(frame, refine=refine, **kwargs)
                     for frame in display_progress(storage, enabled=progress))

        return cls(emulsions, times=storage.times)
Example #5
0
def get_performance_data(periodic=False):
    """obtain the data used in the performance plot

    Args:
        periodic (bool): The boundary conditions of the underlying grid

    Returns:
        dict: The durations of calculating the Laplacian on different grids
        using different methods
    """
    sizes = 2**np.arange(3, 13)

    statistics = {}
    for size in display_progress(sizes):
        data = {}
        grid = UnitGrid([size] * 2, periodic=periodic)
        field = ScalarField.random_normal(grid)
        field.set_ghost_cells(bc="auto_periodic_neumann")

        for backend in ["numba", "scipy"]:
            op = grid.make_operator("laplace",
                                    bc="auto_periodic_neumann",
                                    backend=backend)
            data[backend] = time_function(op, field.data)

        op = grid.make_operator_no_bc("laplace", backend="numba")
        data["numba_no_bc"] = time_function(op, field._data_full, use_out=True)

        if opencv_laplace:
            data["opencv"] = time_function(opencv_laplace, field.data)

        statistics[int(size)] = data

    return statistics
Example #6
0
    def from_emulsion_time_course(
        cls,
        time_course: "EmulsionTimeCourse",
        method: str = "overlap",
        progress: bool = False,
        **kwargs,
    ) -> "DropletTrackList":
        r"""obtain droplet tracks from an emulsion time course

        Args:
            time_course (:class:`droplets.emulsions.EmulsionTimeCourse`):
                A collection of temporally arranged emulsions
            method (str):
                The method used for tracking droplet identities. Possible methods are
                "overlap" (adding droplets that overlap with those in previous frames)
                and "distance" (matching droplets to minimize center-to-center
                distances).
            progress (bool):
                Whether to show the progress of the process.
            **kwargs:
                Additional parameters for the tracking algorithm. Currently, one can
                only specify a maximal distance (using `max_dist`) for the "distance"
                method.

        Returns:
            :class:`DropletTrackList`: the resulting droplet tracks
        """
        # get tracks, i.e. clearly overlapping droplets
        tracks = cls()
        logger = logging.getLogger(cls.__name__)

        # determine the tracking method
        if method == "overlap":
            # track droplets by their physical overlap

            def match_tracks(emulsion, tracks_alive, time):
                """helper function adding emulsions to the tracks"""
                found_multiple_overlap = False
                for droplet in emulsion:
                    # determine which old tracks could be extended
                    overlaps: List[DropletTrack] = []
                    for track in tracks_alive:
                        if track.last.overlaps(droplet, time_course.grid):
                            overlaps.append(track)

                    if len(overlaps) == 1:
                        overlaps[0].append(droplet, time=time)
                    else:
                        if len(overlaps) > 1:
                            found_multiple_overlap = True
                        tracks.append(DropletTrack(droplets=[droplet], times=[time]))

                if found_multiple_overlap:
                    logger.debug(f"Found multiple overlapping droplet(s) at t={time}")

        elif method == "distance":
            # track droplets by their physical distance

            max_dist = kwargs.pop("max_dist", np.inf)

            def match_tracks(emulsion, tracks_alive, time):
                """helper function adding emulsions to the tracks"""
                added = set()

                # calculate the distance between droplets
                if tracks_alive:
                    if time_course.grid is None:
                        metric = "euclidean"
                    else:
                        metric = time_course.grid.distance_real
                    points_prev = [track.last.position for track in tracks_alive]
                    points_now = [droplet.position for droplet in emulsion]
                    dists = distance.cdist(points_prev, points_now, metric=metric)

                    # impose a cutoff distance
                    dists[dists > max_dist] = np.inf

                    # add all matching droplets
                    while True:
                        i, j = np.unravel_index(np.argmin(dists), dists.shape)
                        if np.isinf(dists[i, j]):
                            break  # no more matches
                        added.add(j)
                        tracks_alive[i].append(emulsion[j], time=time)
                        dists[i, :] = np.inf
                        dists[:, j] = np.inf

                # add droplets that have not been matched
                for i, droplet in enumerate(emulsion):
                    if i not in added:
                        tracks.append(DropletTrack(droplets=[droplet], times=[time]))

        else:
            raise ValueError(f"Unknown tracking method {method}")

        # check kwargs
        if kwargs:
            logger.warning(f"Unused keyword arguments: {kwargs}")

        # add all emulsions successively using the given algorithm
        t_last = None
        for t, emulsion in display_progress(
            time_course.items(), total=len(time_course), enabled=progress
        ):
            # determine tracks from the last frame that have not yet been extended
            tracks_alive = [track for track in tracks if track.end == t_last]
            # match all tracks with the current emulsion
            match_tracks(emulsion, tracks_alive, time=t)
            t_last = t

        return tracks