Python package for solving partial differential equations with a focus on ease of use and performance
—
Solver classes provide time integration algorithms for evolving PDE systems with adaptive time stepping, stability control, and parallel computing support through MPI.
High-level solver controller that manages time integration with automatic solver selection and progress tracking.
class Controller:
def __init__(self, sol_class, *, t_range, tracker=None):
"""
Initialize solver controller.
Parameters:
- sol_class: SolverBase class or instance, time integration solver
- t_range: float or array-like, time integration range
- tracker: TrackerBase or list, progress tracking
"""
def run(self, initial_state, dt=None, **kwargs):
"""
Run the simulation.
Parameters:
- initial_state: FieldBase, initial field configuration
- dt: float, time step (auto-determined if None)
- kwargs: additional solver parameters
Returns:
FieldBase: Final field state
"""
@property
def solver(self):
"""SolverBase: The underlying solver instance"""
@property
def tracker(self):
"""TrackerCollection: Collection of trackers"""Explicit time stepping methods with adaptive time step control.
class ExplicitSolver:
def __init__(self, pde, scheme="euler", *, backend="auto", adaptive=False, tolerance=1e-4):
"""
Initialize explicit solver.
Parameters:
- pde: PDEBase, the PDE to solve
- scheme: str, integration scheme ("euler", "runge-kutta", "rk", "rk45")
- backend: str, computation backend ("auto", "numpy", "numba")
- adaptive: bool, enable adaptive time stepping
- tolerance: float, error tolerance for adaptive stepping
"""
def make_stepper(self, state, dt):
"""
Create compiled stepper function.
Parameters:
- state: FieldBase, example state for compilation
- dt: float, time step
Returns:
Callable: Compiled stepper function
"""
@property
def pde(self):
"""PDEBase: The PDE being solved"""
@property
def info(self):
"""dict: Solver information and statistics"""Implicit time stepping methods for stiff PDEs requiring large time steps.
class ImplicitSolver:
def __init__(self, pde, *, scheme="backward_euler"):
"""
Initialize implicit solver.
Parameters:
- pde: PDEBase, the PDE to solve
- scheme: str, integration scheme ("backward_euler")
"""
def solve_newton(self, state, dt, *, newton_options=None):
"""
Solve nonlinear system using Newton's method.
Parameters:
- state: FieldBase, current state
- dt: float, time step
- newton_options: dict, Newton solver options
Returns:
FieldBase: Updated state
"""Crank-Nicolson scheme providing second-order accuracy in time.
class CrankNicolsonSolver:
def __init__(self, pde):
"""
Initialize Crank-Nicolson solver for linear PDEs.
Parameters:
- pde: PDEBase, the PDE to solve (must be linear)
"""
def make_stepper(self, state, dt):
"""
Create stepper for Crank-Nicolson scheme.
Parameters:
- state: FieldBase, example state
- dt: float, time step
Returns:
Callable: Stepper function
"""Adams-Bashforth multi-step method with higher-order accuracy.
class AdamsBashforthSolver:
def __init__(self, pde, *, order=2):
"""
Initialize Adams-Bashforth solver.
Parameters:
- pde: PDEBase, the PDE to solve
- order: int, order of the method (1-4)
"""
@property
def order(self):
"""int: Order of the Adams-Bashforth method"""
def make_stepper(self, state, dt):
"""
Create multi-step stepper function.
Parameters:
- state: FieldBase, example state
- dt: float, time step
Returns:
Callable: Multi-step stepper function
"""Interface to SciPy's ODE integration methods with automatic stiffness detection.
class ScipySolver:
def __init__(self, pde, *, method="RK45"):
"""
Initialize SciPy solver wrapper.
Parameters:
- pde: PDEBase, the PDE to solve
- method: str, SciPy integration method
("RK45", "RK23", "DOP853", "Radau", "BDF", "LSODA")
"""
@property
def method(self):
"""str: SciPy integration method being used"""
def solve(self, initial_state, t_span, **kwargs):
"""
Solve using SciPy integration.
Parameters:
- initial_state: FieldBase, initial condition
- t_span: tuple, (t_start, t_end)
- kwargs: additional SciPy solver options
Returns:
FieldBase: Final state
"""MPI-parallel explicit solver for distributed computing (requires MPI installation).
class ExplicitMPISolver:
def __init__(self, pde, *, scheme="euler"):
"""
Initialize MPI parallel explicit solver.
Parameters:
- pde: PDEBase, the PDE to solve
- scheme: str, integration scheme
Note:
Only available if MPI dependencies are installed
"""
@property
def is_mpi_root(self):
"""bool: True if this is the root MPI process"""
def make_stepper(self, state, dt):
"""
Create MPI-parallel stepper.
Parameters:
- state: FieldBase, example state
- dt: float, time step
Returns:
Callable: MPI-parallel stepper function
"""Functions for managing and discovering available solvers.
def registered_solvers():
"""
Get list of all registered solver names.
Returns:
list of str: Names of available solvers
"""Base class providing common solver functionality.
class SolverBase:
@classmethod
def from_name(cls, name, pde, **kwargs):
"""
Create solver instance by name.
Parameters:
- name: str, solver name
- pde: PDEBase, PDE to solve
- kwargs: additional solver parameters
Returns:
SolverBase: Solver instance
"""
@classmethod
def registered_solvers(cls):
"""
Get list of registered solver names.
Returns:
list of str: Available solver names
"""
def make_stepper(self, state, dt=None):
"""
Create time stepping function (abstract method).
Parameters:
- state: FieldBase, example state for compilation
- dt: float, time step
Returns:
Callable: Compiled stepper function
"""
@property
def supports_adaptive_stepping(self):
"""bool: Whether solver supports adaptive time steps"""
def diagnose_performance(self, steps=100, *, state=None):
"""
Analyze solver performance characteristics.
Parameters:
- steps: int, number of test steps
- state: FieldBase, test state (created if None)
Returns:
dict: Performance diagnostics
"""
def check_state_compatibility(self, state):
"""
Check if state is compatible with solver.
Parameters:
- state: FieldBase, state to check
Raises:
ValueError: If incompatible
"""import pde
# Set up problem
grid = pde.UnitGrid([64, 64], periodic=False)
state = pde.ScalarField.random_uniform(grid, 0.2, 0.3)
eq = pde.DiffusionPDE(diffusivity=0.1)
# Use explicit solver
solver = pde.ExplicitSolver(eq, adaptive=True)
result = eq.solve(state, t_range=10.0, solver=solver)
print(f"Solver info: {solver.info}")import pde
import time
# Set up test problem
grid = pde.UnitGrid([32, 32], periodic=True)
state = pde.ScalarField.random_uniform(grid)
eq = pde.AllenCahnPDE()
solvers = {
"explicit": pde.ExplicitSolver(eq),
"implicit": pde.ImplicitSolver(eq),
"crank_nicolson": pde.CrankNicolsonSolver(eq),
"scipy_rk45": pde.ScipySolver(eq, method="RK45")
}
# Time each solver
for name, solver in solvers.items():
start_time = time.time()
result = eq.solve(state.copy(), t_range=1.0, solver=solver)
elapsed = time.time() - start_time
print(f"{name}: {elapsed:.3f}s")import pde
# Set up stiff PDE requiring implicit methods
grid = pde.CartesianGrid([[0, 10]], [128])
eq = pde.DiffusionPDE(diffusivity=100) # High diffusivity = stiff
# Configure implicit solver with Newton options
newton_opts = {
"maxiter": 10,
"atol": 1e-8,
"rtol": 1e-6
}
solver = pde.ImplicitSolver(eq)
state = pde.ScalarField.random_uniform(grid)
# Use controller for automatic management
controller = pde.Controller(
solver,
t_range=1.0,
tracker=pde.ProgressTracker()
)
result = controller.run(state, dt=0.1)
print(f"Simulation completed successfully")import pde
# Problem with varying time scales
grid = pde.UnitGrid([64])
eq = pde.KuramotoSivashinskyPDE()
state = eq.get_initial_condition(grid)
# Enable adaptive stepping
solver = pde.ExplicitSolver(eq, adaptive=True)
# Set up detailed tracking
tracker = [
pde.DataTracker(interrupts=0.1),
pde.RuntimeTracker(interrupts=1.0)
]
result = eq.solve(
state,
t_range=100.0,
solver=solver,
tracker=tracker,
dt=0.01, # Initial time step
adaptive={"atol": 1e-4, "rtol": 1e-3} # Tolerance for adaptation
)
print(f"Adaptive stepping completed")Function for discovering available solver types.
def registered_solvers():
"""
Get list of all registered solver names.
Returns:
list of str: Names of available solver classes
"""Install with Tessl CLI
npx tessl i tessl/pypi-py-pde