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