diff --git a/docs/source/parse_examples.py b/docs/source/parse_examples.py index 6e56440..38e33cf 100755 --- a/docs/source/parse_examples.py +++ b/docs/source/parse_examples.py @@ -12,7 +12,7 @@ def main(): - """parse all examples and write them in a special example module""" + """Parse all examples and write them in a special example module.""" # create the output directory OUTPUT.mkdir(parents=True, exist_ok=True) diff --git a/docs/source/run_autodoc.py b/docs/source/run_autodoc.py index 6f08c64..6e4bc04 100755 --- a/docs/source/run_autodoc.py +++ b/docs/source/run_autodoc.py @@ -11,8 +11,8 @@ def replace_in_file(infile, replacements, outfile=None): - """reads in a file, replaces the given data using python formatting and - writes back the result to a file. + """Reads in a file, replaces the given data using python formatting and writes back + the result to a file. Args: infile (str): @@ -22,7 +22,6 @@ def replace_in_file(infile, replacements, outfile=None): outfile (str): Output file to which the data is written. If it is omitted, the input file will be overwritten instead - """ if outfile is None: outfile = infile diff --git a/docs/source/sphinx_simplify_typehints.py b/docs/source/sphinx_simplify_typehints.py index e59bc02..10c364c 100644 --- a/docs/source/sphinx_simplify_typehints.py +++ b/docs/source/sphinx_simplify_typehints.py @@ -1,6 +1,4 @@ -""" -Simple sphinx plug-in that simplifies type information in function signatures -""" +"""Simple sphinx plug-in that simplifies type information in function signatures.""" import collections import re @@ -87,7 +85,7 @@ def process_signature( app, what: str, name: str, obj, options, signature, return_annotation ): - """Process signature by applying replacement rules""" + """Process signature by applying replacement rules.""" if signature is not None: for key, value in REPLACEMENTS.items(): signature = signature.replace(key, value) @@ -97,5 +95,5 @@ def process_signature( def setup(app): - """set up hooks for this sphinx plugin""" + """Set up hooks for this sphinx plugin.""" app.connect("autodoc-process-signature", process_signature) diff --git a/droplets/__init__.py b/droplets/__init__.py index 25a9249..39aaf6c 100644 --- a/droplets/__init__.py +++ b/droplets/__init__.py @@ -1,5 +1,4 @@ -""" -Functions and classes for analyzing emulsions and droplets +"""Functions and classes for analyzing emulsions and droplets. .. codeauthor:: David Zwicker """ diff --git a/droplets/droplet_tracks.py b/droplets/droplet_tracks.py index 5889145..1e040ad 100644 --- a/droplets/droplet_tracks.py +++ b/droplets/droplet_tracks.py @@ -1,5 +1,4 @@ -""" -Classes representing the time evolution of droplets +"""Classes representing the time evolution of droplets. .. autosummary:: :nosignatures: @@ -33,7 +32,7 @@ def contiguous_true_regions(condition: np.ndarray) -> np.ndarray: - """Finds contiguous True regions in the boolean array "condition" + """Finds contiguous True regions in the boolean array "condition". Inspired by http://stackoverflow.com/a/4495197/932593 @@ -72,7 +71,7 @@ def contiguous_true_regions(condition: np.ndarray) -> np.ndarray: class DropletTrack: - """information about a single droplet over multiple time steps""" + """Information about a single droplet over multiple time steps.""" def __init__(self, droplets=None, times=None): """ @@ -105,7 +104,7 @@ def __init__(self, droplets=None, times=None): ) def __repr__(self): - """human-readable representation of a droplet track""" + """Human-readable representation of a droplet track.""" class_name = self.__class__.__name__ if len(self.times) == 0: return f"{class_name}([])" @@ -115,11 +114,11 @@ def __repr__(self): return f"{class_name}(timespan={self.start}..{self.end})" def __len__(self): - """number of time points""" + """Number of time points.""" return len(self.times) def __getitem__(self, key: int | slice): - """return the droplets identified by the given index/slice""" + """Return the droplets identified by the given index/slice.""" result = self.droplets.__getitem__(key) if isinstance(key, slice): return self.__class__(droplets=result, times=self.times[key]) @@ -127,7 +126,7 @@ def __getitem__(self, key: int | slice): return result def __eq__(self, other): - """determine whether two DropletTracks instance are equal""" + """Determine whether two DropletTracks instance are equal.""" return self.times == other.times and self.droplets == other.droplets @property @@ -160,7 +159,7 @@ def last(self) -> SphericalDroplet: @property def dim(self) -> int | None: - """return the space dimension of the droplets""" + """Return the space dimension of the droplets.""" try: return self.last.dim except IndexError: @@ -168,7 +167,7 @@ def dim(self) -> int | None: @property def data(self) -> np.ndarray | None: - """:class:`~numpy.ndarray`: an array containing the data of the full track""" + """:class:`~numpy.ndarray`: an array containing the data of the full track.""" if len(self) == 0: return None else: @@ -180,15 +179,15 @@ def data(self) -> np.ndarray | None: return result def __iter__(self): - """iterate over all droplets""" + """Iterate over all droplets.""" return iter(self.droplets) def items(self): - """iterate over all times and droplets, returning them in pairs""" + """Iterate over all times and droplets, returning them in pairs.""" return zip(self.times, self.droplets) def append(self, droplet: SphericalDroplet, time: float | None = None) -> None: - """append a new droplet with a time code + """Append a new droplet with a time code. Args: droplet (:class:`droplets.droplets.SphericalDroplet`): @@ -209,7 +208,7 @@ def append(self, droplet: SphericalDroplet, time: float | None = None) -> None: self.times.append(time) def get_position(self, time: float) -> np.ndarray: - """:class:`~numpy.ndarray`: returns the droplet position at a specific time""" + """:class:`~numpy.ndarray`: returns the droplet position at a specific time.""" try: idx = self.times.index(time) except AttributeError: @@ -220,7 +219,7 @@ def get_position(self, time: float) -> np.ndarray: def get_trajectory( self, smoothing: float = 0, *, attribute: str = "position" ) -> np.ndarray: - """return a the time-evolution of a droplet attribute (e.g., the position) + """Return a the time-evolution of a droplet attribute (e.g., the position) Args: smoothing (float): @@ -241,7 +240,7 @@ def get_trajectory( return trajectory def get_radii(self, smoothing: float = 0) -> np.ndarray: - """:class:`~numpy.ndarray`: returns the droplet radius for each time point + """:class:`~numpy.ndarray`: returns the droplet radius for each time point. Args: smoothing (float): @@ -251,7 +250,7 @@ def get_radii(self, smoothing: float = 0) -> np.ndarray: return self.get_trajectory(smoothing, attribute="radius") def get_volumes(self, smoothing: float = 0) -> np.ndarray: - """:class:`~numpy.ndarray`: returns the droplet volume for each time point + """:class:`~numpy.ndarray`: returns the droplet volume for each time point. Args: smoothing (float): @@ -261,7 +260,7 @@ def get_volumes(self, smoothing: float = 0) -> np.ndarray: return self.get_trajectory(smoothing, attribute="volume") def time_overlaps(self, other: DropletTrack) -> bool: - """determine whether two DropletTrack instances overlaps in time + """Determine whether two DropletTrack instances overlaps in time. Args: other (:class:`DropletTrack`): @@ -276,7 +275,7 @@ def time_overlaps(self, other: DropletTrack) -> bool: @classmethod def _from_hdf_dataset(cls, dataset) -> DropletTrack: - """construct a droplet track by reading data from an hdf5 dataset + """Construct a droplet track by reading data from an hdf5 dataset. Args: dataset: @@ -299,7 +298,7 @@ def _from_hdf_dataset(cls, dataset) -> DropletTrack: @classmethod def from_file(cls, path: str) -> DropletTrack: - """create droplet track by reading from file + """Create droplet track by reading from file. Args: path (str): @@ -320,7 +319,7 @@ def from_file(cls, path: str) -> DropletTrack: return obj def _write_hdf_dataset(self, hdf_path, key: str = "droplet_track"): - """write data to a given hdf5 path `hdf_path`""" + """Write data to a given hdf5 path `hdf_path`""" if self: # emulsion contains at least one droplet dataset = hdf_path.create_dataset(key, data=self.data) @@ -335,7 +334,7 @@ def _write_hdf_dataset(self, hdf_path, key: str = "droplet_track"): return dataset def to_file(self, path: str, info: InfoDict | None = None) -> None: - """store data in hdf5 file + """Store data in hdf5 file. The data can be read using the classmethod :meth:`DropletTrack.from_file`. @@ -364,7 +363,7 @@ def plot( ax=None, **kwargs, ) -> PlotReference: - """plot the time evolution of the droplet + """Plot the time evolution of the droplet. Args: attribute (str): @@ -411,7 +410,7 @@ def plot( def plot_positions( self, grid: GridBase | None = None, arrow: bool = True, ax=None, **kwargs ) -> PlotReference: - """plot the droplet track + """Plot the droplet track. Args: grid (GridBase, optional): @@ -479,10 +478,10 @@ def plot_positions( class DropletTrackList(list): - """a list of instances of :class:`DropletTrack`""" + """A list of instances of :class:`DropletTrack`""" def __getitem__(self, key: int | slice): # type: ignore - """return the droplets identified by the given index/slice""" + """Return the droplets identified by the given index/slice.""" result = super().__getitem__(key) if isinstance(key, slice): return self.__class__(result) @@ -499,7 +498,7 @@ def from_emulsion_time_course( progress: bool = False, **kwargs, ) -> DropletTrackList: - r"""obtain droplet tracks from an emulsion time course + r"""Obtain droplet tracks from an emulsion time course. Args: time_course (:class:`droplets.emulsions.EmulsionTimeCourse`): @@ -533,7 +532,7 @@ def from_emulsion_time_course( def match_tracks( emulsion: Emulsion, tracks_alive: list[DropletTrack], time: float ) -> None: - """helper function adding emulsions to the tracks""" + """Helper function adding emulsions to the tracks.""" found_multiple_overlap = False for droplet in emulsion: # determine which old tracks could be extended @@ -560,7 +559,7 @@ def match_tracks( def match_tracks( emulsion: Emulsion, tracks_alive: list[DropletTrack], time: float ) -> None: - """helper function adding emulsions to the tracks""" + """Helper function adding emulsions to the tracks.""" added = set() # calculate the distance between droplets @@ -621,7 +620,7 @@ def from_storage( num_processes: int | Literal["auto"] = 1, progress: bool | None = None, ) -> DropletTrackList: - r"""obtain droplet tracks from stored scalar field data + r"""Obtain droplet tracks from stored scalar field data. This method first determines an emulsion time course and than collects tracks by tracking droplets. @@ -656,7 +655,7 @@ def from_storage( @classmethod def from_file(cls, path: str) -> DropletTrackList: - """create droplet track list by reading file + """Create droplet track list by reading file. Args: path (str): @@ -676,7 +675,7 @@ def from_file(cls, path: str) -> DropletTrackList: return obj def to_file(self, path: str, info: InfoDict | None = None) -> None: - """store data in hdf5 file + """Store data in hdf5 file. The data can be read using the classmethod :meth:`DropletTrackList.from_file`. @@ -699,7 +698,7 @@ def to_file(self, path: str, info: InfoDict | None = None) -> None: fp.attrs[k] = json.dumps(v) def remove_short_tracks(self, min_duration: float = 0) -> None: - """remove tracks that a shorter than a minimal duration + """Remove tracks that a shorter than a minimal duration. Args: min_duration (float): @@ -713,7 +712,7 @@ def remove_short_tracks(self, min_duration: float = 0) -> None: @plot_on_axes() def plot(self, attribute: str = "radius", ax=None, **kwargs) -> PlotReference: - """plot the time evolution of all droplets + """Plot the time evolution of all droplets. Args: attribute (str): @@ -755,7 +754,7 @@ def plot(self, attribute: str = "radius", ax=None, **kwargs) -> PlotReference: @plot_on_axes() def plot_positions(self, ax=None, **kwargs) -> PlotReference: - """plot all droplet tracks + """Plot all droplet tracks. Args: {PLOT_ARGS} diff --git a/droplets/droplets.py b/droplets/droplets.py index 9dc58da..d140adf 100644 --- a/droplets/droplets.py +++ b/droplets/droplets.py @@ -1,5 +1,4 @@ -""" -Classes representing (perturbed) droplets in various dimensions +"""Classes representing (perturbed) droplets in various dimensions. The classes differ in what features of a droplet they track. In the simplest case, only the position and radius of a spherical droplet are stored. Other classes additionally @@ -53,7 +52,7 @@ def get_dtype_field_size(dtype: DTypeLike, field_name: str) -> int: - """return the number of elements in a field of structured numpy array + """Return the number of elements in a field of structured numpy array. Args: dtype (list): @@ -66,7 +65,7 @@ def get_dtype_field_size(dtype: DTypeLike, field_name: str) -> int: def iterate_in_pairs(it, fill=0): - """return consecutive pairs from an iterator + """Return consecutive pairs from an iterator. For instance, `list(pair_iterator('ABCDE', fill='Z'))` returns `[('A', 'B'), ('C', 'D'), ('E', 'Z')]` @@ -97,7 +96,7 @@ def iterate_in_pairs(it, fill=0): class DropletBase: - """represents a generic droplet + """Represents a generic droplet. The data associated with a droplet is stored in structured array. Consequently, the `dtype` of the array determines what information the droplet class stores. @@ -110,11 +109,11 @@ class DropletBase: data: np.recarray # all information about the droplet in a record array _merge_data: Callable[[np.ndarray, np.ndarray, np.ndarray], None] - """private method for merging droplet data, created by __init_subclass__""" + """Private method for merging droplet data, created by __init_subclass__""" @classmethod def from_data(cls, data: np.recarray) -> DropletBase: - """create droplet class from a given data + """Create droplet class from a given data. Args: data (:class:`numpy.recarray`): @@ -129,7 +128,7 @@ def from_data(cls, data: np.recarray) -> DropletBase: @classmethod def from_droplet(cls, droplet: DropletBase, **kwargs) -> DropletBase: - r"""return a droplet with data taken from `droplet` + r"""Return a droplet with data taken from `droplet` Args: droplet (:class:`DropletBase`): @@ -146,7 +145,7 @@ def from_droplet(cls, droplet: DropletBase, **kwargs) -> DropletBase: @classmethod @abstractmethod def get_dtype(cls, **kwargs) -> DTypeList: - """determine the dtype representing this droplet class + """Determine the dtype representing this droplet class. Returns: :class:`numpy.dtype`: @@ -155,7 +154,7 @@ def get_dtype(cls, **kwargs) -> DTypeList: ... def _init_data(self, **kwargs) -> None: - """initializes the `data` attribute if it is not present + """Initializes the `data` attribute if it is not present. Args: **kwargs: @@ -172,7 +171,7 @@ def _init_data(self, **kwargs) -> None: self.data = np.recarray(1, dtype=dtype)[0] def __init_subclass__(cls, **kwargs): # @NoSelf - """modify subclasses of this base class""" + """Modify subclasses of this base class.""" super().__init_subclass__(**kwargs) # register all subclassess to reconstruct them later @@ -192,7 +191,7 @@ def __eq__(self, other): ) def check_data(self): - """method that checks the validity and consistency of self.data""" + """Method that checks the validity and consistency of self.data.""" pass @property @@ -207,11 +206,11 @@ def __str__(self): @property def _data_array(self) -> np.ndarray: - """:class:`~numpy.ndarray`: the data of the droplet in an unstructured array""" + """:class:`~numpy.ndarray`: the data of the droplet in an unstructured array.""" return structured_to_unstructured(self.data) # type: ignore def copy(self: TDroplet, **kwargs) -> TDroplet: - r"""return a copy of the current droplet + r"""Return a copy of the current droplet. Args: \**kwargs: @@ -224,11 +223,11 @@ def copy(self: TDroplet, **kwargs) -> TDroplet: @classmethod def _make_merge_data(cls) -> Callable[[np.ndarray, np.ndarray, np.ndarray], None]: - """factory for a function that merges the data of two droplets""" + """Factory for a function that merges the data of two droplets.""" raise NotImplementedError def merge(self: TDroplet, other: TDroplet, *, inplace: bool = False) -> TDroplet: - """merge two droplets into one""" + """Merge two droplets into one.""" if inplace: self._merge_data(self.data, other.data, out=self.data) # type: ignore return self @@ -245,7 +244,7 @@ def data_bounds(self) -> tuple[np.ndarray, np.ndarray]: class SphericalDroplet(DropletBase): - """Represents a single, spherical droplet""" + """Represents a single, spherical droplet.""" __slots__ = ["data"] @@ -264,13 +263,13 @@ def __init__(self, position: np.ndarray, radius: float): self.check_data() def check_data(self): - """method that checks the validity and consistency of self.data""" + """Method that checks the validity and consistency of self.data.""" if self.radius < 0: raise ValueError("Radius must be positive") @classmethod def get_dtype(cls, **kwargs) -> DTypeList: - """determine the dtype representing this droplet class + """Determine the dtype representing this droplet class. Args: position (:class:`~numpy.ndarray`): @@ -299,7 +298,7 @@ def data_bounds(self) -> tuple[np.ndarray, np.ndarray]: @classmethod def from_volume(cls, position: np.ndarray, volume: float): - """Construct a droplet from given volume instead of radius + """Construct a droplet from given volume instead of radius. Args: position (:class:`~numpy.ndarray`): @@ -315,7 +314,7 @@ def from_volume(cls, position: np.ndarray, volume: float): @property def position(self) -> np.ndarray: - """:class:`~numpy.ndarray`: the position of the droplet""" + """:class:`~numpy.ndarray`: the position of the droplet.""" return self.data["position"] @position.setter @@ -342,7 +341,7 @@ def volume(self) -> float: @volume.setter def volume(self, volume: float) -> None: - """set the radius from a supplied volume""" + """Set the radius from a supplied volume.""" self.radius = spherical.radius_from_volume(volume, self.dim) @property @@ -352,13 +351,13 @@ def surface_area(self) -> float: @property def bbox(self) -> Cuboid: - """:class:`~pde.tools.cuboid.Cuboid`: bounding box of the droplet""" + """:class:`~pde.tools.cuboid.Cuboid`: bounding box of the droplet.""" return Cuboid.from_points( self.position - self.radius, self.position + self.radius ) def overlaps(self, other: SphericalDroplet, grid: GridBase | None = None) -> bool: - """determine whether another droplet overlaps with this one + """Determine whether another droplet overlaps with this one. Note that this function so far only compares the distances of the droplets to their radii, which does not respect perturbed droplets correctly. @@ -382,13 +381,13 @@ def overlaps(self, other: SphericalDroplet, grid: GridBase | None = None) -> boo @classmethod def _make_merge_data(cls) -> Callable[[np.ndarray, np.ndarray, np.ndarray], None]: - """factory for a function that merges the data of two droplets""" + """Factory for a function that merges the data of two droplets.""" radius_from_volume = spherical.make_radius_from_volume_nd_compiled() volume_from_radius = spherical.make_volume_from_radius_nd_compiled() @register_jitable def merge_data(drop1: np.ndarray, drop2: np.ndarray, out: np.ndarray) -> None: - """merge the data of two droplets""" + """Merge the data of two droplets.""" dim = len(drop1.position) # type: ignore V1 = volume_from_radius(drop1.radius, dim) # type: ignore @@ -403,7 +402,7 @@ def merge_data(drop1: np.ndarray, drop2: np.ndarray, out: np.ndarray) -> None: @preserve_scalars def interface_position(self, *args) -> np.ndarray: - r"""calculates the position of the interface of the droplet + r"""Calculates the position of the interface of the droplet. Args: *args (float or :class:`~numpy.ndarray`): @@ -497,7 +496,7 @@ def get_phase_field( return ScalarField(grid, data=data, label=label) def get_triangulation(self, resolution: float = 1) -> dict[str, Any]: - """obtain a triangulated shape of the droplet surface + """Obtain a triangulated shape of the droplet surface. Args: resolution (float): @@ -535,7 +534,7 @@ def get_triangulation(self, resolution: float = 1) -> dict[str, Any]: raise NotImplementedError(f"Triangulation not implemented for {self.dim}d") def _get_mpl_patch(self, dim=None, **kwargs): - """return the patch representing the droplet for plotting + """Return the patch representing the droplet for plotting. Args: dim (int, optional): @@ -567,7 +566,7 @@ def _get_mpl_patch(self, dim=None, **kwargs): @plot_on_axes() def plot(self, ax, value: Callable | None = None, **kwargs) -> PlotReference: - """Plot the droplet + """Plot the droplet. Args: {PLOT_ARGS} @@ -592,7 +591,7 @@ def plot(self, ax, value: Callable | None = None, **kwargs) -> PlotReference: class DiffuseDroplet(SphericalDroplet): - """Represents a single, spherical droplet with a diffuse interface""" + """Represents a single, spherical droplet with a diffuse interface.""" __slots__ = ["data"] @@ -624,7 +623,7 @@ def data_bounds(self) -> tuple[np.ndarray, np.ndarray]: @classmethod def get_dtype(cls, **kwargs) -> DTypeList: - """determine the dtype representing this droplet class + """Determine the dtype representing this droplet class. Args: position (:class:`~numpy.ndarray`): @@ -638,12 +637,12 @@ def get_dtype(cls, **kwargs) -> DTypeList: @classmethod def _make_merge_data(cls) -> Callable[[np.ndarray, np.ndarray, np.ndarray], None]: - """factory for a function that merges the data of two droplets""" + """Factory for a function that merges the data of two droplets.""" parent_merge = super()._make_merge_data() @register_jitable def merge_data(drop1: np.ndarray, drop2: np.ndarray, out: np.ndarray) -> None: - """merge the data of two droplets""" + """Merge the data of two droplets.""" parent_merge(drop1, drop2, out) out.interface_width = (drop1.interface_width + drop2.interface_width) / 2 # type: ignore @@ -705,7 +704,7 @@ def _get_phase_field(self, grid: GridBase, dtype: DTypeLike = float) -> np.ndarr class PerturbedDropletBase(DiffuseDroplet, metaclass=ABCMeta): - """represents a single droplet with a perturbed shape. + """Represents a single droplet with a perturbed shape. This acts as an abstract class for which member functions need to specified depending on dimensionality. @@ -743,7 +742,7 @@ def __init__( @classmethod def get_dtype(cls, **kwargs) -> DTypeList: - """determine the dtype representing this droplet class + """Determine the dtype representing this droplet class. Args: position (:class:`~numpy.ndarray`): @@ -784,7 +783,7 @@ def modes(self) -> int: @property def amplitudes(self) -> np.ndarray: - """:class:`~numpy.ndarray`: the perturbation amplitudes""" + """:class:`~numpy.ndarray`: the perturbation amplitudes.""" return np.atleast_1d(self.data["amplitudes"]) # type: ignore @amplitudes.setter @@ -856,7 +855,7 @@ def _get_phase_field(self, grid: GridBase, dtype: DTypeLike = float) -> np.ndarr return result.astype(dtype) def _get_mpl_patch(self, dim=None, *, color=None, **kwargs): - """return the patch representing the droplet for plotting + """Return the patch representing the droplet for plotting. Args: dim (int, optional): @@ -867,7 +866,7 @@ def _get_mpl_patch(self, dim=None, *, color=None, **kwargs): class PerturbedDroplet2D(PerturbedDropletBase): - r"""Represents a single droplet in two dimensions with a perturbed shape + r"""Represents a single droplet in two dimensions with a perturbed shape. The shape is described using the distance :math:`R(\phi)` of the interface from the `position`, which is a function of the polar angle :math:`\phi`. This function is @@ -918,7 +917,7 @@ def __init__( @preserve_scalars def interface_distance(self, φ: np.ndarray) -> np.ndarray: # type: ignore - """calculates the distance of the droplet interface to the origin + """Calculates the distance of the droplet interface to the origin. Args: φ (float or :class:`~np.ndarray`): @@ -937,7 +936,7 @@ def interface_distance(self, φ: np.ndarray) -> np.ndarray: # type: ignore @preserve_scalars def interface_position(self, φ: np.ndarray) -> np.ndarray: - """calculates the position of the interface of the droplet + """Calculates the position of the interface of the droplet. Args: φ (float or :class:`~np.ndarray`): @@ -952,7 +951,7 @@ def interface_position(self, φ: np.ndarray) -> np.ndarray: @preserve_scalars def interface_curvature(self, φ: np.ndarray) -> np.ndarray: # type: ignore - r"""calculates the mean curvature of the interface of the droplet + r"""Calculates the mean curvature of the interface of the droplet. For simplicity, the effect of the perturbations are only included to linear order in the perturbation amplitudes :math:`\epsilon^{(1/2)}_n`. @@ -981,7 +980,7 @@ def volume(self) -> float: @volume.setter def volume(self, volume: float) -> None: - """set volume keeping relative perturbations""" + """Set volume keeping relative perturbations.""" term = 1 + np.sum(self.amplitudes**2) / 2 self.radius = np.sqrt(volume / (np.pi * term)) @@ -1016,7 +1015,7 @@ def surface_area_approx(self) -> float: return np.pi * self.radius * length / 2 def _get_mpl_patch(self, dim=2, **kwargs): - """return the patch representing the droplet for plotting + """Return the patch representing the droplet for plotting. Args: dim (int, optional): @@ -1045,7 +1044,7 @@ def _get_mpl_patch(self, dim=2, **kwargs): class PerturbedDroplet3D(PerturbedDropletBase): - r"""Represents a single droplet in three dimensions with a perturbed shape + r"""Represents a single droplet in three dimensions with a perturbed shape. The shape is described using the distance :math:`R(\theta, \phi)` of the interface from the origin as a function of the azimuthal angle :math:`\theta` and the polar @@ -1101,7 +1100,7 @@ def __init__( def interface_distance( # type: ignore self, θ: np.ndarray, φ: np.ndarray | None = None ) -> np.ndarray: - r"""calculates the distance of the droplet interface to the origin + r"""Calculates the distance of the droplet interface to the origin. Args: θ (float or :class:`~np.ndarray`): @@ -1126,7 +1125,7 @@ def interface_distance( # type: ignore def interface_position( self, θ: np.ndarray, φ: np.ndarray | None = None ) -> np.ndarray: - r"""calculates the position of the interface of the droplet + r"""Calculates the position of the interface of the droplet. Args: θ (float or :class:`~np.ndarray`): @@ -1150,7 +1149,7 @@ def interface_position( def interface_curvature( # type: ignore self, θ: np.ndarray, φ: np.ndarray | None = None ) -> np.ndarray: - r"""calculates the mean curvature of the interface of the droplet + r"""Calculates the mean curvature of the interface of the droplet. For simplicity, the effect of the perturbations are only included to linear order in the perturbation amplitudes :math:`\epsilon_{l,m}`. @@ -1182,7 +1181,7 @@ def volume(self) -> float: """float: volume of the droplet (determined numerically)""" def integrand(θ, φ): - """helper function calculating the integrand""" + """Helper function calculating the integrand.""" r = self.interface_distance(θ, φ) return r**3 * np.sin(θ) / 3 @@ -1193,7 +1192,7 @@ def integrand(θ, φ): @volume.setter def volume(self, volume: float) -> None: - """set volume keeping relative perturbations""" + """Set volume keeping relative perturbations.""" raise NotImplementedError("Cannot set volume") @property @@ -1206,7 +1205,7 @@ def volume_approx(self) -> float: class PerturbedDroplet3DAxisSym(PerturbedDropletBase): - r"""Represents a droplet axisymmetrically perturbed shape in three dimensions + r"""Represents a droplet axisymmetrically perturbed shape in three dimensions. The shape is described using the distance :math:`R(\theta)` of the interface from the origin as a function of the azimuthal angle :math:`\theta`, while polar symmetry @@ -1226,14 +1225,14 @@ class PerturbedDroplet3DAxisSym(PerturbedDropletBase): __slots__ = ["data"] def check_data(self): - """method that checks the validity and consistency of self.data""" + """Method that checks the validity and consistency of self.data.""" super().check_data() if not np.allclose(self.position[:2], 0): raise ValueError("Droplet must lie on z-axis") @preserve_scalars def interface_distance(self, θ: np.ndarray) -> np.ndarray: # type: ignore - r"""calculates the distance of the droplet interface to the origin + r"""Calculates the distance of the droplet interface to the origin. Args: θ (float or :class:`~np.ndarray`): @@ -1250,7 +1249,7 @@ def interface_distance(self, θ: np.ndarray) -> np.ndarray: # type: ignore @preserve_scalars def interface_curvature(self, θ: np.ndarray) -> np.ndarray: # type: ignore - r"""calculates the mean curvature of the interface of the droplet + r"""Calculates the mean curvature of the interface of the droplet. For simplicity, the effect of the perturbations are only included to linear order in the perturbation amplitudes :math:`\epsilon_{l,m}`. @@ -1280,7 +1279,7 @@ def volume_approx(self) -> float: def droplet_from_data(droplet_class: str, data: np.ndarray) -> DropletBase: - """create a droplet instance of the given class using some data + """Create a droplet instance of the given class using some data. Args: droplet_class (str): @@ -1293,7 +1292,7 @@ def droplet_from_data(droplet_class: str, data: np.ndarray) -> DropletBase: class _TriangulatedSpheres: - """helper class for handling stored data about triangulated spheres""" + """Helper class for handling stored data about triangulated spheres.""" def __init__(self) -> None: self.path = Path(__file__).resolve().parent / "resources" / "spheres_3d.hdf5" @@ -1301,7 +1300,7 @@ def __init__(self) -> None: self.data: dict[int, dict[str, Any]] | None = None def _load(self): - """load the stored resource""" + """Load the stored resource.""" import h5py logger = logging.getLogger(__name__) @@ -1319,7 +1318,7 @@ def _load(self): self.data[num] = tri def get_triangulation(self, num_est: int = 1) -> dict[str, Any]: - """get a triangulation of a sphere + """Get a triangulation of a sphere. Args: num_est (int): The rough number of vertices in the triangulation diff --git a/droplets/emulsions.py b/droplets/emulsions.py index 69aa397..fc46bc4 100644 --- a/droplets/emulsions.py +++ b/droplets/emulsions.py @@ -1,5 +1,5 @@ -""" -Classes describing collections of droplets, i.e. emulsions, and their temporal dynamics. +"""Classes describing collections of droplets, i.e. emulsions, and their temporal +dynamics. .. autosummary:: :nosignatures: @@ -39,7 +39,7 @@ class Emulsion(list): - """class representing a collection of droplets in a common system""" + """Class representing a collection of droplets in a common system.""" _show_projection_warning: bool = True """bool: Flag determining whether a warning is shown when high-dimensional @@ -94,7 +94,7 @@ def __init__( @classmethod def empty(cls, droplet: SphericalDroplet) -> Emulsion: - """create empty emulsion with particular droplet type + """Create empty emulsion with particular droplet type. Args: droplet (:class:`~droplets.droplets.SphericalDroplet`): @@ -116,8 +116,7 @@ def from_random( droplet_class: type[SphericalDroplet] = SphericalDroplet, rng: np.random.Generator | None = None, ) -> Emulsion: - """ - Create an emulsion with random droplets + """Create an emulsion with random droplets. Args: num (int): @@ -204,7 +203,7 @@ def __getitem__(self, key): return Emulsion(result) def copy(self, min_radius: float = -1) -> Emulsion: - """return a copy of this emulsion + """Return a copy of this emulsion. Args: min_radius (float): @@ -224,7 +223,7 @@ def extend( copy: bool = True, force_consistency: bool = False, ) -> None: - """add many droplets to the emulsion + """Add many droplets to the emulsion. Args: droplet (list of :class:`droplets.dropelts.SphericalDroplet`): @@ -244,7 +243,7 @@ def append( copy: bool = True, force_consistency: bool = False, ) -> None: - """add a droplet to the emulsion + """Add a droplet to the emulsion. Args: droplet (:class:`droplets.dropelts.SphericalDroplet`): @@ -269,7 +268,7 @@ def append( @property def data(self) -> np.ndarray: - """:class:`~numpy.ndarray`: an array containing the data of the full emulsion + """:class:`~numpy.ndarray`: an array containing the data of the full emulsion. Warning: This requires all droplets to be of the same class. The returned array is @@ -302,7 +301,7 @@ def data(self) -> np.ndarray: return result def get_linked_data(self) -> np.ndarray: - """link the data of all droplets in a single array + """Link the data of all droplets in a single array. Returns: :class:`~numpy.ndarray`: The array containing all droplet data. If entries in @@ -316,7 +315,7 @@ def get_linked_data(self) -> np.ndarray: @classmethod def _from_hdf_dataset(cls, dataset) -> Emulsion: - """construct an emulsion by reading data from an hdf5 dataset + """Construct an emulsion by reading data from an hdf5 dataset. Args: dataset: @@ -338,7 +337,7 @@ def _from_hdf_dataset(cls, dataset) -> Emulsion: @classmethod def from_file(cls, path: str) -> Emulsion: - """create emulsion by reading file + """Create emulsion by reading file. Args: path (str): @@ -361,7 +360,7 @@ def from_file(cls, path: str) -> Emulsion: return obj def _write_hdf_dataset(self, hdf_path, key: str = "emulsion"): - """write data to a given hdf5 path `hdf_path` + """Write data to a given hdf5 path `hdf_path` Args: hdf_path: @@ -386,7 +385,7 @@ def _write_hdf_dataset(self, hdf_path, key: str = "emulsion"): return dataset def to_file(self, path: str) -> None: - """store data in hdf5 file + """Store data in hdf5 file. The data can be read using the classmethod :meth:`Emulsion.from_file`. @@ -426,13 +425,13 @@ def interface_width(self) -> float | None: @property def bbox(self) -> Cuboid: - """:class:`Cuboid`: bounding box of the emulsion""" + """:class:`Cuboid`: bounding box of the emulsion.""" if len(self) == 0: raise RuntimeError("Bounding box of empty emulsion is undefined") return sum((droplet.bbox for droplet in self[1:]), self[0].bbox) def get_phasefield(self, grid: GridBase, label: str | None = None) -> ScalarField: - """create a phase field representing a list of droplets + """Create a phase field representing a list of droplets. Args: grid (:class:`pde.grids.base.GridBase`): @@ -455,7 +454,7 @@ def get_phasefield(self, grid: GridBase, label: str | None = None) -> ScalarFiel return result def remove_small(self, min_radius: float = -np.inf) -> None: - """remove droplets that are very small + """Remove droplets that are very small. The emulsions is modified in-place. @@ -472,7 +471,7 @@ def remove_small(self, min_radius: float = -np.inf) -> None: def get_pairwise_distances( self, subtract_radius: bool = False, grid: GridBase | None = None ) -> np.ndarray: - """return the pairwise distance between droplets + """Return the pairwise distance between droplets. Args: subtract_radius (bool): @@ -489,7 +488,7 @@ def get_pairwise_distances( if grid is None: def get_distance(p1, p2): - """helper function calculating the distance between points""" + """Helper function calculating the distance between points.""" return np.linalg.norm(p1 - p2) else: @@ -510,7 +509,7 @@ def get_distance(p1, p2): return dists def get_neighbor_distances(self, subtract_radius: bool = False) -> np.ndarray: - """calculates the distance of each droplet to its nearest neighbor + """Calculates the distance of each droplet to its nearest neighbor. Warning: This function does not take periodic boundary conditions into account. @@ -551,7 +550,7 @@ def get_neighbor_distances(self, subtract_radius: bool = False) -> np.ndarray: def remove_overlapping( self, min_distance: float = 0, grid: GridBase | None = None ) -> None: - """remove all droplets that are overlapping + """Remove all droplets that are overlapping. If a pair of overlapping droplets was found, the smaller one of these is removed from the current emulsion. This method modifies the emulsion in place and thus @@ -591,7 +590,7 @@ def total_droplet_volume(self) -> float: return sum(droplet.volume for droplet in self) # type: ignore def get_size_statistics(self, incl_vanished: bool = True) -> dict[str, float]: - """determine size statistics of the current emulsion + """Determine size statistics of the current emulsion. Args: incl_vanished (bool): @@ -637,7 +636,7 @@ def plot( colorbar: bool | str = True, **kwargs, ) -> PlotReference: - """plot the current emulsion together with a corresponding field + """Plot the current emulsion together with a corresponding field. If the emulsion is defined in a 3d geometry, only a projection on the first two axes is shown. @@ -774,7 +773,7 @@ def plot( class EmulsionTimeCourse: - """represents emulsions as a function of time""" + """Represents emulsions as a function of time.""" def __init__( self, @@ -811,7 +810,7 @@ def __init__( def append( self, emulsion: Emulsion, time: float | None = None, copy: bool = True ) -> None: - """add an emulsion to the list + """Add an emulsion to the list. Args: emulsions (Emulsion): @@ -833,7 +832,7 @@ def append( self.times.append(time) def clear(self) -> None: - """removes all data stored in this instance""" + """Removes all data stored in this instance.""" self.emulsions = [] self.times = [] @@ -847,7 +846,7 @@ def __len__(self): return len(self.times) def __getitem__(self, key: int | slice): - """return the information for the given index""" + """Return the information for the given index.""" result = self.emulsions.__getitem__(key) if isinstance(key, slice): return self.__class__(emulsions=result, times=self.times[key]) @@ -855,15 +854,15 @@ def __getitem__(self, key: int | slice): return result def __iter__(self) -> Iterator[Emulsion]: - """iterate over the emulsions""" + """Iterate over the emulsions.""" return iter(self.emulsions) def items(self) -> Iterator[tuple[float, Emulsion]]: - """iterate over all times and emulsions, returning them in pairs""" + """Iterate over all times and emulsions, returning them in pairs.""" return zip(self.times, self.emulsions) def __eq__(self, other): - """determine whether two EmulsionTimeCourse instance are equal""" + """Determine whether two EmulsionTimeCourse instance are equal.""" return self.times == other.times and self.emulsions == other.emulsions @classmethod @@ -876,7 +875,7 @@ def from_storage( progress: bool | None = None, **kwargs, ) -> EmulsionTimeCourse: - r"""create an emulsion time course from a stored phase field + r"""Create an emulsion time course from a stored phase field. Args: storage (:class:`~pde.storage.base.StorageBase`): @@ -927,7 +926,7 @@ def from_storage( @classmethod def from_file(cls, path: str, progress: bool = True) -> EmulsionTimeCourse: - """create emulsion time course by reading file + """Create emulsion time course by reading file. Args: path (str): @@ -954,7 +953,7 @@ def from_file(cls, path: str, progress: bool = True) -> EmulsionTimeCourse: return obj def to_file(self, path: str, info: InfoDict | None = None) -> None: - """store data in hdf5 file + """Store data in hdf5 file. The data can be read using the classmethod :meth:`EmulsionTimeCourse.from_file`. @@ -978,7 +977,7 @@ def to_file(self, path: str, info: InfoDict | None = None) -> None: fp.attrs[k] = json.dumps(v) def get_emulsion(self, time: float) -> Emulsion: - """returns the emulsion clostest to a specific time point + """Returns the emulsion clostest to a specific time point. Args: time (float): The time point @@ -997,7 +996,7 @@ def tracker( *, interval=None, ) -> DropletTracker: - """return a tracker that analyzes emulsions during simulations + """Return a tracker that analyzes emulsions during simulations. Args: interrupts: diff --git a/droplets/image_analysis.py b/droplets/image_analysis.py index 9199940..d198741 100644 --- a/droplets/image_analysis.py +++ b/droplets/image_analysis.py @@ -1,5 +1,4 @@ -""" -Functions for analyzing phase field images of emulsions. +"""Functions for analyzing phase field images of emulsions. .. autosummary:: :nosignatures: @@ -92,7 +91,7 @@ def threshold_otsu(data: np.ndarray, nbins: int = 256) -> float: def _locate_droplets_in_mask_cartesian(mask: ScalarField) -> Emulsion: - """locate droplets in a (potentially periodic) data set on a Cartesian grid + """Locate droplets in a (potentially periodic) data set on a Cartesian grid. This function locates droplets respecting periodic boundary conditions. @@ -175,7 +174,7 @@ def _locate_droplets_in_mask_cartesian(mask: ScalarField) -> Emulsion: def _locate_droplets_in_mask_spherical(mask: ScalarField) -> Emulsion: - """locates droplets in a binary data set on a spherical grid + """Locates droplets in a binary data set on a spherical grid. Args: mask (:class:`~pde.fields.scalar.ScalarField`): @@ -211,7 +210,7 @@ def _locate_droplets_in_mask_spherical(mask: ScalarField) -> Emulsion: class _SpanningDropletSignal(RuntimeError): - """exception signaling that an untypical droplet spanning the system was found""" + """Exception signaling that an untypical droplet spanning the system was found.""" ... @@ -219,7 +218,7 @@ class _SpanningDropletSignal(RuntimeError): def _locate_droplets_in_mask_cylindrical_single( grid: CylindricalSymGrid, mask: np.ndarray ) -> Emulsion: - """locate droplets in a data set on a single cylindrical grid + """Locate droplets in a data set on a single cylindrical grid. Args: grid: @@ -271,7 +270,7 @@ def _locate_droplets_in_mask_cylindrical_single( def _locate_droplets_in_mask_cylindrical(mask: ScalarField) -> Emulsion: - """locate droplets in a data set on a (periodic) cylindrical grid + """Locate droplets in a data set on a (periodic) cylindrical grid. This function locates droplets respecting periodic boundary conditions. @@ -324,7 +323,7 @@ def _locate_droplets_in_mask_cylindrical(mask: ScalarField) -> Emulsion: def locate_droplets_in_mask(mask: ScalarField) -> Emulsion: - """locates droplets in a binary image + """Locates droplets in a binary image. This function locates droplets respecting periodic boundary conditions. @@ -358,7 +357,7 @@ def locate_droplets( refine_args: dict[str, Any] | None = None, num_processes: int | Literal["auto"] = 1, ) -> Emulsion: - """Locates droplets in the phase field + """Locates droplets in the phase field. This uses a binarized image to locate clusters of large concentration in the phase field, which are interpreted as droplets. Basic quantities, like position and size, @@ -493,7 +492,7 @@ def refine_droplets( num_processes: int | Literal["auto"] = 1, **kwargs, ) -> list[DiffuseDroplet]: - r"""Refines many droplets by fitting to phase field + r"""Refines many droplets by fitting to phase field. Args: phase_field (:class:`~pde.fields.ScalarField`): @@ -548,7 +547,7 @@ def refine_droplet( tolerance: float | None = None, least_squares_params: dict[str, Any] | None = None, ) -> DiffuseDroplet: - """Refines droplet parameters by fitting to phase field + """Refines droplet parameters by fitting to phase field. This function varies droplet parameters, like position, size, interface width, and potential perturbation amplitudes until the overlap with the respective phase field @@ -628,7 +627,7 @@ def refine_droplet( bounds = np.r_[bounds[0], vmin - vrng, 0], np.r_[bounds[1], vmax, 3 * vrng] def _image_deviation(params): - """helper function evaluating the residuals""" + """Helper function evaluating the residuals.""" # generate the droplet data_flat[free] = params[:-2] vmin, vrng = params[-2:] @@ -647,7 +646,7 @@ def _image_deviation(params): # fit only droplet parameters and assume all intensities fixed def _image_deviation(params): - """helper function evaluating the residuals""" + """Helper function evaluating the residuals.""" # generate the droplet data_flat[free] = params droplet.data = unstructured_to_structured(data_flat, dtype=dtype) @@ -676,7 +675,7 @@ def get_structure_factor( wave_numbers: Sequence[float] | Literal["auto"] = "auto", add_zero: bool = False, ) -> tuple[np.ndarray, np.ndarray]: - r"""Calculates the structure factor associated with a field + r"""Calculates the structure factor associated with a field. Here, the structure factor is basically the power spectral density of the field `scalar_field` normalized so that re-gridding or rescaling the field does not change @@ -785,7 +784,7 @@ def get_length_scale( ] = "structure_factor_maximum", **kwargs, ) -> float | tuple[float, Any]: - """Calculates a length scale associated with a phase field + """Calculates a length scale associated with a phase field. Args: scalar_field (:class:`~pde.fields.ScalarField`): diff --git a/droplets/resources/make_spheres_3d.py b/droplets/resources/make_spheres_3d.py index 56c24d7..58658ac 100755 --- a/droplets/resources/make_spheres_3d.py +++ b/droplets/resources/make_spheres_3d.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -"""script that creates the resource with discretized surfaces of unit spheres """ +"""Script that creates the resource with discretized surfaces of unit spheres.""" from __future__ import annotations diff --git a/droplets/tools/spherical.py b/droplets/tools/spherical.py index c485617..70b9910 100644 --- a/droplets/tools/spherical.py +++ b/droplets/tools/spherical.py @@ -1,5 +1,4 @@ -r""" -Module collecting functions for handling spherical geometry +r"""Module collecting functions for handling spherical geometry. The coordinate systems use the following convention for polar coordinates :math:`(r, \phi)`, where :math:`r` is the radial coordinate and :math:`\phi` is @@ -29,7 +28,7 @@ The module also provides functions for handling spherical harmonics. -These spherical harmonics are described by the degree :math:`l` and the order +These spherical harmonics are described by the degree :math:`l` and the order :math:`m` or, alternatively, by the mode :math:`k`. The relation between these values is @@ -69,7 +68,7 @@ spherical_harmonic_real spherical_harmonic_real_k -.. codeauthor:: David Zwicker +.. codeauthor:: David Zwicker """ from __future__ import annotations @@ -91,7 +90,7 @@ def radius_from_volume(volume: TNumArr, dim: int) -> TNumArr: - """Return the radius of a sphere with a given volume + """Return the radius of a sphere with a given volume. Args: volume (float or :class:`~numpy.ndarray`): @@ -113,7 +112,7 @@ def radius_from_volume(volume: TNumArr, dim: int) -> TNumArr: def make_radius_from_volume_compiled(dim: int) -> Callable[[TNumArr], TNumArr]: - """Return a function calculating the radius of a sphere with a given volume + """Return a function calculating the radius of a sphere with a given volume. Args: dim (int): @@ -143,7 +142,7 @@ def radius_from_volume(volume: TNumArr) -> TNumArr: def make_radius_from_volume_nd_compiled() -> Callable[[TNumArr, int], TNumArr]: - """Return a function calculating the radius of a sphere with a given volume + """Return a function calculating the radius of a sphere with a given volume. Returns: function: A function that calculate the radius from a volume and dimension @@ -163,7 +162,7 @@ def radius_from_volume(volume: TNumArr, dim: int) -> TNumArr: def make_volume_from_radius_compiled(dim: int) -> Callable[[TNumArr], TNumArr]: - """Return a function calculating the volume of a sphere with a given radius + """Return a function calculating the volume of a sphere with a given radius. Args: dim (int): @@ -193,7 +192,7 @@ def volume_from_radius(radius: TNumArr) -> TNumArr: def make_volume_from_radius_nd_compiled() -> Callable[[TNumArr, int], TNumArr]: - """Return a function calculating the volume of a sphere with a given radius + """Return a function calculating the volume of a sphere with a given radius. Returns: function: A function that calculates the volume using a radius and dimension @@ -213,7 +212,7 @@ def volume_from_radius(radius: TNumArr, dim: int) -> TNumArr: def surface_from_radius(radius: TNumArr, dim: int) -> TNumArr: - """Return the surface area of a sphere with a given radius + """Return the surface area of a sphere with a given radius. Args: radius (float or :class:`~numpy.ndarray`): @@ -240,7 +239,7 @@ def surface_from_radius(radius: TNumArr, dim: int) -> TNumArr: def radius_from_surface(surface: TNumArr, dim: int) -> TNumArr: - """Return the radius of a sphere with a given surface area + """Return the radius of a sphere with a given surface area. Args: surface (float or :class:`~numpy.ndarray`): @@ -262,7 +261,7 @@ def radius_from_surface(surface: TNumArr, dim: int) -> TNumArr: def make_surface_from_radius_compiled(dim: int) -> Callable[[TNumArr], TNumArr]: - """Return a function calculating the surface area of a sphere + """Return a function calculating the surface area of a sphere. Args: dim (int): Dimension of the space @@ -311,7 +310,7 @@ def surface_from_radius(radius: TNumArr) -> TNumArr: def points_cartesian_to_spherical(points: np.ndarray) -> np.ndarray: - """Convert points from Cartesian to spherical coordinates + """Convert points from Cartesian to spherical coordinates. Args: points (:class:`~numpy.ndarray`): Points in Cartesian coordinates @@ -334,7 +333,7 @@ def points_cartesian_to_spherical(points: np.ndarray) -> np.ndarray: def points_spherical_to_cartesian(points: np.ndarray) -> np.ndarray: - """Convert points from spherical to Cartesian coordinates + """Convert points from spherical to Cartesian coordinates. Args: points (:class:`~numpy.ndarray`): @@ -373,7 +372,7 @@ def polar_coordinates( def polar_coordinates( grid: GridBase, *, origin: np.ndarray | None = None, ret_angle: bool = False ) -> np.ndarray | tuple[np.ndarray, ...]: - """return polar coordinates associated with grid points + """Return polar coordinates associated with grid points. Args: grid (:class:`~pde.grids.base.GridBase`): @@ -425,7 +424,7 @@ def polar_coordinates( def spherical_index_k(degree: int, order: int = 0) -> int: - """returns the mode `k` from the degree `degree` and order `order` + """Returns the mode `k` from the degree `degree` and order `order` Args: degree (int): @@ -445,7 +444,7 @@ def spherical_index_k(degree: int, order: int = 0) -> int: def spherical_index_lm(k: int) -> tuple[int, int]: - """returns the degree `l` and the order `m` from the mode `k` + """Returns the degree `l` and the order `m` from the mode `k` Args: k (int): @@ -460,7 +459,7 @@ def spherical_index_lm(k: int) -> tuple[int, int]: def spherical_index_count(l: int) -> int: - """return the number of modes for all indices <= l + """Return the number of modes for all indices <= l. The returned value is one less than the maximal mode `k` required. @@ -475,7 +474,7 @@ def spherical_index_count(l: int) -> int: def spherical_index_count_optimal(k_count: int) -> bool: - """checks whether the modes captures all orders for maximal degree + """Checks whether the modes captures all orders for maximal degree. Args: k_count (int): @@ -489,7 +488,7 @@ def spherical_index_count_optimal(k_count: int) -> bool: def spherical_harmonic_symmetric(degree: int, θ: float) -> float: - r"""axisymmetric spherical harmonics with degree `degree`, so `m=0`. + r"""Axisymmetric spherical harmonics with degree `degree`, so `m=0`. Args: degree (int): @@ -506,7 +505,7 @@ def spherical_harmonic_symmetric(degree: int, θ: float) -> float: def spherical_harmonic_real(degree: int, order: int, θ: float, φ: float) -> float: - r"""real spherical harmonics of degree l and order m + r"""Real spherical harmonics of degree l and order m. Args: degree (int): @@ -539,7 +538,7 @@ def spherical_harmonic_real(degree: int, order: int, θ: float, φ: float) -> fl def spherical_harmonic_real_k(k: int, θ: float, φ: float) -> float: - r"""real spherical harmonics described by mode k + r"""Real spherical harmonics described by mode k. Args: k (int): diff --git a/droplets/trackers.py b/droplets/trackers.py index c1562aa..b594cdd 100644 --- a/droplets/trackers.py +++ b/droplets/trackers.py @@ -1,5 +1,4 @@ -""" -Module defining classes for tracking droplets in simulations. +"""Module defining classes for tracking droplets in simulations. .. autosummary:: :nosignatures: @@ -23,7 +22,7 @@ class LengthScaleTracker(TrackerBase): - """Tracker that stores length scales measured in simulations + """Tracker that stores length scales measured in simulations. Attributes: times (list): @@ -75,7 +74,7 @@ def __init__( self.verbose = verbose def handle(self, field: FieldBase, t: float): - """handle data supplied to this tracker + """Handle data supplied to this tracker. Args: field (:class:`~pde.fields.FieldBase`): @@ -102,7 +101,7 @@ def handle(self, field: FieldBase, t: float): self.length_scales.append(length) # type: ignore def finalize(self, info: InfoDict | None = None) -> None: - """finalize the tracker, supplying additional information + """Finalize the tracker, supplying additional information. Args: info (dict): @@ -118,7 +117,7 @@ def finalize(self, info: InfoDict | None = None) -> None: class DropletTracker(TrackerBase): - """Detect droplets in a scalar field during simulations + """Detect droplets in a scalar field during simulations. This tracker is useful when only the parameters of actual droplets are needed, since it stores considerably less information compared to the full scalar field. @@ -214,7 +213,7 @@ def __init__( self.perturbation_modes = perturbation_modes def handle(self, field: FieldBase, t: float) -> None: - """handle data supplied to this tracker + """Handle data supplied to this tracker. Args: field (:class:`~pde.fields.base.FieldBase`): @@ -238,7 +237,7 @@ def handle(self, field: FieldBase, t: float) -> None: self.data.append(emulsion, t) def finalize(self, info: InfoDict | None = None) -> None: - """finalize the tracker, supplying additional information + """Finalize the tracker, supplying additional information. Args: info (dict): diff --git a/scripts/format_code.sh b/scripts/format_code.sh index 2366dc0..0d91fc6 100755 --- a/scripts/format_code.sh +++ b/scripts/format_code.sh @@ -9,5 +9,8 @@ popd > /dev/null echo "Formating import statements..." isort .. +echo "Formating docstrings..." +docformatter --in-place --black --recursive .. + echo "Formating source code..." black .. \ No newline at end of file diff --git a/scripts/run_tests.py b/scripts/run_tests.py index e555393..8e92b42 100755 --- a/scripts/run_tests.py +++ b/scripts/run_tests.py @@ -12,7 +12,7 @@ def _most_severe_exit_code(retcodes: Sequence[int]) -> int: - """returns the most severe exit code of a given list + """Returns the most severe exit code of a given list. Args: retcodes (list): A list of return codes @@ -27,7 +27,7 @@ def _most_severe_exit_code(retcodes: Sequence[int]) -> int: def test_codestyle(*, verbose: bool = True) -> int: - """run the codestyle tests + """Run the codestyle tests. Args: verbose (bool): Whether to do extra output @@ -53,7 +53,7 @@ def test_codestyle(*, verbose: bool = True) -> int: def test_types(*, report: bool = False, verbose: bool = True) -> int: - """run mypy to check the types of the python code + """Run mypy to check the types of the python code. Args: report (bool): Whether to write a report @@ -96,7 +96,7 @@ def run_unit_tests( no_numba: bool = False, pattern: str = None, ) -> int: - """run the unit tests + """Run the unit tests. Args: runslow (bool): Whether to run the slow tests @@ -166,7 +166,7 @@ def run_unit_tests( def main() -> int: - """the main program controlling the tests + """The main program controlling the tests. Returns: int: The return code indicating success or failure diff --git a/tests/conftest.py b/tests/conftest.py index 78b2cfd..f26f09e 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,5 +1,4 @@ -""" -This file is used to configure the test environment when running py.test +"""This file is used to configure the test environment when running py.test. .. codeauthor:: David Zwicker """ @@ -13,7 +12,7 @@ @pytest.fixture(scope="function", autouse=False, name="rng") def init_random_number_generators(): - """get a random number generator and set the seed of the random number generator + """Get a random number generator and set the seed of the random number generator. The function returns an instance of :func:`~numpy.random.default_rng()` and initializes the default generators of both :mod:`numpy` and :mod:`numba`. @@ -24,7 +23,7 @@ def init_random_number_generators(): @pytest.fixture(scope="function", autouse=True) def setup_and_teardown(): - """helper function adjusting environment before and after tests""" + """Helper function adjusting environment before and after tests.""" # raise all underflow errors np.seterr(all="raise", under="ignore") diff --git a/tests/requirements.txt b/tests/requirements.txt index 013776c..8da3fa0 100644 --- a/tests/requirements.txt +++ b/tests/requirements.txt @@ -1,5 +1,6 @@ -r ../requirements.txt -black>=24.* +black>=24 +docformatter>=1.7 isort>=5.1 pyupgrade>=3 pytest>=5.4 diff --git a/tests/test_droplet_tracks.py b/tests/test_droplet_tracks.py index 128ba29..a958e19 100644 --- a/tests/test_droplet_tracks.py +++ b/tests/test_droplet_tracks.py @@ -14,7 +14,7 @@ def test_droplettrack(): - """test some droplet track functions""" + """Test some droplet track functions.""" t1 = DropletTrack() for i in range(4): t1.append(SphericalDroplet([i], i), i) @@ -44,7 +44,7 @@ def test_droplettrack(): @pytest.mark.skipif(not module_available("h5py"), reason="requires `h5py` module") def test_droplettrack_io(tmp_path): - """test writing and reading droplet tracks""" + """Test writing and reading droplet tracks.""" path = tmp_path / "test_droplettrack_io.hdf5" t1 = DropletTrack() @@ -60,7 +60,7 @@ def test_droplettrack_io(tmp_path): def test_droplettrack_plotting(): - """test writing and reading droplet tracks""" + """Test writing and reading droplet tracks.""" ds = [DiffuseDroplet([0, 1], 10, 0.5)] * 2 t = DropletTrack(droplets=ds, times=[0, 10]) t.plot("radius") @@ -70,7 +70,7 @@ def test_droplettrack_plotting(): def test_droplettracklist(): - """test droplet tracks""" + """Test droplet tracks.""" t1 = DropletTrack() ds = [DiffuseDroplet([0, 1], 10, 0.5)] * 2 t2 = DropletTrack(droplets=ds, times=[0, 10]) @@ -86,7 +86,7 @@ def test_droplettracklist(): @pytest.mark.skipif(not module_available("h5py"), reason="requires `h5py` module") def test_droplettracklist_io(tmp_path): - """test writing and reading droplet tracks""" + """Test writing and reading droplet tracks.""" path = tmp_path / "test_droplettracklist_io.hdf5" t1 = DropletTrack() @@ -100,7 +100,7 @@ def test_droplettracklist_io(tmp_path): def test_droplettracklist_plotting(): - """test plotting droplet tracks""" + """Test plotting droplet tracks.""" t1 = DropletTrack() ds = [DiffuseDroplet([0, 1], 10, 0.5)] * 2 t2 = DropletTrack(droplets=ds, times=[0, 10]) @@ -109,7 +109,7 @@ def test_droplettracklist_plotting(): def test_conversion_from_emulsion_timecourse(): - """test converting between DropletTrackList and EmulsionTimecourse""" + """Test converting between DropletTrackList and EmulsionTimecourse.""" d1 = SphericalDroplet([0, 1], 5) d2 = SphericalDroplet([10, 15], 4) times = [0, 10] diff --git a/tests/test_droplets.py b/tests/test_droplets.py index c935177..fe0d449 100644 --- a/tests/test_droplets.py +++ b/tests/test_droplets.py @@ -14,7 +14,7 @@ def test_simple_droplet(): - """test a given simple droplet""" + """Test a given simple droplet.""" d = droplets.SphericalDroplet((1, 2), 1) assert d.surface_area == pytest.approx(2 * np.pi) np.testing.assert_allclose(d.interface_position(0), [2, 2]) @@ -26,7 +26,7 @@ def test_simple_droplet(): @pytest.mark.parametrize("dim", [1, 2, 3]) def test_random_droplet(dim, rng): - """tests simple droplet""" + """Tests simple droplet.""" pos = rng.uniform(0, 10, dim) radius = rng.uniform(2, 3) d1 = droplets.SphericalDroplet(pos, radius) @@ -55,7 +55,7 @@ def test_random_droplet(dim, rng): def test_perturbed_droplet_2d(): - """test methods of perturbed droplets in 2d""" + """Test methods of perturbed droplets in 2d.""" d = droplets.PerturbedDroplet2D([0, 1], 1, 0.1, [0.0, 0.1, 0.2]) d.volume d.interface_distance(0.1) @@ -64,7 +64,7 @@ def test_perturbed_droplet_2d(): def test_perturbed_droplet_3d(): - """test methods of perturbed droplets in 3d""" + """Test methods of perturbed droplets in 3d.""" d = droplets.PerturbedDroplet3D([0, 1, 2], 1, 0.1, [0.0, 0.1, 0.2, 0.3]) d.volume_approx d.interface_distance(0.1, 0.2) @@ -73,7 +73,7 @@ def test_perturbed_droplet_3d(): def test_perturbed_droplet_3d_axis_sym(): - """test methods of axisymmetrically perturbed droplets in 3d""" + """Test methods of axisymmetrically perturbed droplets in 3d.""" d = droplets.PerturbedDroplet3DAxisSym([0, 0, 0], 1, 0.1, [0.0, 0.1]) d.volume_approx d.interface_distance(0.1) @@ -84,7 +84,7 @@ def test_perturbed_droplet_3d_axis_sym(): def test_perturbed_volume(rng): - """test volume calculation of perturbed droplets""" + """Test volume calculation of perturbed droplets.""" pos = rng.normal(size=2) radius = 1 + rng.random() amplitudes = rng.uniform(-0.2, 0.2, 6) @@ -108,7 +108,7 @@ def integrand(φ): def test_surface_area(rng): - """test surface area calculation of droplets""" + """Test surface area calculation of droplets.""" # perturbed 2d droplet R0 = 3 amplitudes = rng.uniform(-1e-2, 1e-2, 6) @@ -127,7 +127,7 @@ def test_surface_area(rng): def test_curvature(rng): - """test interface curvature calculation""" + """Test interface curvature calculation.""" # spherical droplet for dim in range(1, 4): d = droplets.SphericalDroplet(np.zeros(dim), radius=rng.uniform(1, 4)) @@ -139,7 +139,7 @@ def test_curvature(rng): amplitudes = epsilon * np.array([0.1, 0.2, 0.3, 0.4]) def curvature_analytical(φ): - """analytical expression for curvature""" + """Analytical expression for curvature.""" radius = ( 3.0 * ( @@ -195,7 +195,7 @@ def curvature_analytical(φ): def test_from_data(): - """test the from_data constructor""" + """Test the from_data constructor.""" for d1 in [ droplets.SphericalDroplet((1,), 2), droplets.SphericalDroplet((1, 2), 3), @@ -209,7 +209,7 @@ def test_from_data(): @pytest.mark.skipif(not module_available("h5py"), reason="requires `h5py` module") def test_triangulation_2d(): - """test the 2d triangulation of droplets""" + """Test the 2d triangulation of droplets.""" d1 = droplets.SphericalDroplet([1, 3], 5) d2 = droplets.PerturbedDroplet2D([2, 4], 5, amplitudes=[0.1, 0.2, 0.1, 0.2]) for drop in [d1, d2]: @@ -223,7 +223,7 @@ def test_triangulation_2d(): @pytest.mark.skipif(not module_available("h5py"), reason="requires `h5py` module") def test_triangulation_3d(): - """test the 3d triangulation of droplets""" + """Test the 3d triangulation of droplets.""" d1 = droplets.SphericalDroplet([1, 2, 3], 5) d2 = droplets.PerturbedDroplet3D([2, 3, 4], 5, amplitudes=[0.1, 0.2, 0.1, 0.2]) for drop in [d1, d2]: @@ -241,7 +241,7 @@ def test_triangulation_3d(): @pytest.mark.parametrize("cls", [droplets.SphericalDroplet, droplets.DiffuseDroplet]) @pytest.mark.parametrize("dim", [1, 2, 3]) def test_droplet_merge(cls, dim): - """test merging of droplets""" + """Test merging of droplets.""" if cls == droplets.SphericalDroplet: d1 = droplets.SphericalDroplet([0] * dim, 1) d2 = droplets.SphericalDroplet([2] * dim, 1) @@ -276,7 +276,7 @@ def test_droplet_merge(cls, dim): def test_droplet_interface_merge(): - """test merging of droplets with diffuse interfaces""" + """Test merging of droplets with diffuse interfaces.""" d1 = droplets.DiffuseDroplet([0, 0], 1, 1) d2 = droplets.DiffuseDroplet([2, 2], 1, 2) d1.merge(d2, inplace=True) diff --git a/tests/test_emulsion.py b/tests/test_emulsion.py index 96c2c90..75b057b 100644 --- a/tests/test_emulsion.py +++ b/tests/test_emulsion.py @@ -16,7 +16,7 @@ def test_empty_emulsion(caplog): - """test an emulsions without any droplets""" + """Test an emulsions without any droplets.""" caplog.set_level(logging.WARNING) e = Emulsion([]) @@ -78,7 +78,7 @@ def test_empty_emulsion(caplog): def test_emulsion_single(): - """test an emulsions with a single droplet""" + """Test an emulsions with a single droplet.""" e = Emulsion([]) e.append(DiffuseDroplet([10], 3, 1)) assert e @@ -102,7 +102,7 @@ def test_emulsion_single(): def test_emulsion_two(): - """test an emulsions with two droplets""" + """Test an emulsions with two droplets.""" e = Emulsion([DiffuseDroplet([10], 3, 1)]) e1 = Emulsion([DiffuseDroplet([20], 5, 1)]) e.extend(e1) @@ -129,7 +129,7 @@ def test_emulsion_two(): def test_emulsion_incompatible(): - """test incompatible droplets in an emulsion""" + """Test incompatible droplets in an emulsion.""" # different type d1 = SphericalDroplet([1], 2) d2 = DiffuseDroplet([1], 2, 1) @@ -148,7 +148,7 @@ def test_emulsion_incompatible(): def test_emulsion_linked_data(): - """test whether emulsions link the data to droplets correctly""" + """Test whether emulsions link the data to droplets correctly.""" d1 = SphericalDroplet([0, 0], 1) d2 = SphericalDroplet([1, 2], 3) e = Emulsion([d1, d2]) @@ -165,7 +165,7 @@ def test_emulsion_linked_data(): @pytest.mark.skipif(not module_available("h5py"), reason="requires `h5py` module") def test_emulsion_io(tmp_path): - """test writing and reading emulsions""" + """Test writing and reading emulsions.""" path = tmp_path / "test_emulsion_io.hdf5" drop_diff = DiffuseDroplet([0, 1], 10, 0.5) @@ -184,7 +184,7 @@ def test_emulsion_io(tmp_path): def test_timecourse(): - """test some droplet track functions""" + """Test some droplet track functions.""" t1 = emulsions.EmulsionTimeCourse() for i in range(4): d = droplets.SphericalDroplet([i], i) @@ -208,7 +208,7 @@ def test_timecourse(): @pytest.mark.skipif(not module_available("h5py"), reason="requires `h5py` module") def test_timecourse_io(tmp_path): - """test writing and reading emulsions time courses""" + """Test writing and reading emulsions time courses.""" path = tmp_path / "test_timecourse_io.hdf5" e1 = Emulsion() @@ -223,7 +223,7 @@ def test_timecourse_io(tmp_path): def test_emulsion_plotting(): - """test plotting emulsions""" + """Test plotting emulsions.""" # 1d emulsion e1 = Emulsion([DiffuseDroplet([1], 10, 0.5)] * 2) with pytest.raises(NotImplementedError): @@ -256,7 +256,7 @@ def test_emulsion_plotting(): def test_remove_overlapping(): - """test that removing overlapping droplets works""" + """Test that removing overlapping droplets works.""" e = Emulsion([SphericalDroplet([0, 1], 2), SphericalDroplet([1, 1], 2)]) assert len(e) == 2 e.remove_overlapping() @@ -265,7 +265,7 @@ def test_remove_overlapping(): @pytest.mark.parametrize("modify_data", [True, False]) def test_emulsion_merge(modify_data): - """test merging of droplets""" + """Test merging of droplets.""" em = Emulsion([DiffuseDroplet([0], 1, 1)] * 5, copy=True) drop_data = em.get_linked_data() for i in range(1, len(em)): @@ -284,7 +284,7 @@ def test_emulsion_merge(modify_data): @pytest.mark.parametrize("dim", [1, 2, 3]) @pytest.mark.parametrize("grid", [True, False]) def test_emulsion_random(dim, grid, rng): - """create random emulsions""" + """Create random emulsions.""" if grid: bounds = CartesianGrid([(10, 30)] * dim, 1) else: @@ -298,7 +298,7 @@ def test_emulsion_random(dim, grid, rng): @pytest.mark.parametrize("proc", [1, 2]) def test_emulsion_from_storage(proc): - """test reading emulsion time courses from a file""" + """Test reading emulsion time courses from a file.""" grid = UnitGrid([32, 32]) radii = [3, 2.7, 4.3] pos = [[7, 8], [9, 22], [22, 10]] diff --git a/tests/test_examples.py b/tests/test_examples.py index 908c38b..303c7d6 100644 --- a/tests/test_examples.py +++ b/tests/test_examples.py @@ -23,7 +23,7 @@ @pytest.mark.skipif(sys.platform == "win32", reason="Assumes unix setup") @pytest.mark.parametrize("path", EXAMPLES) def test_example(path): - """runs an example script given by path""" + """Runs an example script given by path.""" if path.name.startswith("_"): pytest.skip("skip examples starting with an underscore") if any(name in str(path) for name in SKIP_EXAMPLES): diff --git a/tests/test_image_analysis.py b/tests/test_image_analysis.py index 62017cf..15a085a 100644 --- a/tests/test_image_analysis.py +++ b/tests/test_image_analysis.py @@ -28,7 +28,7 @@ @pytest.mark.parametrize("size", [16, 17]) @pytest.mark.parametrize("periodic", [True, False]) def test_localization_sym_unit(size, periodic, rng): - """tests simple droplets localization in 2d""" + """Tests simple droplets localization in 2d.""" pos = rng.random(2) * size radius = rng.uniform(2, 5) width = rng.uniform(1, 2) @@ -54,7 +54,7 @@ def test_localization_sym_unit(size, periodic, rng): @pytest.mark.parametrize("periodic", [True, False]) def test_localization_sym_rect(periodic, rng): - """tests simple droplets localization in 2d with a rectangular grid""" + """Tests simple droplets localization in 2d with a rectangular grid.""" size = 16 pos = rng.uniform(-4, 4, size=2) @@ -81,7 +81,7 @@ def test_localization_sym_rect(periodic, rng): @pytest.mark.parametrize("periodic", [True, False]) def test_localization_perturbed_2d(periodic, rng): - """tests localization of perturbed 2d droplets""" + """Tests localization of perturbed 2d droplets.""" size = 16 pos = rng.uniform(-4, 4, size=2) @@ -108,7 +108,7 @@ def test_localization_perturbed_2d(periodic, rng): @pytest.mark.parametrize("periodic", [True, False]) def test_localization_perturbed_3d(periodic, rng): - """tests localization of perturbed 3d droplets""" + """Tests localization of perturbed 3d droplets.""" size = 8 pos = rng.uniform(-2, 2, size=3) @@ -139,7 +139,7 @@ def test_localization_perturbed_3d(periodic, rng): def test_localization_polar(rng): - """tests simple droplets localization in polar grid""" + """Tests simple droplets localization in polar grid.""" radius = rng.uniform(2, 3) width = rng.uniform(0.5, 1.5) d1 = DiffuseDroplet((0, 0), radius, interface_width=width) @@ -161,7 +161,7 @@ def test_localization_polar(rng): def test_localization_spherical(rng): - """tests simple droplets localization in spherical grid""" + """Tests simple droplets localization in spherical grid.""" radius = rng.uniform(2, 3) width = rng.uniform(0.5, 1.5) d1 = DiffuseDroplet((0, 0, 0), radius, interface_width=width) @@ -184,7 +184,7 @@ def test_localization_spherical(rng): @pytest.mark.parametrize("periodic", [True, False]) def test_localization_cylindrical(periodic, rng): - """tests simple droplets localization in cylindrical grid""" + """Tests simple droplets localization in cylindrical grid.""" pos = (0, 0, rng.uniform(-4, 4)) radius = rng.uniform(2, 3) width = rng.uniform(0.5, 1.5) @@ -208,7 +208,7 @@ def test_localization_cylindrical(periodic, rng): def test_localization_threshold(rng): - """tests different localization thresholds""" + """Tests different localization thresholds.""" pos = rng.random(2) * 16 radius = rng.uniform(2, 5) width = rng.uniform(1, 2) @@ -233,7 +233,7 @@ def test_localization_threshold(rng): "adjust_values, auto_values", [(False, False), (True, False), (True, True)] ) def test_localization_vmin_vmax(adjust_values, auto_values): - """tests localization of droplets with non-normalized densities""" + """Tests localization of droplets with non-normalized densities.""" # create perturbed droplet grid = CartesianGrid(bounds=[[-2, 2], [-2, 2]], shape=32, periodic=True) d1 = DiffuseDroplet([0, 0], 1, 0.2) @@ -255,7 +255,7 @@ def test_localization_vmin_vmax(adjust_values, auto_values): def test_get_structure_factor(rng): - """test the structure factor method""" + """Test the structure factor method.""" grid = UnitGrid([512], periodic=True) k0 = rng.uniform(1, 3) field = ScalarField.from_expression(grid, f"sin({k0} * x)") @@ -273,7 +273,7 @@ def test_get_structure_factor(rng): ], ) def test_get_length_scale(method): - """test determining the length scale""" + """Test determining the length scale.""" grid = CartesianGrid([[0, 8 * np.pi]], 64, periodic=True) c = ScalarField.from_expression(grid, "sin(x)") s = image_analysis.get_length_scale(c, method=method) @@ -281,7 +281,7 @@ def test_get_length_scale(method): def test_get_length_scale_edge(): - """test determining the length scale for edge cases""" + """Test determining the length scale for edge cases.""" grid = CartesianGrid(bounds=[[0, 1]], shape=32, periodic=True) for n in range(1, 4): c = ScalarField.from_expression(grid, f"0.2 + 0.2*sin(2*{n}*pi*x)") @@ -290,7 +290,7 @@ def test_get_length_scale_edge(): def test_emulsion_processing(): - """test identifying emulsions in phase fields""" + """Test identifying emulsions in phase fields.""" e1 = Emulsion( [ DiffuseDroplet(position=[5, 6], radius=9, interface_width=1), @@ -311,7 +311,7 @@ def test_emulsion_processing(): def test_structure_factor_random(): - """test the structure factor function for random input""" + """Test the structure factor function for random input.""" g1 = CartesianGrid([[0, 10]] * 2, 64, periodic=True) f1 = ScalarField.random_colored(g1, -2) @@ -341,7 +341,7 @@ def test_structure_factor_random(): ], ) def test_locating_stripes(grid): - """check whether the locate_droplets function can deal with stripe morphologies""" + """Check whether the locate_droplets function can deal with stripe morphologies.""" field = ScalarField(grid, 1) em = image_analysis.locate_droplets(field) assert len(em) == 1 @@ -351,7 +351,7 @@ def test_locating_stripes(grid): @pytest.mark.parametrize("dim", [1, 2, 3]) @pytest.mark.parametrize("pos", [0.5, 1.5, 3, 5.5, 6.5]) def test_droplets_on_periodic_grids(dim, pos): - """check whether the locate_droplets function can deal with periodic BCs""" + """Check whether the locate_droplets function can deal with periodic BCs.""" grid = UnitGrid([7] * dim, periodic=True) field = SphericalDroplet([pos] * dim, 3).get_phase_field(grid) em = image_analysis.locate_droplets(field) @@ -362,7 +362,7 @@ def test_droplets_on_periodic_grids(dim, pos): @pytest.mark.parametrize("num_processes", [1, 2]) def test_droplet_refine_parallel(num_processes): - """tests droplets localization in 2d with and without multiprocessing""" + """Tests droplets localization in 2d with and without multiprocessing.""" grid = UnitGrid([32, 32]) radii = [3, 2.7, 4.3] pos = [[7, 8], [9, 22], [22, 10]] diff --git a/tests/test_spherical.py b/tests/test_spherical.py index 310593e..b0e0c10 100644 --- a/tests/test_spherical.py +++ b/tests/test_spherical.py @@ -17,7 +17,7 @@ @pytest.mark.parametrize("dim", [1, 2, 3]) def test_volume_conversion(dim): - """tests conversion of volume and radius of droplet""" + """Tests conversion of volume and radius of droplet.""" radius = 1 + random.random() volume = spherical.volume_from_radius(radius, dim=dim) radius2 = spherical.radius_from_volume(volume, dim=dim) @@ -36,7 +36,7 @@ def test_volume_conversion(dim): @pytest.mark.parametrize("dim", [1, 2, 3]) def test_surface(dim): - """test whether the surface is calculated correctly""" + """Test whether the surface is calculated correctly.""" radius = 1 + random.random() eps = 1e-10 vol1 = spherical.volume_from_radius(radius + eps, dim=dim) @@ -58,7 +58,7 @@ def test_surface(dim): def test_spherical_conversion(rng): - """test the conversion between spherical and Cartesian coordinates""" + """Test the conversion between spherical and Cartesian coordinates.""" s2c = spherical.points_spherical_to_cartesian c2s = spherical.points_cartesian_to_spherical @@ -73,7 +73,7 @@ def test_spherical_conversion(rng): def test_spherical_index(): - """test the conversion of the spherical index""" + """Test the conversion of the spherical index.""" # check initial state assert spherical.spherical_index_lm(0) == (0, 0) assert spherical.spherical_index_k(0, 0) == 0 @@ -102,7 +102,7 @@ def test_spherical_index(): def test_spherical_harmonics_real(): - """test spherical harmonics""" + """Test spherical harmonics.""" # test real spherical harmonics for symmetric case for deg in range(4): for _ in range(5): @@ -131,7 +131,7 @@ def integrand(t, p): def test_polar_coordinates_1d(): - """test polar_coordinates function in 1d""" + """Test polar_coordinates function in 1d.""" grid = pde.UnitGrid([2]) p1, a1 = spherical.polar_coordinates(grid, ret_angle=True) p2 = grid.c.pos_from_cart(grid.cell_coords) @@ -140,7 +140,7 @@ def test_polar_coordinates_1d(): def test_polar_coordinates_2d(): - """test polar_coordinates function in 2d""" + """Test polar_coordinates function in 2d.""" grid = pde.UnitGrid([2, 2]) grid_sph = pde.PolarSymGrid(5, 1) p1 = spherical.polar_coordinates(grid, ret_angle=True) @@ -149,7 +149,7 @@ def test_polar_coordinates_2d(): def test_polar_coordinates_3d(): - """test polar_coordinates function in 3d""" + """Test polar_coordinates function in 3d.""" grid = pde.UnitGrid([2, 2, 2]) p1 = spherical.polar_coordinates(grid, ret_angle=True) p2 = spherical.points_cartesian_to_spherical(grid.cell_coords) diff --git a/tests/test_trackers.py b/tests/test_trackers.py index 9350975..5c5d67a 100644 --- a/tests/test_trackers.py +++ b/tests/test_trackers.py @@ -14,7 +14,7 @@ @pytest.mark.skipif(not module_available("h5py"), reason="requires `h5py` module") def test_emulsion_tracker(tmp_path): - """test using the emulsions tracker""" + """Test using the emulsions tracker.""" path = tmp_path / "test_emulsion_tracker.hdf5" d = SphericalDroplet([4, 4], 3) @@ -34,7 +34,7 @@ def test_emulsion_tracker(tmp_path): def test_length_scale_tracker(tmp_path): - """test the length scale tracker""" + """Test the length scale tracker.""" path = tmp_path / "test_length_scale_tracker.json" grid = CartesianGrid([[0, 10 * np.pi]], 64, periodic=True)