Python package for solving partial differential equations with a focus on ease of use and performance
—
Grid classes define spatial domains with coordinate systems and discretization for solving PDEs. py-pde supports regular orthogonal grids in various coordinate systems including Cartesian, polar, spherical, and cylindrical.
Simple unit grid in Cartesian coordinates, suitable for quick prototyping and testing.
class UnitGrid:
def __init__(self, shape, periodic=True):
"""
Initialize unit grid with domain [0, 1]^dim.
Parameters:
- shape: int or sequence of ints, number of grid points per axis
- periodic: bool or sequence of bools, periodicity per axis
"""
@classmethod
def from_state(cls, state):
"""
Create grid from serialized state.
Parameters:
- state: dict, serialized grid state
Returns:
UnitGrid reconstructed from state
"""
@property
def dim(self):
"""int: Number of spatial dimensions"""
@property
def shape(self):
"""tuple: Number of grid points per axis"""
@property
def periodic(self):
"""list of bool: Periodicity per axis"""
@property
def volume(self):
"""float: Total volume of the grid"""
def get_line_data(self, data, *, extract="auto"):
"""
Extract line data for 1D plotting.
Parameters:
- data: array-like, field data on grid
- extract: extraction method
Returns:
dict with 'x' and 'data' arrays
"""
def to_cartesian(self):
"""
Convert to equivalent CartesianGrid.
Returns:
CartesianGrid with same discretization
"""
def slice(self, indices):
"""
Create subgrid by slicing.
Parameters:
- indices: slice indices for each axis
Returns:
UnitGrid containing the slice
"""Cartesian grid with customizable domain bounds and discretization.
class CartesianGrid:
def __init__(self, bounds, shape, periodic=False):
"""
Initialize Cartesian grid.
Parameters:
- bounds: sequence of [min, max] pairs for each axis
- shape: int or sequence of ints, number of grid points per axis
- periodic: bool or sequence of bools, periodicity per axis
"""
@classmethod
def from_state(cls, state):
"""
Create grid from serialized state.
Parameters:
- state: dict, serialized grid state
Returns:
CartesianGrid reconstructed from state
"""
@classmethod
def from_bounds(cls, bounds, shape, periodic=False):
"""
Create grid from bounds specification.
Parameters:
- bounds: sequence of [min, max] pairs for each axis
- shape: int or sequence of ints, number of grid points per axis
- periodic: bool or sequence of bools, periodicity per axis
Returns:
CartesianGrid with specified bounds
"""
@property
def bounds(self):
"""list: Domain bounds [[xmin, xmax], [ymin, ymax], ...]"""
@property
def discretization(self):
"""np.ndarray: Grid spacing per axis"""
@property
def axes_bounds(self):
"""list: Bounds for each axis"""
def get_image_data(self, data, **kwargs):
"""
Prepare data for image visualization.
Parameters:
- data: array-like, field data on grid
- kwargs: additional visualization parameters
Returns:
dict with image data and extent information
"""
def cell_to_point(self, cells, *, cartesian=True):
"""
Convert cell indices to coordinate points.
Parameters:
- cells: array-like, cell indices
- cartesian: bool, return Cartesian coordinates
Returns:
np.ndarray: Coordinate points
"""
def point_to_cell(self, points):
"""
Convert coordinate points to cell indices.
Parameters:
- points: array-like, coordinate points
Returns:
np.ndarray: Cell indices
"""
@property
def cell_volume_data(self):
"""np.ndarray: Volume of each grid cell"""
def iter_mirror_points(self, point, num_axes=None):
"""
Iterate over mirror points considering periodicity.
Parameters:
- point: array-like, reference point
- num_axes: int, number of axes to consider
Yields:
np.ndarray: Mirror points
"""
def get_random_point(self, boundary_distance=0, coords='grid', rng=None):
"""
Generate random point within grid domain.
Parameters:
- boundary_distance: float, minimum distance from boundaries
- coords: str, coordinate system ('grid' or 'cartesian')
- rng: random number generator
Returns:
np.ndarray: Random point coordinates
"""
def difference_vector(self, p1, p2, coords='grid'):
"""
Calculate difference vector between two points.
Parameters:
- p1: array-like, first point
- p2: array-like, second point
- coords: str, coordinate system
Returns:
np.ndarray: Difference vector
"""
def get_vector_data(self, data, **kwargs):
"""
Prepare vector data for visualization.
Parameters:
- data: array-like, vector field data
- kwargs: additional visualization parameters
Returns:
dict: Vector visualization data
"""
def plot(self, ax, **kwargs):
"""
Plot the grid structure.
Parameters:
- ax: matplotlib axes object
- kwargs: plotting parameters
"""
def slice(self, indices):
"""
Create subgrid by slicing.
Parameters:
- indices: slice indices for each axis
Returns:
CartesianGrid containing the slice
"""Polar grid with angular symmetry for 2D problems with radial symmetry.
class PolarSymGrid:
def __init__(self, radius, shape, periodic=True):
"""
Initialize polar symmetric grid.
Parameters:
- radius: float or [r_min, r_max], radial domain
- shape: int, number of radial grid points
- periodic: bool, periodicity in angular direction
"""
@property
def radius(self):
"""float: Maximum radius of the grid"""
@property
def axes_bounds(self):
"""list: Radial bounds [r_min, r_max]"""
def transform(self, coordinates, *, with_jacobian=False):
"""
Transform between coordinate systems.
Parameters:
- coordinates: array-like, coordinates to transform
- with_jacobian: bool, whether to return Jacobian
Returns:
np.ndarray or tuple: Transformed coordinates (and Jacobian)
"""
@classmethod
def from_state(cls, state):
"""
Create grid from serialized state.
Parameters:
- state: dict, serialized grid state
Returns:
PolarSymGrid reconstructed from state
"""Spherical grid with full spherical symmetry for 3D radially symmetric problems.
class SphericalSymGrid:
def __init__(self, radius, shape):
"""
Initialize spherical symmetric grid.
Parameters:
- radius: float or [r_min, r_max], radial domain
- shape: int, number of radial grid points
"""
@property
def coordinate_constraints(self):
"""list: Constraints on coordinate values"""
def get_cartesian_grid(self):
"""
Get equivalent Cartesian grid for visualization.
Returns:
CartesianGrid: Corresponding Cartesian grid
"""
@classmethod
def from_state(cls, state):
"""
Create grid from serialized state.
Parameters:
- state: dict, serialized grid state
Returns:
SphericalSymGrid reconstructed from state
"""Cylindrical grid with symmetry in angular direction for problems with cylindrical geometry.
class CylindricalSymGrid:
def __init__(self, radius, bounds, shape, periodic_z=True):
"""
Initialize cylindrical symmetric grid.
Parameters:
- radius: float or [r_min, r_max], radial domain
- bounds: [z_min, z_max], axial domain bounds
- shape: [r_points, z_points], grid points per axis
- periodic_z: bool, periodicity in z-direction
"""
@property
def typical_discretization(self):
"""np.ndarray: Typical grid spacing"""
def make_operator_list(self, operator_type):
"""
Create list of differential operators.
Parameters:
- operator_type: str, type of operator
Returns:
list: Differential operators for this grid
"""
@classmethod
def from_state(cls, state):
"""
Create grid from serialized state.
Parameters:
- state: dict, serialized grid state
Returns:
CylindricalSymGrid reconstructed from state
"""Common functionality shared by all grid types.
class GridBase:
@property
def coordinate_constraints(self):
"""list: Constraints on coordinate values"""
@property
def cell_volume_data(self):
"""np.ndarray: Volume of each grid cell"""
def iter_mirror_points(self, point, with_self=True):
"""
Iterate over mirror points considering periodicity.
Parameters:
- point: array-like, reference point
- with_self: bool, include the original point
Yields:
np.ndarray: Mirror points
"""
def normalize_point(self, point, *, reflect=True):
"""
Normalize point to grid domain.
Parameters:
- point: array-like, point to normalize
- reflect: bool, apply reflection at boundaries
Returns:
np.ndarray: Normalized point
"""
def contains_point(self, point):
"""
Check if point is inside grid domain.
Parameters:
- point: array-like, point to check
Returns:
bool: True if point is inside domain
"""
@property
def state(self):
"""dict: Serializable state of the grid"""
@property
def size(self):
"""int: Total number of grid points"""
@property
def ndim(self):
"""int: Number of spatial dimensions"""
def copy(self):
"""
Create a copy of the grid.
Returns:
GridBase: Copy of the grid
"""
def get_boundary_conditions(self, bc, rank=0):
"""
Process boundary condition specification.
Parameters:
- bc: boundary condition specification
- rank: int, tensor rank of the field
Returns:
Processed boundary conditions
"""
def make_operator(self, operator, bc, *, backend='auto'):
"""
Create differential operator for this grid.
Parameters:
- operator: str, operator name ('laplace', 'gradient', etc.)
- bc: boundary conditions
- backend: str, computational backend
Returns:
Callable differential operator
"""import pde
# Simple unit grid for prototyping
unit_grid = pde.UnitGrid([64, 64], periodic=[True, False])
# Cartesian grid with custom bounds
cart_grid = pde.CartesianGrid([[-5, 5], [0, 10]], [32, 64])
# Polar grid for radially symmetric problems
polar_grid = pde.PolarSymGrid(radius=5.0, shape=64)
# Cylindrical grid
cyl_grid = pde.CylindricalSymGrid(
radius=[0, 3], bounds=[-10, 10], shape=[32, 64]
)
print(f"Unit grid volume: {unit_grid.volume}")
print(f"Cartesian grid discretization: {cart_grid.discretization}")
print(f"Polar grid radius: {polar_grid.radius}")import pde
import numpy as np
# Create 2D Cartesian grid
grid = pde.CartesianGrid([[-2, 2], [-1, 1]], [32, 16])
# Convert between cell indices and coordinates
cell_indices = np.array([[15, 8], [20, 12]])
coordinates = grid.cell_to_point(cell_indices)
back_to_cells = grid.point_to_cell(coordinates)
print(f"Cell indices: {cell_indices}")
print(f"Coordinates: {coordinates}")
print(f"Back to cells: {back_to_cells}")
# Check if points are inside domain
test_points = np.array([[0, 0], [3, 0], [-1.5, 0.8]])
inside = [grid.contains_point(p) for p in test_points]
print(f"Points inside domain: {inside}")Install with Tessl CLI
npx tessl i tessl/pypi-py-pde