Time-Dependent PDEs

Method of Lines solver for time-dependent PDEs.

Solves initial-boundary value problems of the form u_t = L(u) + s(t), or u_tt = L(u) + s(t) for problems of second order in time (e.g. the wave equation), where L is a spatial differential operator (Expression) and s an optional source term.

class findiff.ivp.MOLSolution(t, u, v=None)

Container for time-dependent PDE solutions.

Returned by TimeDependentPDE.solve() when store_every is set.

Attributes

tndarray, shape (nt_stored,)

Time points at which the solution is stored.

undarray, shape (nt_stored, *spatial_shape)

Solution snapshots. u[i] is the solution at time t[i].

vndarray or None

Snapshots of the time derivative \(u_t\) for problems of second order in time, otherwise None.

property final

Solution at the final time.

class findiff.ivp.TimeDependentPDE(lhs, u0, bcs, t, source=None, v0=None)

Solve a time-dependent PDE using the Method of Lines.

Solves problems of the form

\[\frac{\partial u}{\partial t} = L(u) + s(t)\]

or, if the initial velocity v0 is given, problems of second order in time such as the wave equation,

\[\frac{\partial^2 u}{\partial t^2} = L(u) + s(t)\]

where L is a spatial differential operator built with findiff and s an optional source term.

Parameters

lhsExpression

The spatial differential operator L.

u0ndarray

Initial condition array with the spatial grid shape.

bcsBoundaryConditions

Spatial boundary conditions applied at each time step. Boundary values may be callables g(t) for time-dependent conditions.

t1D ndarray

Time points. t[0] is the initial time.

sourcendarray, callable or None

Optional source term s: an array (constant in time, broadcastable to the grid shape) or a callable s(t) returning such an array.

v0ndarray or None

Initial velocity \(u_t(t_0)\). If given, the problem is of second order in time.

Examples

1D heat equation \(u_t = D\, u_{xx}\):

>>> import numpy as np
>>> from findiff import Diff, BoundaryConditions
>>> from findiff.ivp import TimeDependentPDE
>>> nx = 51
>>> x = np.linspace(0, 1, nx)
>>> dx = x[1] - x[0]
>>> L = 0.01 * Diff(0, dx)**2
>>> u0 = np.sin(np.pi * x)
>>> bc = BoundaryConditions((nx,))
>>> bc[0] = 0
>>> bc[-1] = 0
>>> t = np.linspace(0, 0.1, 100)
>>> u_final = TimeDependentPDE(L, u0, bc, t).solve()
>>> u_final.shape
(51,)
solve(method='crank-nicolson', solver=None, store_every=None, callback=None, **solver_options)

Advance the solution in time.

Parameters

methodstr

Time integration method:

  • 'forward-euler': explicit first-order.

  • 'rk4': explicit fourth-order Runge-Kutta.

  • 'backward-euler': implicit first-order.

  • 'crank-nicolson': implicit second-order (default).

  • 'verlet': explicit second-order Stoermer-Verlet, only for problems of second order in time (v0 given).

For problems of second order in time, 'forward-euler' is not available (it is unstable for undamped waves); the other methods are applied to the equivalent first-order system.

solverstr, callable, or None

Linear solver for implicit methods. Same interface as PDE.solve(). Ignored for explicit methods.

store_everyint or None

If None (default), return only the final solution as an ndarray. If an integer N, store every N-th time step and return a MOLSolution. store_every=1 stores all steps.

callbackcallable or None

Called as callback(step, t_i, u_i) after each time step. Return False to stop early.

**solver_options

Passed to the linear solver (rtol, maxiter, preconditioner, etc.).

Returns

ndarray

Final solution (when store_every is None).

MOLSolution

Solution container (when store_every is set). For problems of second order in time it also holds the velocities v.