Source code for implementations.problem_classes.Auzinger_implicit
import numpy as np
from pySDC.core.problem import Problem
from pySDC.implementations.datatype_classes.mesh import mesh
# noinspection PyUnusedLocal
[docs]
class auzinger(Problem):
r"""
This class implements the Auzinger equation [1]_ as initial value problem. The system of two ordinary differential equations
(ODEs) is given by
.. math::
\frac{d y_1 (t)}{dt} = -y_2 (t) + y_1 (t) (1 - y^2_1 (t) - y^2_2 (t)),
.. math::
\frac{d y_2 (t)}{dt} = y_1 (t) + 3 y_2 (t) (1 - y^2_1 (t) - y^2_2 (t))
with initial condition :math:`(y_1(t), y_2(t))^T = (1, 0)^T` for :math:`t \in [0, 10]`. The exact solution of this problem is
.. math::
(y_1(t), y_2(t))^T = (\cos(t), \sin(t))^T.
Attributes
----------
newton_maxiter : int, optional
Maximum number of iterations for Newton's method.
newton_tol : float, optional
Tolerance for Newton's method to terminate.
References
----------
.. [1] doi.org/10.2140/camcos.2015.10.1
"""
dtype_u = mesh
dtype_f = mesh
def __init__(self, newton_maxiter=1e-12, newton_tol=100):
"""Initialization routine"""
# invoke super init, passing dtype_u and dtype_f, plus setting number of elements to 2
super().__init__((2, None, np.dtype('float64')))
self._makeAttributeAndRegister('newton_maxiter', 'newton_tol', localVars=locals(), readOnly=True)
[docs]
def u_exact(self, t):
r"""
Routine to compute the exact solution at time :math:`t`.
Parameters
----------
t : float
Time of the exact solution.
Returns
-------
me : dtype_u
The exact solution.
"""
me = self.dtype_u(self.init)
me[0] = np.cos(t)
me[1] = np.sin(t)
return me
[docs]
def eval_f(self, u, t):
"""
Routine to compute the right-hand side of the problem for both components simultaneously.
Parameters
----------
u : dtype_u
Current values of the numerical solution.
t : float
Current time of the numerical solution is computed (not used here).
Returns
-------
f : dtype_f
The right-hand side of the problem (contains two components).
"""
x1 = u[0]
x2 = u[1]
f = self.dtype_f(self.init)
f[0] = -x2 + x1 * (1 - x1**2 - x2**2)
f[1] = x1 + 3 * x2 * (1 - x1**2 - x2**2)
return f
[docs]
def solve_system(self, rhs, dt, u0, t):
"""
Simple Newton solver for the nonlinear system.
Parameters
----------
rhs : dtype_f
Right-hand side for the nonlinear system.
dt : float
Abbrev. for the node-to-node stepsize (or any other factor required).
u0 : dtype_u
Initial guess for the iterative solver.
t : float
Current time (e.g. for time-dependent BCs.)
Returns
-------
u : dtype_u
The solution as mesh.
"""
# create new mesh object from u0 and set initial values for iteration
u = self.dtype_u(u0)
x1 = u[0]
x2 = u[1]
# start newton iteration
n = 0
while n < self.newton_maxiter:
# form the function g with g(u) = 0
g = np.array(
[
x1 - dt * (-x2 + x1 * (1 - x1**2 - x2**2)) - rhs[0],
x2 - dt * (x1 + 3 * x2 * (1 - x1**2 - x2**2)) - rhs[1],
]
)
# if g is close to 0, then we are done
res = np.linalg.norm(g, np.inf)
if res < self.newton_tol:
break
# assemble dg and invert the matrix (yeah, I know)
dg = np.array(
[
[1 - dt * (1 - 3 * x1**2 - x2**2), -dt * (-1 - 2 * x1 * x2)],
[-dt * (1 - 6 * x1 * x2), 1 - dt * (3 - 3 * x1**2 - 9 * x2**2)],
]
)
idg = np.linalg.inv(dg)
# newton update: u1 = u0 - g/dg
u -= np.dot(idg, g)
# set new values and increase iteration count
x1 = u[0]
x2 = u[1]
n += 1
return u
# def eval_jacobian(self, u):
#
# x1 = u[0]
# x2 = u[1]
#
# dfdu = np.array([[1-3*x1**2-x2**2, -1-x1], [1+6*x2*x1, 3+3*x1**2-9*x2**2]])
#
# return dfdu
#
#
# def solve_system_jacobian(self, dfdu, rhs, factor, u0, t):
#
# me = mesh(2)
# me = LA.spsolve(sp.eye(2) - factor * dfdu, rhs)
# return me