Skip to content

Commit

Permalink
Adjusted to latest changes in py-pde
Browse files Browse the repository at this point in the history
* Bumped py-pde required version to 0.35
* Removed the dependence on `grid.distance_real` and
`grid.polar_coordinates_real`
  • Loading branch information
david-zwicker committed Jan 9, 2024
1 parent 9758bab commit 3f08aeb
Show file tree
Hide file tree
Showing 7 changed files with 93 additions and 15 deletions.
2 changes: 1 addition & 1 deletion docs/source/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ matplotlib >=3.1.0 Visualizing results
numpy >=1.22 Array library used for storing data
numba >=0.48 Just-in-time compilation to accelerate numerics
scipy >=1.4 Miscellaneous scientific functions
py-pde >=0.34 Simulating partial differential equations
py-pde >=0.35 Simulating partial differential equations
=========== ========= =========

These package can be installed via your operating system's package manager, e.g.
Expand Down
6 changes: 3 additions & 3 deletions droplets/droplet_tracks.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@
DropletTrack
DropletTrackList
.. codeauthor:: David Zwicker <david.zwicker@ds.mpg.de>
"""

from __future__ import annotations

import functools
import json
import logging
from typing import Callable, Literal
Expand Down Expand Up @@ -448,7 +448,7 @@ def plot_positions(
segments = []
for p1, p2 in zip(xy[:-1], xy[1:]):
dist_direct = np.hypot(p1[0] - p2[0], p1[1] - p2[1])
dist_real = grid.distance_real(p1, p2)
dist_real = grid.distance(p1, p2, coords="cartesian")
close = np.isclose(dist_direct, dist_real)
segments.append(close)

Expand Down Expand Up @@ -568,7 +568,7 @@ def match_tracks(
if grid is None:
metric: str | Callable = "euclidean"
else:
metric = grid.distance_real
metric = functools.partial(grid.distance, coords="cartesian")

Check warning on line 571 in droplets/droplet_tracks.py

View check run for this annotation

Codecov / codecov/patch

droplets/droplet_tracks.py#L571

Added line #L571 was not covered by tests
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)
Expand Down
85 changes: 78 additions & 7 deletions droplets/droplets.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
import warnings
from abc import ABCMeta, abstractmethod
from pathlib import Path
from typing import Any, Callable, List, Tuple, Type, TypeVar, Union
from typing import Any, Callable, List, Literal, Tuple, Type, TypeVar, Union, overload

import numpy as np
from numba.extending import register_jitable
Expand All @@ -41,7 +41,7 @@
from scipy import integrate

from pde.fields import ScalarField
from pde.grids.base import GridBase
from pde.grids.base import DimensionError, GridBase
from pde.tools.cuboid import Cuboid
from pde.tools.misc import preserve_scalars
from pde.tools.plotting import PlotReference, plot_on_axes
Expand Down Expand Up @@ -96,6 +96,77 @@ def iterate_in_pairs(it, fill=0):
break


@overload
def polar_coordinates(
grid: GridBase,
*,
origin: np.ndarray | None = None,
ret_angle: Literal[False] = False,
) -> np.ndarray:
...

Check warning on line 106 in droplets/droplets.py

View check run for this annotation

Codecov / codecov/patch

droplets/droplets.py#L106

Added line #L106 was not covered by tests


@overload
def polar_coordinates(
grid: GridBase, *, origin: np.ndarray | None = None, ret_angle: Literal[True]
) -> tuple[np.ndarray, ...]:
...

Check warning on line 113 in droplets/droplets.py

View check run for this annotation

Codecov / codecov/patch

droplets/droplets.py#L113

Added line #L113 was not covered by tests


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
Args:
grid (:class:`~pde.grids.base.GridBase`):
The grid whose cell coordinates are used.
origin (:class:`~numpy.ndarray`, optional):
Cartesian coordinates of the origin at which polar coordinates are anchored.
ret_angle (bool):
Determines whether angles are returned alongside the distance. If `False`
only the distance to the origin is returned for each support point of the
grid. If `True`, the distance and angles are returned. For a 1d system
system, the angle is defined as the sign of the difference between the
point and the origin, so that angles can either be 1 or -1. For 2d
systems and 3d systems, polar coordinates and spherical coordinates are
used, respectively.
Returns:
:class:`~numpy.ndarray` or tuple of :class:`~numpy.ndarray`:
Coordinates values in polar coordinates
"""
if origin is None:
origin = np.zeros(grid.dim)

Check warning on line 140 in droplets/droplets.py

View check run for this annotation

Codecov / codecov/patch

droplets/droplets.py#L140

Added line #L140 was not covered by tests
else:
origin = np.asarray(origin, dtype=float)
if origin.shape != (grid.dim,):
raise DimensionError("Dimensions are not compatible")

