Time-dependence#

We denote by \(\leftrightarrow\) a correspondence between mathematical notation and its Python implementation, for example

\[\begin{split} u(\textbf{x}, t\leq t^{n+1})= \begin{bmatrix} u^{n+1}(\textbf{x}) \\ u^n(\textbf{x}) \\ u^{n-1}(\textbf{x}) \\ \vdots \\ u^{1}(\textbf{x}) \\ u^{0}(\textbf{x}) \\ \end{bmatrix}\leftrightarrow\texttt{FunctionSeries} \end{split}\]

Mathematical notation

Python implementation

\(u(\textbf{x})=\sum_ju_j\xi_j(\textbf{x})\)

u = Function(fs)

\(\textbf{u} = \{u_j\}_j\)

u.x.array

\(u(\textbf{x},t)=\sum_ju_j(t)\xi_j(\textbf{x})\)

u = FunctionSeries(fs)

\(u(\textbf{x},t^{n+i})=u^{n+i}(\textbf{x})=\sum_ju_j\xi_j^{n+i}(\textbf{x})\)

u[i]

\(\{u^i\}_{i\geq0}\)

u.series

\(\{t^i\}_{i\geq0}\)

u.time_series

\(u^{n+1} \gets w\)

u.update(w, future=True)

\(u^n \gets w\)

u.update(w, future=False)

\(u^{n-j} \gets u^{n+1-j} ~\forall j\in\mathbb{N}\)

u.forward()

\(c\)

c = Constant(mesh)

\(c(t)\)

u = ConstantSeries(mesh)

\(\{c^i\}_{i\geq0}\)

c.series

\(\{c^i\}_{i\geq0}\)

c.time_series

\(f(u(\textbf{x}), w(\textbf{x})) = uw\)

f = u * w or f = Expr(u * w)

\(f(u(\textbf{x}, t), w(\textbf{x}, t)) = uv\)

f = u * w or f = ExprSeries(u * w)

\(\{f^i\}_{i\geq0}=\{u^iw^i\}_{i\geq0}\)

f.series

\(\{t^i\}_{i\geq0}=\{t^i\}_{i\geq0}\)

f.time_series

from lucifex.mesh import interval_mesh
from lucifex.fdm import FunctionSeries
from lucifex.fdm.ufl_operators import grad, inner


mesh = interval_mesh(1.0, 10)
order = 3

a = FunctionSeries((mesh, 'P', 1), 'a', order=order)
a.update(0.1)

b = FunctionSeries((mesh, 'P', 1), 'b', order=order)
b.update(0.3)

print('\n After setting present value:')
print(a)
print(b)

a.update(0.2, future=True)
b.update(0.4, future=True)
print('\n After setting future value:')
print(a)
print(b)

t = 0.0
a.forward(t)
b.forward(t)
print('\n After stepping forward:')
print(a)
print(b)

t = 1.0
a.forward(t)
b.forward(t)
print('\n After stepping forward again:')
print(a)
print(b)
 After setting present value:
FunctionSeries(Unsolved, Unsolved; a⁽⁰⁾; Unsolved)
FunctionSeries(Unsolved, Unsolved; b⁽⁰⁾; Unsolved)

 After setting future value:
FunctionSeries(Unsolved, Unsolved; a⁽⁰⁾; a⁽⁺¹⁾)
FunctionSeries(Unsolved, Unsolved; b⁽⁰⁾; b⁽⁺¹⁾)

 After stepping forward:
FunctionSeries(Unsolved, a⁽⁻¹⁾; a⁽⁰⁾; Unsolved)
FunctionSeries(Unsolved, b⁽⁻¹⁾; b⁽⁰⁾; Unsolved)

 After stepping forward again:
FunctionSeries(a⁽⁻²⁾, a⁽⁻¹⁾; Unsolved; Unsolved)
FunctionSeries(b⁽⁻²⁾, b⁽⁻¹⁾; Unsolved; Unsolved)

Unary operations on series#

lucifex.fdm.ufl_operators provides overloaded versions of the ufl package’s div, grad and curl operators, which can additionally accept an argument of type Series.

\[\mathcal{O}_1 \leftrightarrow \texttt{Callable[[Series], ExprSeries]}\]
\[\mathcal{O}_1(u(\textbf{x},t)) \leftrightarrow \texttt{ExprSeries}\]
\[\begin{split}\mathcal{O}_1(u(\textbf{x},t)) \approx \begin{bmatrix} \mathcal{O}_1(u^{n+1}(\textbf{x})) \\ \mathcal{O}_1(u^n(\textbf{x})) \\ \mathcal{O}_1(u^{n-1}(\textbf{x})) \\ \vdots \end{bmatrix}\end{split}\]
grad_a = grad(a)

Binary operations on series#

lucifex.fdm.ufl_operators provides overloaded versions of the ufl package’s inner and dot operators, which can additionally accept arguments of type Series.

\[\mathcal{O}_2 \leftrightarrow \texttt{Callable[[Series, Series], ExprSeries]}\]
\[\mathcal{O}_2(a(\textbf{x},t), b(\textbf{x},t)) \leftrightarrow \texttt{ExprSeries}\]
\[\begin{split}\mathcal{O}_2(a(\textbf{x},t), b(\textbf{x},t)) \approx \begin{bmatrix} \mathcal{O}_2(a^{n+1}(\textbf{x}), b^{n+1}(\textbf{x})) \\ \mathcal{O}_2(a^n(\textbf{x}), b^n(\textbf{x})) \\ \mathcal{O}_2(a^{n-1}(\textbf{x}), b^{n-1}(\textbf{x})) \\ \vdots \end{bmatrix}\end{split}\]
e = a * (1 + b)**2

print(type(e))
print(repr(e))
<class 'lucifex.fdm.series.ExprSeries'>
ExprSeries(a⁽⁻²⁾ * (1 + b⁽⁻²⁾) ** 2, a⁽⁻¹⁾ * (1 + b⁽⁻¹⁾) ** 2; Unsolved; Unsolved)

Time-dependent quantities#

A time-dependent finite element function

\[u(\textbf{x},t)\approx\sum_ju_j(t)\xi_j(\textbf{x})\]
\[\begin{split}u(\textbf{x}, t\leq t^{n+1})\approx \begin{bmatrix} u^{n+1}(\textbf{x}) \\ u^n(\textbf{x}) \\ u^{n-1}(\textbf{x}) \\ \vdots \end{bmatrix}\end{split}\]

where \(u^n(\textbf{x})=\sum_ju_j^n\xi_j(\textbf{x})\) and \(u_j^n\approx u_j(t^n)\) is represented by the FunctionSeries object

u = FunctionSeries(function_space, 'u', order, store)

and its future, present and past values \(u^{n+1}, u^n, u^{n-1}, \dots\) as far back as specified by order are accessed as

u[+1], u[0], u[-1], ...

If held in memory in accordance with the store parameter passed to FunctionSeries, the sequences \([u^0(\textbf{x}), u^1(\textbf{x}), \dots]\) and \([t^0, t^1, \dots]\) are acessed as

u.series
u.time_series

Time-dependent constants and expressions are similarly implemented by ConstantSeries and ExprSeries.