|
| 1 | +""" |
| 2 | +Derived problem classes for the SDC order-reduction playground. |
| 3 | +
|
| 4 | +This module defines problem classes that extend the standard FEniCS-based 1D |
| 5 | +heat equation implementations to demonstrate boundary lifting as a remedy for |
| 6 | +order reduction in SDC with time-dependent Dirichlet boundary conditions. |
| 7 | +""" |
| 8 | + |
| 9 | +import dolfin as df |
| 10 | +import numpy as np |
| 11 | + |
| 12 | +from pySDC.implementations.problem_classes.HeatEquation_1D_FEniCS_matrix_forced import fenics_heat_mass_timebc |
| 13 | + |
| 14 | + |
| 15 | +class fenics_heat_mass_timebc_lift(fenics_heat_mass_timebc): |
| 16 | + r""" |
| 17 | + One-dimensional heat equation with time-dependent Dirichlet boundary |
| 18 | + conditions, solved by **boundary lifting** to restore the full SDC |
| 19 | + convergence order. |
| 20 | +
|
| 21 | + **Background** |
| 22 | +
|
| 23 | + When the time-dependent BC is applied directly inside ``solve_system`` |
| 24 | + (as in :class:`fenics_heat_mass_timebc`), the BC imposition overwrites |
| 25 | + rows of the right-hand-side at each SDC sweep, which means the fixed |
| 26 | + point of the implicit sweeper no longer matches the collocation solution. |
| 27 | + This causes *order reduction*: the effective convergence order is lower |
| 28 | + than the theoretical SDC order :math:`2M-1`. |
| 29 | +
|
| 30 | + **Boundary lifting** eliminates this problem by reformulating the |
| 31 | + equation in terms of a new variable :math:`v = u - E`, where :math:`E` |
| 32 | + is a *lift function* that already satisfies the time-dependent BCs at |
| 33 | + every time. The equation for :math:`v` then has **homogeneous** Dirichlet |
| 34 | + BCs, and the standard SDC sweep applies without any BC imposition inside |
| 35 | + ``solve_system``. This restores the full collocation order. |
| 36 | +
|
| 37 | + **Problem formulation** |
| 38 | +
|
| 39 | + The original problem is |
| 40 | +
|
| 41 | + .. math:: |
| 42 | + u_t = \nu u_{xx} + f(x,t), \quad u(0,t) = \cos(0)\cos(t) = \cos(t), |
| 43 | + \quad u(1,t) = \cos(\pi)\cos(t) = -\cos(t), |
| 44 | +
|
| 45 | + with exact solution :math:`u(x,t) = \cos(\pi x)\cos(t) + c`. |
| 46 | +
|
| 47 | + We choose the lift |
| 48 | +
|
| 49 | + .. math:: |
| 50 | + E(x,t) = (1 - 2x)\cos(t) + c, |
| 51 | +
|
| 52 | + which interpolates linearly between the two boundary values |
| 53 | + :math:`E(0,t) = \cos(t) + c` and :math:`E(1,t) = -\cos(t) + c`. |
| 54 | +
|
| 55 | + The transformed variable :math:`v = u - E` satisfies :math:`v = 0` on |
| 56 | + :math:`\partial\Omega` and |
| 57 | +
|
| 58 | + .. math:: |
| 59 | + v_t = \nu v_{xx} + \tilde{f}(x,t), |
| 60 | +
|
| 61 | + where the modified forcing is |
| 62 | +
|
| 63 | + .. math:: |
| 64 | + \tilde{f}(x,t) = f(x,t) - E_t(x,t) + \nu E_{xx}(x,t). |
| 65 | +
|
| 66 | + Since :math:`E` is linear in :math:`x`, we have :math:`E_{xx} = 0` and |
| 67 | + :math:`E_t = -(1-2x)\sin(t)`, so |
| 68 | +
|
| 69 | + .. math:: |
| 70 | + \tilde{f}(x,t) = -\cos(\pi x)(\sin(t) - \nu\pi^2\cos(t)) |
| 71 | + + (1-2x)\sin(t). |
| 72 | +
|
| 73 | + The exact solution of the transformed problem is |
| 74 | +
|
| 75 | + .. math:: |
| 76 | + v(x,t) = \cos(\pi x)\cos(t) - (1-2x)\cos(t) = \cos(t)(\cos(\pi x) - 1 + 2x). |
| 77 | +
|
| 78 | + Parameters |
| 79 | + ---------- |
| 80 | + c_nvars : int, optional |
| 81 | + Spatial resolution (number of degrees of freedom). Default ``128``. |
| 82 | + t0 : float, optional |
| 83 | + Starting time. Default ``0.0``. |
| 84 | + family : str, optional |
| 85 | + FEniCS finite element family. Default ``'CG'``. |
| 86 | + order : int, optional |
| 87 | + Finite element polynomial order. Default ``4``. |
| 88 | + refinements : int, optional |
| 89 | + Number of mesh refinements. Default ``1``. |
| 90 | + nu : float, optional |
| 91 | + Diffusion coefficient :math:`\nu`. Default ``0.1``. |
| 92 | + c : float, optional |
| 93 | + Constant offset in the boundary data. Default ``0.0``. |
| 94 | +
|
| 95 | + Attributes |
| 96 | + ---------- |
| 97 | + V : FunctionSpace |
| 98 | + FEniCS function space. |
| 99 | + M : Matrix |
| 100 | + Mass matrix :math:`\int_\Omega u v\,dx`. |
| 101 | + K : Matrix |
| 102 | + Stiffness matrix :math:`-\nu\int_\Omega \nabla u \cdot \nabla v\,dx`. |
| 103 | + g : Expression |
| 104 | + Modified forcing term :math:`\tilde{f}` including the lift correction. |
| 105 | + bc_hom : DirichletBC |
| 106 | + Homogeneous Dirichlet BC for the transformed variable :math:`v`. |
| 107 | +
|
| 108 | + References |
| 109 | + ---------- |
| 110 | + .. [1] Spectral Deferred Correction Methods for Ordinary Differential Equations. |
| 111 | + A. Dutt, L. Greengard, V. Rokhlin. Mathematics of Computation, 2001. |
| 112 | + https://dl.acm.org/doi/abs/10.1090/S0025-5718-01-01362-X |
| 113 | + """ |
| 114 | + |
| 115 | + def __init__(self, c_nvars=128, t0=0.0, family='CG', order=4, refinements=1, nu=0.1, c=0.0): |
| 116 | + """Initialization routine""" |
| 117 | + |
| 118 | + super().__init__(c_nvars, t0, family, order, refinements, nu, c) |
| 119 | + |
| 120 | + # Override the forcing term to include lift correction terms. |
| 121 | + # Lift: E(x, t) = (1 - 2*x) * cos(t) + c (linear interpolation of boundary data) |
| 122 | + # dE/dt = -(1 - 2*x) * sin(t) |
| 123 | + # E_xx = 0 (E is linear in x) |
| 124 | + # Modified forcing: f_tilde = f - dE/dt + nu * E_xx |
| 125 | + # = -cos(pi*x) * (sin(t) - nu*pi^2*cos(t)) + (1 - 2*x) * sin(t) |
| 126 | + self.g = df.Expression( |
| 127 | + '-cos(a*x[0]) * (sin(t) - b*a*a*cos(t)) + (1 - 2*x[0]) * sin(t)', |
| 128 | + a=np.pi, |
| 129 | + b=self.nu, |
| 130 | + t=self.t0, |
| 131 | + degree=self.order, |
| 132 | + ) |
| 133 | + |
| 134 | + def solve_system(self, rhs, factor, u0, t): |
| 135 | + r""" |
| 136 | + Dolfin's linear solver for the transformed problem :math:`(M - \text{factor} \cdot A)\,v = \text{rhs}`. |
| 137 | +
|
| 138 | + Uses homogeneous Dirichlet BCs since the transformed variable |
| 139 | + :math:`v = u - E` satisfies :math:`v = 0` on :math:`\partial\Omega`. |
| 140 | +
|
| 141 | + Parameters |
| 142 | + ---------- |
| 143 | + rhs : dtype_f |
| 144 | + Right-hand side for the linear system. |
| 145 | + factor : float |
| 146 | + Abbrev. for the node-to-node stepsize (or any other factor required). |
| 147 | + u0 : dtype_u |
| 148 | + Initial guess (not used here). |
| 149 | + t : float |
| 150 | + Current time. |
| 151 | +
|
| 152 | + Returns |
| 153 | + ------- |
| 154 | + u : dtype_u |
| 155 | + Solution of the transformed variable :math:`v`. |
| 156 | + """ |
| 157 | + |
| 158 | + u = self.dtype_u(u0) |
| 159 | + T = self.M - factor * self.K |
| 160 | + b = self.dtype_u(rhs) |
| 161 | + |
| 162 | + self.bc_hom.apply(T, b.values.vector()) |
| 163 | + |
| 164 | + df.solve(T, u.values.vector(), b.values.vector()) |
| 165 | + |
| 166 | + return u |
| 167 | + |
| 168 | + def u_exact(self, t): |
| 169 | + r""" |
| 170 | + Routine to compute the exact solution of the transformed variable :math:`v` at time :math:`t`. |
| 171 | +
|
| 172 | + The exact transformed solution is |
| 173 | +
|
| 174 | + .. math:: |
| 175 | + v(x,t) = u_{\text{exact}}(x,t) - E(x,t) = \cos(t)(\cos(\pi x) - 1 + 2x), |
| 176 | +
|
| 177 | + where :math:`E(x,t) = (1-2x)\cos(t) + c` is the lift. |
| 178 | +
|
| 179 | + Parameters |
| 180 | + ---------- |
| 181 | + t : float |
| 182 | + Time of the exact solution. |
| 183 | +
|
| 184 | + Returns |
| 185 | + ------- |
| 186 | + me : dtype_u |
| 187 | + Exact solution of the transformed variable :math:`v`. |
| 188 | + """ |
| 189 | + |
| 190 | + # v_exact = u_real_exact - E |
| 191 | + # = (cos(pi*x)*cos(t) + c) - ((1 - 2*x)*cos(t) + c) |
| 192 | + # = cos(t) * (cos(pi*x) - 1 + 2*x) |
| 193 | + u0 = df.Expression('cos(t) * (cos(a*x[0]) - 1 + 2*x[0])', a=np.pi, t=t, degree=self.order) |
| 194 | + me = self.dtype_u(df.interpolate(u0, self.V), val=self.V) |
| 195 | + |
| 196 | + return me |
0 commit comments