Check warning on line 144 in droplets/droplets.py

View check run for this annotation

Codecov / codecov/patch

droplets/droplets.py#L144

Added line #L144 was not covered by tests

# calculate the difference vector between all cells and the origin
origin_grid = grid.transform(origin, source="cartesian", target="grid")
diff = grid.difference_vector(grid.cell_coords, origin_grid)
dist: np.ndarray = np.linalg.norm(diff, axis=-1) # get distance

# determine distance and optionally angles for these vectors
if not ret_angle:
return dist

elif grid.dim == 1:
return dist, np.sign(diff)[..., 0]

Check warning on line 156 in droplets/droplets.py

View check run for this annotation

Codecov / codecov/patch

droplets/droplets.py#L156

Added line #L156 was not covered by tests

elif grid.dim == 2:
return dist, np.arctan2(diff[..., 0], diff[..., 1])

elif grid.dim == 3:
theta = np.arccos(diff[..., 2] / dist)
phi = np.arctan2(diff[..., 0], diff[..., 1])
return dist, theta, phi

else:
raise NotImplementedError(f"Cannot calculate angles for dimension {grid.dim}")

Check warning on line 167 in droplets/droplets.py

View check run for this annotation

Codecov / codecov/patch

droplets/droplets.py#L167

Added line #L167 was not covered by tests


class DropletBase:
"""represents a generic droplet
Expand Down Expand Up @@ -376,7 +447,7 @@ def overlaps(self, other: SphericalDroplet, grid: GridBase | None = None) -> boo
if grid is None:
distance = float(np.linalg.norm(self.position - other.position))
else:
distance = grid.distance_real(self.position, other.position)
distance = grid.distance(self.position, other.position, coords="cartesian")

Check warning on line 450 in droplets/droplets.py

View check run for this annotation

Codecov / codecov/patch

droplets/droplets.py#L450

Added line #L450 was not covered by tests
return distance < self.radius + other.radius

@classmethod
Expand Down Expand Up @@ -464,8 +535,8 @@ def _get_phase_field(self, grid: GridBase, dtype: DTypeLike = float) -> np.ndarr
)

# calculate distances from droplet center
dist = grid.polar_coordinates_real(self.position)
return (dist < self.radius).astype(dtype) # type: ignore
dist = polar_coordinates(grid, origin=self.position, ret_angle=False)
return (dist < self.radius).astype(dtype)

def get_phase_field(
self,
Expand Down Expand Up @@ -692,7 +763,7 @@ def _get_phase_field(self, grid: GridBase, dtype: DTypeLike = float) -> np.ndarr
interface_width = self.interface_width

# calculate distances from droplet center
dist: np.ndarray = grid.polar_coordinates_real(self.position, ret_angle=False) # type: ignore
dist = polar_coordinates(grid, origin=self.position, ret_angle=False)

# make the image
if interface_width == 0 or np.issubdtype(dtype, bool):
Expand Down Expand Up @@ -838,7 +909,7 @@ def _get_phase_field(self, grid: GridBase, dtype: DTypeLike = float) -> np.ndarr
interface_width = self.interface_width

# calculate grid distance from droplet center
dist, *angles = grid.polar_coordinates_real(self.position, ret_angle=True)
dist, *angles = polar_coordinates(grid, origin=self.position, ret_angle=True)

# calculate interface distance from droplet center
interface = self.interface_distance(*angles)
Expand Down
2 changes: 1 addition & 1 deletion droplets/emulsions.py
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,7 @@ def get_distance(p1, p2):
return np.linalg.norm(p1 - p2)

else:
get_distance = grid.distance_real
get_distance = functools.partial(grid.distance, coords="cartesian")

# calculate pairwise distance and return it in requested form
num = len(self)
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ dependencies = [
"numpy>=1.22.0",
"scipy>=1.4.0",
"sympy>=1.5.0",
"py-pde>=0.34",
"py-pde>=0.35",
]

[project.optional-dependencies]
Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ matplotlib>=3.1.0
numpy>=1.22.0
numba>=0.48.0
scipy>=1.4.0
py-pde>=0.34
py-pde>=0.35
9 changes: 8 additions & 1 deletion scripts/run_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,14 @@ def run_unit_tests(
args.append("tests")

# actually run the test
return sp.run(args, env=env, cwd=PACKAGE_PATH).returncode
retcode = sp.run(args, env=env, cwd=PACKAGE_PATH).returncode

# delete intermediate coverage files, which are sometimes left behind
if coverage:
for p in Path("..").glob(".coverage*"):
p.unlink()

return retcode


def main() -> int:
Expand Down

0 comments on commit 3f08aeb

Please sign in to comment.