Quickstart

Solving an equation with odecast involves three steps: declaring the unknown functions, writing the equations, and calling odecast.solve().

Variables

odecast.var() declares an unknown function of the independent variable \(t\). Derivatives are written with .d():

from odecast import var

y = var("y")
y.d()     # y'
y.d(2)    # y''

Vector-valued unknowns are declared with shape; see User Guide.

Equations

odecast.Eq takes a left-hand and a right-hand side:

from odecast import Eq

Eq(y.d(2) + y, 0)               # y'' + y = 0
Eq(y.d(2) + 0.1*y.d() + y, 0)   # y'' + 0.1 y' + y = 0

Nonlinear terms and terms that depend explicitly on the independent variable odecast.t are written with SymPy (or NumPy) functions:

import sympy as sp
from odecast import t

Eq(y.d(2) + sp.sin(y), 0)    # y'' + sin(y) = 0
Eq(y.d(2) + y, sp.sin(t))    # y'' + y = sin(t)

Solving

An initial value problem needs a value for each variable and each of its derivatives below the highest order that occurs, here \(y(0)\) and \(y'(0)\):

from odecast import solve

eq = Eq(y.d(2) + 0.3*y.d() + y, 0)
sol = solve(eq, ivp={y: 1.0, y.d(): 0.0}, tspan=(0, 10))

The initial conditions are taken at tspan[0]. By default the equation is integrated with scipy.integrate.solve_ivp().

Results

sol.t                # time points chosen by the integrator
sol[y]               # y at those points
sol[y.d()]           # y' at those points
sol.eval(y, 5.0)     # y(5), interpolated
sol.eval(y, [1, 2])  # y at several points

Full example

import matplotlib.pyplot as plt
import numpy as np
from odecast import var, Eq, solve

y = var("y")
eq = Eq(y.d(2) + 0.3*y.d() + y, 0)
sol = solve(eq, ivp={y: 1.0, y.d(): 0.0}, tspan=(0, 10))

t = np.linspace(0, 10, 500)
plt.plot(t, sol.eval(y, t), label="y")
plt.plot(t, sol.eval(y.d(), t), label="y'")
plt.xlabel("t")
plt.legend()
plt.show()

Where to go next: the User Guide covers systems, vector variables, boundary value problems and backends; Examples contains worked problems from several fields.