{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "###### Content under Creative Commons Attribution license CC-BY 4.0, code under MIT license (c)2014 L.A. Barba, C.D. Cooper, G.F. Forsyth." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Spreading out" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Welcome to the fifth, and last, notebook of Module 4 \"_Spreading out: diffusion problems,\"_ of our fabulous course **\"Practical Numerical Methods with Python.\"**\n", "\n", "In this course module, we have learned about explicit and implicit methods for parabolic equations in 1 and 2 dimensions. So far, all schemes have been first-order in time and second-order in space. _Can we do any better?_ We certainly can: this notebook presents the Crank-Nicolson scheme, which is a second-order method in both time and space! We will continue to use the heat equation to guide the discussion, as we've done throughout this module. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Crank-Nicolson scheme" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The [Crank Nicolson scheme](http://en.wikipedia.org/wiki/CrankâNicolson_method) is a popular second-order, implicit method used with parabolic PDEs in particular. It was developed by John Crank and [Phyllis Nicolson](http://en.wikipedia.org/wiki/Phyllis_Nicolson). The main idea is to take the average between the solutions at $t^n$ and $t^{n+1}$ in the evaluation of the spatial derivative. Why bother doing that? Because the time derivative will then be discretized with a centered scheme, giving second-order accuracy!\n", "\n", "Remember the 1D heat equation from the [first notebook](https://nbviewer.jupyter.org/github/numerical-mooc/numerical-mooc/blob/master/lessons/04_spreadout/04_01_Heat_Equation_1D_Explicit.ipynb)? Just to refresh your memory, here it is:\n", "\n", "$$\n", "\\begin{equation}\n", " \\frac{\\partial T}{\\partial t} = \\alpha \\frac{\\partial^2 T}{\\partial x^2}.\n", "\\end{equation}\n", "$$\n", "\n", "In this case, the Crank-Nicolson scheme leads to the following discretized equation:\n", "\n", "$$\n", "\\begin{equation}\n", " \\begin{split}\n", " & \\frac{T^{n+1}_i - T^n_i}{\\Delta t} = \\\\\n", " & \\quad \\alpha \\cdot \\frac{1}{2} \\left( \\frac{T^{n+1}_{i+1} - 2 T^{n+1}_i + T^{n+1}_{i-1}}{\\Delta x^2} + \\frac{T^n_{i+1} - 2 T^n_i + T^n_{i-1}}{\\Delta x^2} \\right) \\\\\n", " \\end{split}\n", "\\end{equation}\n", "$$\n", "\n", "Notice how the both time indices $n$ and $n+1$ appear on the right-hand side. You know we'll have to rearrange this equation, right? Now look at the stencil and notice that we are using more information than before in the update." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "#### Figure 2. Stencil of the Crank-Nicolson scheme." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Rearranging terms so that everything that we don't know is on the left side and what we do know on the right side, we get\n", "\n", "$$\n", "\\begin{equation}\n", " \\begin{split}\n", " & -T^{n+1}_{i-1} + 2 \\left( \\frac{\\Delta x^2}{\\alpha \\Delta t} + 1 \\right) T^{n+1}_i - T^{n+1}_{i+1} \\\\\n", " & \\qquad = T^{n}_{i-1} + 2 \\left( \\frac{\\Delta x^2}{\\alpha \\Delta t} - 1 \\right) T^{n}_i + T^{n}_{i+1} \\\\\n", " \\end{split}\n", "\\end{equation}\n", "$$\n", "\n", "Again, we are left with a linear system of equations. Check out the left side of that equation: it looks a lot like the matrix from [notebook 2](https://nbviewer.jupyter.org/github/numerical-mooc/numerical-mooc/blob/master/lessons/04_spreadout/04_02_Heat_Equation_1D_Implicit.ipynb), doesn't it? Apart from the slight modification in the $T_i^{n+1}$ term, the left side of the equation is pretty much the same. What about the right-hand side? Sure, it looks quite different, but that is not a problem, we know all those terms!\n", "\n", "Things don't change much for boundary conditions, either. We've seen all the cases already. Say $T_0^{n+1}$ is a Dirichlet boundary. Then the equation for $i=1$ becomes\n", "\n", "$$\n", "\\begin{equation}\n", " \\begin{split}\n", " & 2 \\left( \\frac{\\Delta x^2}{\\alpha \\Delta t} + 1 \\right) T^{n+1}_1 - T^{n+1}_{2} \\\\ \n", " & \\qquad = T^{n}_{0} + 2 \\left( \\frac{\\Delta x^2}{\\alpha \\Delta t} - 1 \\right) T^{n}_1 + T^{n}_{2} + T^{n+1}_{0} \\\\\n", " \\end{split}\n", "\\end{equation}\n", "$$\n", "\n", "And if we have a Neumann boundary $\\left(\\left.\\frac{\\partial T}{\\partial x}\\right|_{x=L} = q\\right)$ at $T_{n_x-1}^{n+1}$? We know this stuff, right? For $i=n_x-2$ we get\n", "\n", "$$\n", "\\begin{equation}\n", " \\begin{split}\n", " & -T^{n+1}_{n_x-3} + \\left( 2 \\frac{\\Delta x^2}{\\alpha \\Delta t} + 1 \\right) T^{n+1}_{n_x-2} \\\\\n", " & \\qquad = T^{n}_{n_x-3} + 2 \\left( \\frac{\\Delta x^2}{\\alpha \\Delta t} - 1 \\right) T^{n}_{n_x-2} + T^{n}_{n_x-1} + q\\Delta x \\\\\n", " \\end{split}\n", "\\end{equation}\n", "$$\n", "\n", "The code will look a lot like the implicit method from the [second notebook](https://nbviewer.jupyter.org/github/numerical-mooc/numerical-mooc/blob/master/lessons/04_spreadout/04_02_Heat_Equation_1D_Implicit.ipynb). Only some terms of the matrix and right-hand-side vector will be different, which changes some of our custom functions." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### The linear system" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Just like in [notebook 2](https://nbviewer.jupyter.org/github/numerical-mooc/numerical-mooc/blob/master/lessons/04_spreadout/04_02_Heat_Equation_1D_Implicit.ipynb), we need to solve a linear system on every time step of the form:\n", "\n", "$$\n", "[A][T^{n+1}_\\text{int}] = [b]+[b]_{b.c.}\n", "$$\n", "\n", "The coefficient matrix is very similar to the previous case, but the right-hand side changes a lot:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "$$\n", "\\begin{align}\n", " \\left[\n", " \\begin{array}{cccccc}\n", " 2 \\left( \\frac{1}{\\sigma} + 1 \\right) & -1 & 0 & \\cdots & & 0 \\\\\n", " -1 & 2 \\left( \\frac{1}{\\sigma} + 1\\right) & -1 & 0 & \\cdots & 0 \\\\\n", " 0 & & \\ddots & & & \\vdots \\\\\n", " \\vdots & & & & 2 \\left( \\frac{1}{\\sigma} + 1\\right) & \\\\\n", " 0 & \\cdots & & & -1 & \\left( 2 \\frac{1}{\\sigma} + 1\\right) \\\\\n", " \\end{array}\n", " \\right] \\cdot \n", " \\left[\n", " \\begin{array}{c} \n", " T_1^{n+1} \\\\\n", " T_2^{n+1} \\\\\n", " \\vdots \\\\\n", " \\\\\n", " T_{N-2}^{n+1} \\\\\n", " \\end{array}\n", " \\right] =\n", " \\left[\n", " \\begin{array}{c}\n", " T_0^n + 2 \\left( \\frac{1}{\\sigma} - 1 \\right) T_1^n + T_2^n \\\\\n", " T_1^n + 2 \\left( \\frac{1}{\\sigma} - 1 \\right) T_2^n + T_3^n \\\\\n", " \\vdots \\\\\n", " \\\\\n", " T_{n_x-3}^n + 2 \\left( \\frac{1}{\\sigma} - 1 \\right) T_{n_x-2}^n + T_{n_x-1}^n \\\\\n", " \\end{array}\n", " \\right] +\n", " \\begin{bmatrix}\n", " T_0^{n+1} \\\\\n", " 0\\\\\n", " \\vdots \\\\\n", " 0 \\\\\n", " q \\Delta x \\\\\n", " \\end{bmatrix}\n", "\\end{align}\n", "$$" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's write a function that will create the coefficient matrix and right-hand-side vectors for the heat conduction problem from [notebook 2](https://nbviewer.jupyter.org/github/numerical-mooc/numerical-mooc/blob/master/lessons/04_spreadout/04_02_Heat_Equation_1D_Implicit.ipynb): with Dirichlet boundary at $x=0$ and zero-flux boundary $(q=0)$ at $x=L$." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import numpy\n", "from scipy import linalg" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "def lhs_operator(N, sigma):\n", " \"\"\"\n", " Computes and returns the implicit operator\n", " of the system for the 1D diffusion equation.\n", " We use Crank-Nicolson method, Dirichlet condition\n", " on the left side of the domain and zero-gradient\n", " Neumann condition on the right side.\n", " \n", " Parameters\n", " ----------\n", " N : integer\n", " Number of interior points.\n", " sigma : float\n", " Value of alpha * dt / dx**2.\n", " \n", " Returns\n", " -------\n", " A : numpy.ndarray\n", " The implicit operator as a 2D array of floats\n", " of size N by N.\n", " \"\"\"\n", " # Setup the diagonal of the operator.\n", " D = numpy.diag(2.0 * (1.0 + 1.0 / sigma) * numpy.ones(N))\n", " # Setup the Neumann condition for the last element.\n", " D[-1, -1] = 1.0 + 2.0 / sigma\n", " # Setup the upper diagonal of the operator.\n", " U = numpy.diag(-1.0 * numpy.ones(N - 1), k=1)\n", " # Setup the lower diagonal of the operator.\n", " L = numpy.diag(-1.0 * numpy.ones(N - 1), k=-1)\n", " # Assemble the operator.\n", " A = D + U + L\n", " return A" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "def rhs_vector(T, sigma, qdx):\n", " \"\"\"\n", " Computes and returns the right-hand side of the system\n", " for the 1D diffusion equation, using a Dirichlet condition\n", " on the left side and a Neumann condition on the right side.\n", " \n", " Parameters\n", " ----------\n", " T : numpy.ndarray\n", " The temperature distribution as a 1D array of floats.\n", " sigma : float\n", " Value of alpha * dt / dx**2.\n", " qdx : float\n", " Value of the temperature flux at the right side.\n", " \n", " Returns\n", " -------\n", " b : numpy.ndarray\n", " The right-hand side of the system as a 1D array of floats.\n", " \"\"\"\n", " b = T[:-2] + 2.0 * (1.0 / sigma - 1.0) * T[1:-1] + T[2:]\n", " # Set Dirichlet condition.\n", " b[0] += T[0]\n", " # Set Neumann condition.\n", " b[-1] += qdx\n", " return b" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We will solve the linear system at every time step. Let's define a function to step in time:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "def crank_nicolson(T0, nt, dt, dx, alpha, q):\n", " \"\"\"\n", " Computes and returns the temperature along the rod\n", " after a given number of time steps.\n", " \n", " The function uses Crank-Nicolson method in time,\n", " central differencing in space, a Dirichlet condition\n", " on the left side, and a Neumann condition on the\n", " right side.\n", " \n", " Parameters\n", " ----------\n", " T0 : numpy.ndarray\n", " The initial temperature distribution as a 1D array of floats.\n", " nt : integer\n", " Number of time steps to compute.\n", " dt : float\n", " Time-step size.\n", " dx : float\n", " Distance between two consecutive locations.\n", " alpha : float\n", " Thermal diffusivity of the rod.\n", " q : float\n", " Value of the temperature gradient on the right side.\n", " \n", " Returns\n", " -------\n", " T : numpy.ndarray\n", " The temperature distribution as a 1D array of floats.\n", " \"\"\"\n", " sigma = alpha * dt / dx**2\n", " # Create the implicit operator of the system.\n", " A = lhs_operator(len(T0) - 2, sigma)\n", " # Integrate in time.\n", " T = T0.copy()\n", " for n in range(nt):\n", " # Generate the right-hand side of the system.\n", " b = rhs_vector(T, sigma, q * dx)\n", " # Solve the system with scipy.linalg.solve.\n", " T[1:-1] = linalg.solve(A, b)\n", " # Apply the Neumann boundary condition.\n", " T[-1] = T[-2] + q * dx\n", " return T" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And we are good to go! First, let's setup our initial conditions, and the matrix" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "# Set parameters.\n", "L = 1.0 # length of the rod\n", "nx = 21 # number of points on the rod\n", "dx = L / (nx - 1) # grid spacing\n", "alpha = 1.22e-3 # thermal diffusivity of the rod\n", "q = 0.0 # temperature gradient at the extremity\n", "\n", "# Define the locations on the rod.\n", "x = numpy.linspace(0.0, L, num=nx)\n", "\n", "# Set the initial temperature distribution.\n", "T0 = numpy.zeros(nx)\n", "T0[0] = 100.0" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Check the matrix..." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[ 6. -1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.\n", " 0. 0.]\n", " [-1. 6. -1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.\n", " 0. 0.]\n", " [ 0. -1. 6. -1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.\n", " 0. 0.]\n", " [ 0. 0. -1. 6. -1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.\n", " 0. 0.]\n", " [ 0. 0. 0. -1. 6. -1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.\n", " 0. 0.]\n", " [ 0. 0. 0. 0. -1. 6. -1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.\n", " 0. 0.]\n", " [ 0. 0. 0. 0. 0. -1. 6. -1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.\n", " 0. 0.]\n", " [ 0. 0. 0. 0. 0. 0. -1. 6. -1. 0. 0. 0. 0. 0. 0. 0. 0. 0.\n", " 0. 0.]\n", " [ 0. 0. 0. 0. 0. 0. 0. -1. 6. -1. 0. 0. 0. 0. 0. 0. 0. 0.\n", " 0. 0.]\n", " [ 0. 0. 0. 0. 0. 0. 0. 0. -1. 6. -1. 0. 0. 0. 0. 0. 0. 0.\n", " 0. 0.]\n", " [ 0. 0. 0. 0. 0. 0. 0. 0. 0. -1. 6. -1. 0. 0. 0. 0. 0. 0.\n", " 0. 0.]\n", " [ 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. -1. 6. -1. 0. 0. 0. 0. 0.\n", " 0. 0.]\n", " [ 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. -1. 6. -1. 0. 0. 0. 0.\n", " 0. 0.]\n", " [ 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. -1. 6. -1. 0. 0. 0.\n", " 0. 0.]\n", " [ 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. -1. 6. -1. 0. 0.\n", " 0. 0.]\n", " [ 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. -1. 6. -1. 0.\n", " 0. 0.]\n", " [ 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. -1. 6. -1.\n", " 0. 0.]\n", " [ 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. -1. 6.\n", " -1. 0.]\n", " [ 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. -1.\n", " 6. -1.]\n", " [ 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.\n", " -1. 5.]]\n" ] } ], "source": [ "A = lhs_operator(nx - 1, 0.5)\n", "print(A)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Looks okay! Now, step in time" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "# Set the time-step size based on CFL limit.\n", "sigma = 0.5\n", "dt = sigma * dx**2 / alpha # time-step size\n", "nt = 10 # number of time steps to compute\n", "\n", "# Compute the temperature distribution.\n", "T = crank_nicolson(T0, nt, dt, dx, alpha, q)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And plot," ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "from matplotlib import pyplot\n", "%matplotlib inline" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "# Set the font family and size to use for Matplotlib figures.\n", "pyplot.rcParams['font.family'] = 'serif'\n", "pyplot.rcParams['font.size'] = 16" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "<Figure size 432x288 with 1 Axes>" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Plot the temperature along the rod.\n", "pyplot.figure(figsize=(6.0, 4.0))\n", "pyplot.xlabel('Distance [m]')\n", "pyplot.ylabel('Temperature [C]')\n", "pyplot.grid()\n", "pyplot.plot(x, T, color='C0', linestyle='-', linewidth=2)\n", "pyplot.xlim(0.0, L)\n", "pyplot.ylim(0.0, 100.0);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Works nicely. But wait! This method has elements of explicit and implicit discretizations. Is it *conditionally stable* like forward Euler, or *unconditionally stable* like backward Euler? Try out different values of `sigma`. You'll see Crank-Nicolson is an *unconditionally stable scheme* for the diffusion equation!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Accuracy & convergence" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Using some techniques you might have learned in your PDE class, such as separation of variables, you can get a closed expression for the rod problem. It looks like this:\n", "\n", "$$\n", "\\begin{eqnarray}\n", "T(x,t) = & \\nonumber \\\\\n", "100 - \\sum_{n=1}^{\\infty} & \\frac{400}{(2n-1)\\pi}\\sin\\left(\\frac{(2n-1)\\pi}{2L}x\\right) \\exp\\left[-\\alpha\\left(\\frac{(2n-1)\\pi}{2L}\\right)^2t\\right]\n", "\\end{eqnarray}\n", "$$\n", "\n", "Unfortunately, the analytical solution is a bit messy, but at least it gives a good approximation if we evaluate it for large $n$. Let's define a function that will calculate this for us:" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [], "source": [ "def analytical_temperature(x, t, alpha, L, N):\n", " \"\"\"\n", " Computes and returns a truncated approximation\n", " of the exact temperature distribution along the rod.\n", " \n", " Parameters\n", " ----------\n", " x : numpy.ndarray\n", " Locations at which to calculate the temperature\n", " as a 1D array of floats.\n", " t : float\n", " Time.\n", " alpha : float\n", " Thermal diffusivity of the rod.\n", " L : float\n", " Length of the rod.\n", " N : integer\n", " Number of terms to use in the expansion.\n", " \n", " Returns\n", " -------\n", " T : numpy.ndarray\n", " The truncated analytical temperature distribution\n", " as a 1D array of floats.\n", " \"\"\"\n", " T = 100.0 * numpy.ones_like(x)\n", " for n in range(1, N + 1):\n", " k = (2 * n - 1) * numpy.pi / (2.0 * L)\n", " T -= (400.0 / (2.0 * L * k) *\n", " numpy.sin(k * x) * numpy.exp(- alpha * k**2 * t))\n", " return T" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And let's see how that expression looks for the time where we left the numerical solution" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "<Figure size 432x288 with 1 Axes>" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Compute the analytical temperature distribution.\n", "T_exact = analytical_temperature(x, nt * dt, alpha, L, 100)\n", "\n", "# Plot the numerical and analytical temperatures.\n", "pyplot.figure(figsize=(6.0, 4.0))\n", "pyplot.xlabel('Distance [m]')\n", "pyplot.ylabel('Temperature [C]')\n", "pyplot.grid()\n", "pyplot.plot(x, T, label='numerical',\n", " color='C0', linestyle='-', linewidth=2)\n", "pyplot.plot(x, T_exact, label='analytical',\n", " color='C1', linestyle='--', linewidth=2)\n", "pyplot.legend()\n", "pyplot.xlim(0.0, L)\n", "pyplot.ylim(0.0, 100.0);" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "6.927917118260093e-13" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "T1 = analytical_temperature(x, 0.2, alpha, L, 100)\n", "T2 = analytical_temperature(x, 0.2, alpha, L, 200)\n", "numpy.sqrt(numpy.sum((T1 - T2)**2) / numpy.sum(T2**2))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "That looks like it should. We'll now use this result to study the convergence of the Crank-Nicolson scheme." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Time convergence" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We said this method was second-order accurate in time, remember? That's in theory, but we should test that the numerical solution indeed behaves like the theory says.\n", "\n", "Leaving $\\Delta x$ constant, we'll run the code for different values of $\\Delta t$ and compare the result at the same physical time, say $t=n_t\\cdot\\Delta t=10$, with the analytical expression above.\n", "\n", "The initial condition of the rod problem has a very sharp gradient: it suddenly jumps from $0{\\rm C}$ to $100{\\rm C}$ at the boundary. To resolve that gradient to the point that it doesn't affect time convergence, we would need a very fine mesh, and computations would be very slow. To avoid this issue, we will start from $t=1$ rather than starting from $t=0$.\n", "\n", "First, let's define a function that will compute the $L_2$-norm of the error:" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [], "source": [ "def l2_error(T, T_exact):\n", " \"\"\"\n", " Computes and returns the relative L2-norm\n", " of the difference between the numerical solution\n", " and the exact solution.\n", " \n", " Parameters\n", " ----------\n", " T : numpy.ndarray\n", " The numerical solution as an array of floats.\n", " T_exact : numpy.ndarray\n", " The exact solution as an array of floats.\n", " \n", " Returns\n", " -------\n", " error : float\n", " The relative L2-norm of the difference.\n", " \"\"\"\n", " error = numpy.sqrt(numpy.sum((T - T_exact)**2) /\n", " numpy.sum(T_exact**2))\n", " return error" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For fun, let's compare the Crank-Nicolson scheme with the implicit (a.k.a., backward) Euler scheme. We'll borrow some functions from [notebook 2](https://nbviewer.jupyter.org/github/numerical-mooc/numerical-mooc/blob/master/lessons/04_spreadout/04_02_Heat_Equation_1D_Implicit.ipynb) to do this." ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [], "source": [ "def lhs_operator_btcs(N, sigma):\n", " \"\"\"\n", " Computes and returns the implicit operator\n", " of the system for the 1D diffusion equation.\n", " We use backward Euler method, Dirichlet condition\n", " on the left side of the domain and zero-gradient\n", " Neumann condition on the right side.\n", " \n", " Parameters\n", " ----------\n", " N : integer\n", " Number of interior points.\n", " sigma : float\n", " Value of alpha * dt / dx**2.\n", " \n", " Returns\n", " -------\n", " A : numpy.ndarray\n", " The implicit operator as a 2D array of floats\n", " of size N by N.\n", " \"\"\"\n", " # Setup the diagonal of the operator.\n", " D = numpy.diag((2.0 + 1.0 / sigma) * numpy.ones(N))\n", " # Setup the Neumann condition for the last element.\n", " D[-1, -1] = 1.0 + 1.0 / sigma\n", " # Setup the upper diagonal of the operator.\n", " U = numpy.diag(-1.0 * numpy.ones(N - 1), k=1)\n", " # Setup the lower diagonal of the operator.\n", " L = numpy.diag(-1.0 * numpy.ones(N - 1), k=-1)\n", " # Assemble the operator.\n", " A = D + U + L\n", " return A" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [], "source": [ "def rhs_vector_btcs(T, sigma, qdx):\n", " \"\"\"\n", " Computes and returns the right-hand side of the system\n", " for the 1D diffusion equation, using a Dirichlet condition\n", " on the left side and a Neumann condition on the right side.\n", " \n", " Parameters\n", " ----------\n", " T : numpy.ndarray\n", " The temperature distribution as a 1D array of floats.\n", " sigma : float\n", " Value of alpha * dt / dx**2.\n", " qdx : float\n", " Value of the temperature flux at the right side.\n", " \n", " Returns\n", " -------\n", " b : numpy.ndarray\n", " The right-hand side of the system as a 1D array of floats.\n", " \"\"\"\n", " b = T[1:-1] / sigma\n", " # Set Dirichlet condition.\n", " b[0] += T[0]\n", " # Set Neumann condition.\n", " b[-1] += qdx\n", " return b" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [], "source": [ "def btcs_implicit(T0, nt, dt, dx, alpha, q):\n", " \"\"\"\n", " Computes and returns the temperature along the rod\n", " after a given number of time steps.\n", " \n", " The function uses Euler implicit in time,\n", " central differencing in space, a Dirichlet condition\n", " on the left side, and a Neumann condition on the\n", " right side.\n", " \n", " Parameters\n", " ----------\n", " T0 : numpy.ndarray\n", " The initial temperature distribution\n", " as a 1D array of floats.\n", " nt : integer\n", " Number of time steps to compute.\n", " dt : float\n", " Time-step size.\n", " dx : float\n", " Distance between two consecutive locations.\n", " alpha : float\n", " Thermal diffusivity of the rod.\n", " q : float\n", " Value of the temperature gradient on the right side.\n", " \n", " Returns\n", " -------\n", " T : numpy.ndarray\n", " The temperature distribution as a 1D array of floats.\n", " \"\"\"\n", " sigma = alpha * dt / dx**2\n", " # Create the implicit operator of the system.\n", " A = lhs_operator_btcs(len(T0) - 2, sigma)\n", " # Integrate in time.\n", " T = T0.copy()\n", " for n in range(nt):\n", " # Generate the right-hand side of the system.\n", " b = rhs_vector_btcs(T, sigma, q * dx)\n", " # Solve the system with scipy.linalg.solve.\n", " T[1:-1] = linalg.solve(A, b)\n", " # Apply the Neumann boundary condition.\n", " T[-1] = T[-2] + q * dx\n", " return T" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now, let's do the runs!" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [], "source": [ "# Update parameters.\n", "nx = 1001 # number of points on the rod\n", "dx = L / (nx - 1) # grid spacing\n", "\n", "# Define the locations on the rod.\n", "x = numpy.linspace(0.0, L, num=nx)\n", "\n", "# Create a list with the time-step sizes to use.\n", "dt_values = [1.0, 0.5, 0.25, 0.125]\n", "\n", "# Create empty lists to hold the errors for both schemes.\n", "errors = []\n", "errors_btcs = []\n", "\n", "# Compute the initial temperature distribution at t=1.0.\n", "t0 = 1.0\n", "T0 = analytical_temperature(x, t0, alpha, L, 100)\n", "\n", "# Compute the final analytical temperature at t=10.0.\n", "t = 10.0\n", "T_exact = analytical_temperature(x, t, alpha, L, 100)\n", "\n", "# Compute the numerical solutions and errors.\n", "for dt in dt_values:\n", " nt = int((t - t0) / dt) # number of time steps\n", " # Compute the solution using Crank-Nicolson scheme.\n", " T = crank_nicolson(T0, nt, dt, dx, alpha, q)\n", " # Compute and record the L2-norm of the error.\n", " errors.append(l2_error(T, T_exact))\n", " # Compute the solution using implicit BTCS scheme.\n", " T = btcs_implicit(T0, nt, dt, dx, alpha, q)\n", " # Compute and record the L2-norm of the error.\n", " errors_btcs.append(l2_error(T, T_exact))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And plot," ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "image/png": "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s2ZIS0vD/fffDwAIDg5GREQEgoODKz1us2CiI/JRqoqMjAwA5urNbdmyBaNHj8bf//53jBgxAtWqWX5NiQjuuusuvPbaawZHWDGDBw9GVlYW4uLicPXq1XLrt23bFlu3bkWHDh0qITpzYqIj8lGqirp16yIoKMhtizcnJyejRYsWqFatGlq0aIHk5GS3tOuMGTNmIDg42NajKW7kyJH4y1/+guPHj6NXr16oVasWYmJi8P777+Omm25CgwYNbINy1q5di9jYWHTu3BlRUVHo0aMHVq1aVaS9wYMH224pbtq0CbfccgtatGiBG264Abt27Soz1oLrFRQUhOjoaKxdu7bcz9etWzfMnj0b33//PV566aUy665evRrR0dEQEUydOrXIsd27dyM2NhYRERGIiopC9+7dMWvWLGRlZdnq7Ny5E0OGDEGLFi1w7bXXYuDAgdiyZUu5MR47dgwPPvggIiMj0alTJ9xwww2YPXt2kTq//vor7r77bkRERKBVq1a48cYb8c0339iOf/7557bYX3jhBTz77LPo0qULwsLCkJCQUG4MbqWqfBn86tKlixpl7dq1hp27KvDk9d29e7eqqubn57ulvffff1+DgoIUgO0VFBSk77//vlvad0ReXp7WqlVL+/Xr51D98+fPa58+fbRRo0aamJioqqonTpzQRo0aqarqI488opMnT7Zdox9//FEDAwN106ZNRdqZMmWKAtDx48fr1atX9cqVK9q7d2/t2bNnkXpr165VALa/14yMDO3SpYt+++23DsU7ZcoUnTJliqqqDh06VP38/HTdunW244cOHdKIiIgS7wNge5+q6v79+7Vu3br61FNP2T7bsmXLVER069atqqq6b98+rVOnjj799NO2OlOmTNHg4GDdvn17qZ9JVbV///764IMP2t73xRdfqCVdWJw+fVqbN2+uI0eO1CtXrqiq6sKFC9XPz09Xr15dIvaIiAhNTU1VVdXVq1crgBL1iiv4+S4NgFR18Hes4b/k+WKiM7PKSHT2FE5WxV/vvPOOrd4777xTZt2CX1Kqqp07dy61zujRo21tFvxCc0VGRoYC0Lvvvtuh+gWJrm7dunrp0iVb+b59+1RV9ciRI5qdnV3kPT169NAxY8YUKStIdAVJQlV1zpw5CkBzc3NtZYWTwunTp7Vbt27l/sIufp6ChHXmzBkNDw/XsLAwPXPmjKo6nujuvfderV27tl68eLFIvZtuukm3bdumqqpxcXFap06dIp//8uXL2rhxY42NjbX7mQoEBwfriy++WKTtyZMn275OSEhQEdH09PQidTp16qQdO3YsEfuwYcOKlNWqVUufe+65Ep+zMHcmOt66JPJBU6dORVZWFvLz8z1+rvT0dI+fozhnJwy3atUKAQEBtu8Ldm4IDg7G888/jy5duthGb+7cuRMHDx60207btm1tX9evXx8A7C5F9fvvv+Pmm2/Gn/70JwwcONCpWAu3/9FHH+HkyZNOb5C7Zs0adOjQocQApO+++w6RkZEAgK+//hodOnQossu8v78/OnXqhK+//trS0ylF7969MWvWLDz66KP43//+h/z8fCQmJtqOf/3112jSpAmaN29e5H3du3fHjh07bM+OCxS+rgBQr169EnU8iYmOyMccP34ciYmJOHPmTKnLJJX1v9v4+Hhbvfj4eFt5RESE3bbCw8MBAJs3by61zaSkJFv9Ll26uPzZGjRogODgYJw8edKp99WqVatEWX5+PmJjY/HVV1/hs88+w/bt25GWloauXbvi0qVLdtspnDgKBsHYGzAyduxYhIaG4t///je2bt1a5NiLL76I6Oho2+vzzz8vNe6ePXsiMTERn376KebNm+fQZwUs65wWJOKy6tSrV69Eef369ZGTk4Ps7OxS37tkyRI888wzWLlyJXr16oVrr722yDSEstouOF5Y8YRcrVo1hwbiuAsTHZGPmTdvHvLy8hAUFIQaNWq4rd3ExMQSv5CCgoKK/E/e0/z8/HDLLbdgy5YtpSbxs2fP4quvvsL58+fLbGv//v1Yv349Ro0ahbCwMLfGOXXqVHz66ado2bIlRo0ahby8PNux6dOn26ZEpKWlYejQoWW2NXHiRAwaNAhPP/00duzY4dD5GzZsiN9//73cOmfPni1RfvbsWQQGBpY5HSUoKAiTJk3CkSNH8M033yAiIgKjR4/G119/XW7bBce9CRMdkQ/JycnB/PnzAbhvC5MCcXFxSEpKQkREBEQEERERSEpKQlxcnFvPU54pU6YgJycH77//vt3jiYmJGDt2bLnzBgt6bcVvgzrbW7TnuuuuQ82aNfHPf/4TaWlpePnll11uS0SwePFiNGjQAKNHj3boPQMGDMCuXbuQk5NTpHzEiBG2FU5uvvlm7Nq1q0jPLS8vD2lpabj55pvLvD18991322Lr168fPv30UwCWSfwFbWdkZJS4rb1p0yZ07NjR66a7MNER+ZD3338fZ86cQdeuXd3amysQFxeHw4cPIz8/H4cPH670JAcAkZGRWLx4MZ5++mksWbLE9hzyypUr+Mc//oEFCxZg4cKFqF697O00r7/+erRs2RLvvfeerffzySefuHVVlT//+c947LHHMH36dPz8888ut9OwYUN8+OGHJW75lWbq1KmoVq0apk6danvW9v7772Pr1q22yfRTpkyxDe0vqDNz5kxcuHCh3F76Rx99VOSW6w8//AA/Pz/07t0bAPDkk08iLCwMEydOtPVmFy9ejG3btuGVV15x7sNXBkdHrfDFUZfkPHde3/z8fG3fvr0C0OTk5HJHpfm6tLQ0HTlypLZv316joqK0Y8eOet999+nOnTtVVTU7O1s7duyowcHBGhwcrFFRUbps2bIibezcuVP79u2roaGh2qdPH50wYYJ26dLFVv/SpUt6zz33aGhoqALQqKgo3b59u/7tb3/T5s2bKwBt166dfvLJJ/rqq69qq1atFIC2atVKX331Vf3222+1bdu2CkBDQ0P1vvvus/tZzp8/r1FRURoaGqqhoaEaFRWl58+fL1FvxowZRUZdfvXVVxoVFWVrv/BoyV27dultt92m4eHhGhUVpcOGDdMDBw4UaW/Hjh06ePBgDQ8P14iICL355puLjIp94YUXinymadOmqarq7NmztXPnzhoZGamRkZHavXt3/fTTT4u0feTIER05cqQ2b95cW7ZsqT179tQ1a9bYjn/33XdFYh87dqz+/vvvGhUVpf7+/lqvXj3t379/qX//7hx1KVrGyBuqHF27dtXU1FRDzp2SkoKYmBhDzl0VuPP6rlmzBgMHDkSzZs1w6NAhHDhwAO3atXNL276KO4x7jtHXds+ePWX+fIvIZlXt6khbZff9ichr/PnPf8aCBQtQvXr1IkPpiahsTHREPiIwMBAPP/yw0WEQ+RwORiHyAYWHrxORc5joiLzc2bNnER4ejqeeeqpSVkIhMhsmOiIvt2DBApw4cQK7du2yrdZBRI7jvxoiL3blyhW8+eabACxzl4jIeUx0biIii0TkZKHXfKNjIt+3dOlSHDt2DNdff73LiwcTVXWmHnUpIk0BvAfgFlV1bjl0F6hqE0+fg6oOVcXcuXMBABMmTOBtSyIXmTbRicgdAOYCsL8y7B/1GlvrFUw83AFggqoedeGciQBqABAAs1W15P4eRA7asGEDNm7ciPr16+O+++4zOhwin2Xm/yJOAjAAwI+lVRCRAABrAAQA6ACgPYCLANaKSMl9P8r2OYA3VfUZAP8D8I2ImPY/EuR5q1atAgA88sgj5S5gTESlM/Mv4l6qmlfOBo4PAIgEcIeq5gGAiDwL4BiARwHMsZatB9C8lDZuUNWjqrqsoEBVl4rIe9a2t1T4k1CV9NJLLyE2Nta2HxwRuca0PbqCxFWOuwCkq6ptu2FVPQlgt/VYQVlPVQ0r5XUUAESk+KJslwEEgqgCunfvjiZN+OjXl/3222+YOXOm0WFg8ODBaNKkidO7t7tDWloaFi1aVOnnLWDaROegSACH7JQfAtDRybb+XfCFiHQCkA9gu+uhUVV18eJFhzfgNJNTp04hOjoa9evXh4jYduhu2bIlIiIi8NBDD9n2kjt8+DACAgLQq1cvW71atWohICCgyO7etWrVsu3PBlgWKp4+fTq6deuGzp07o3379ujSpQseffRRrFmzpshmr/n5+Xj33XfRo0cPdOrUCVFRUejQoQNGjhyJhQsXOvSZTp48iV69eqFNmza2si+++AKNGjXCr7/+6p4L56BVq1ZhzJgxJcrnzZuHFi1alLnjuD32Pse5c+cwdepUpKWlFanbrl07fPTRR5g4caJrwVeQmW9dOqIhgM12ys8DCBKRQFXNsXPcnh0i8hGAkwBaw3I79EJplUUkHkA8AISGhhb5x1iZsrKyDDt3VeDK9V2+fDneeOMNDB8+HGPHji21XkhICC5cKPVHzOcEBgbi+++/x5gxY/DBBx/g+++/tx3bunUrBg0ahIMHD+KLL75AVlYWmjZtiu+++w5+fn4ALD2W9PT0Iu8bPHgwsrOzceHCBaSnp2PYsGHo2bMnli1bhrp16wKw7EQ+btw4zJ8/Hx988AGGDBkCwLKf24cffogVK1bguuuuA2BJxn/961/xwgsvYPjw4eV+pnvuuQd9+vTBrbfeavu7ql69Opo3b44rV65U+t9fwWa0hc8bGBiIa665BtnZ2bh69aqt/OrVq2XGZ+9zHD16FNOmTUOTJk3QqlWrIvXfffdddOzYEZ06dUJsbGy5sebm5rrvd5Oj+/n46gvAIsvHtHvsMoAVdsqTASiAwMqIkfvRmZez1/fq1avapk0bBaCffPJJmXXNuh/dAw88oNZ/s0UMHTpURUQvXLigJ0+e1Pvvv7/Inm59+vQpspebqurEiRN127ZtevXqVe3atavedNNNmp+fX6Lts2fPap06dXT58uW2sgYNGuiECRNK1N2yZYtec8015X6O1NRUBVBijzgjTZkyxe61tcfefnnlOXTokALQ9957z+7xiRMnqqO/79y5H11Vv3V5GoC9DZdqA8hWx3tzRG7x5ZdfYt++fQgPD8ftt99eqecueH5T/OUtzwgLFrYWEYSGhuJf//pXue95+eWXERkZiS+++AKpqakYN26c3WdU9erVwwsvvICwsDBb2ZUrV5Cenl6ibnR0NDZs2FDuuZcsWYLmzZujZcuWtrL33nsP7du3h4jYnlmlpqYiOjoaAQEBePDBB/Hyyy+jR48eCA0NRUJCAgDLMnA33ngjwsLC8Pzzz9vaO378uO0WbUxMDF577TV0794dTZs2RY8ePbBp06YyY0xMTETr1q0hIiV6T19++SW6deuGtm3bomPHjhg4cCD+/e9/l/o5li9fjsGDBwMAXnzxRdvt43Pnztna7N+/PzZv3owDBw6Ue/3cytGM6KsvlN2j+wrAYTvlOwBsqKwY2aMzL2evb//+/RWAzpkzp9y67u7RwXIXw+6rMtnr0a1cuVL9/f318ccfL1JeXo+uwKOPPqoAND093eE4hg0bpgD0r3/9q6alpTn+Aax69Oihffv2LVFeWq8nIiJCmzRpol999ZWqqq5evVoB6OOPP24rW7VqlQIospO3quWzBwUFaUJCgqpa7gw8+OCDGhISor/99putnr0e3dq1axVAkZ/VTz75RP38/Gw93KtXr+pTTz2lISEhZX6O8np0BceTkpLsHi+MPTr3WQYgQkRaFBSISCiAdgCWevrkIhIrIkmZmZmePhX5gB07duCbb75BcHBwhfeds9czK3glJSXZ6iUlJdnKy9OlS5dS24yPj7fV27zZ3mNv5xX0CJo2bYphw4bh4Ycfxssvv+xSW4cPHwZgeR7uqHnz5qF3795YuHChbVDMk08+iW3btjn0/pMnT6Jhw4ZOxdm0aVPccsstAICBAweidu3a+PHHH21lgwYNQq1atbB27doS761evbqtt1etWjXMnDkTWVlZeO2115yKQVXx9NNP46abbrLdVahWrRqmTZuG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\n", "text/plain": [ "<Figure size 432x432 with 1 Axes>" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Plot the error versus the time-step size.\n", "pyplot.figure(figsize=(6.0, 6.0))\n", "pyplot.grid()\n", "pyplot.xlabel(r'$\\Delta t$')\n", "pyplot.ylabel('Relative $L_2$-norm\\nof the error')\n", "pyplot.loglog(dt_values, errors, label='Crank-Nicolson',\n", " color='black', linestyle='--', linewidth=2, marker='o')\n", "pyplot.loglog(dt_values, errors_btcs, label='BTCS (implicit)',\n", " color='black', linestyle='--', linewidth=2, marker='s')\n", "pyplot.legend()\n", "pyplot.axis('equal');" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[0.0005562525604218684,\n", " 0.0001374575644793469,\n", " 3.285170428405964e-05,\n", " 6.771647468538648e-06]" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "errors" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "See how the error drops four times when the time step is halved? This method is second order in time!\n", "\n", "Clearly, Crank-Nicolson (circles) converges faster than backward Euler (squares)! Not only that, but also the error curve is shifted down: Crank-Nicolson is more accurate.\n", "\n", "If you look closely, you'll realize that the error in Crank-Nicolson decays about twice as fast than backward Euler: it's a second versus first order method!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Spatial convergence" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To study spatial convergence, we will run the code for meshes with 21, 41, 81 and 161 points, and compare them at the same non-dimensional time, say $t=20$. \n", "\n", "Let's start by defining a function that will do everything for us" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [], "source": [ "# Set parameters.\n", "dt = 0.1 # time-step size\n", "t = 20.0 # final time\n", "nt = int(t / dt) # number of time steps to compute\n", "\n", "# Create a list with the grid-spacing sizes to use.\n", "nx_values = [11, 21, 41, 81, 161]\n", "\n", "# Create an empty list to store the errors.\n", "errors = []\n", "\n", "# Compute the numerical solutions and errors.\n", "for nx in nx_values:\n", " dx = L / (nx - 1) # grid spacing\n", " x = numpy.linspace(0.0, L, num=nx) # grid points\n", " # Set the initial conditions for the grid.\n", " T0 = numpy.zeros(nx)\n", " T0[0] = 100.0\n", " # Compute the solution using Crank-Nicolson scheme.\n", " T = crank_nicolson(T0, nt, dt, dx, alpha, q)\n", " # Compute the analytical solution.\n", " T_exact = analytical_temperature(x, t, alpha, L, 100)\n", " # Compute and record the L2-norm of the error.\n", " errors.append(l2_error(T, T_exact))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And plot!" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAboAAAGHCAYAAADGE5f2AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvhp/UCwAAIABJREFUeJzt3XmYFOW5/vHvw84gogiCKDAioBElmuCCS4K4JCpIhHPQI1GiKG7RI6KCMwiyKWBUJIsGIVHjKEaJW1yCiSJHf8YVoggoIwouQYPmoDCyDPP8/ugezjjO0l3TM29P9f25rr6YrqquvpNyeHir3sXcHRERkbhqEjqAiIhIfVKhExGRWFOhExGRWFOhExGRWFOhExGRWFOhExGRWFOhExGRWFOhExGRWFOhExGRWGsWOoBAhw4dPD8/P3QMyZDNmzfTpk2b0DEkEF3/hvH6669vcPeOqRyrQpcF8vPzee2110LHkAxZvHgxAwYMCB1DAtH1bxhmtjbVY3XrMiAzG2xmczdu3Bg6iohIbKnQBeTuj7v76Hbt2oWOIiISWyp0IiISayp0IiISayp0IiISayp0IiISayp0AanXpYhI/VOhC0i9LkVE6p8KnYiIxJoKnYiIxJoKnYhIBhQVFZGfn8/AgQPJz8+nqKgodCRJ0lyXIiJ1VFRUxOjRoykpKQFg7dq1jB49GoARI0aEjCaoRSciUmeFhYU7i1y5kpISCgsLAyWSilToAtLwApF4WLduXVrbpWGp0AWk4QUi8dCxY9XLonXr1q2Bk0hVVOhEROrA3atcaDUvL4/p06cHSCSVqdCJiNTBQw89xPvvv8+uu+5K165dMTO6d+/O3Llz1RElS6jQiYhEtH37dgoKCgCYOXMm69at49lnn+WDDz5QkcsiKnQiIhHNmzeP4uJievfuzahRo0LHkWpoHJ2ISESHHnooRx11FFdeeSXNmzcPHUeqoUInIhLRkUceyQsvvBA6htRCty5FRNK0Y8eOnT+bGWYWMI3URoUuIA0YF2mcxowZw9ChQ1mzZk3oKJICFbqANGBcpPF57733uP3223nkkUe+Ne2XZCcVOhGRNEyYMIHS0lJGjhzJQQcdFDqOpECFTkQkRa+99hoLFiygZcuWTJkyJXQcSZEKnYhICtydcePGAXD55ZfTtWvXwIkkVSp0IiIpWLRoEc8++yy77bYb1157beg4kgYVOhGRFLz99ts0a9aMgoICdt9999BxJA0aMC4ikoIrr7ySIUOG0KVLl9BRJE0qdCIiKdpvv/1CR5AIdOtSRKQGf/jDH3jwwQdx99BRJCIVuoA0M4pIdtu4cSNXXHEFw4cP57nnngsdRyJSoQtIM6OIZLdZs2bxxRdfcOyxx3LccceFjiMRqdCJiFThk08+4dZbbwUSBU8TNzdeKnQiIlW4/vrr+frrrxk6dChHHnlk6DhSByp0IiKVrFq1ivnz59O0aVNuuOGG0HGkjlToREQqufnmmykrK+P8889n//33Dx1H6kjj6EREKpkzZw69e/fmpz/9aegokgEqdCIilbRu3Zqrr746dAzJEN26FBFJevvtt/nf//3f0DEkw1ToRESA0tJShg8fzn777cfSpUtDx5EMUqETEQHuueceVqxYQbt27TjwwANDx5EMUqETkZxXUlLCxIkTAZg+fTotW7YMnEgySYUuIM11KZIdfvnLX/Lxxx9z6KGHcsYZZ4SOIxmmQheQ5roUCe/zzz/nxhtvBGDmzJk0aaK/FuNGV1REctqNN97Ixo0bOfHEEznxxBNDx5F6oEInIjnt5JNP5vvf/z4zZswIHUXqiQaMi0hOO/7443n11Ve1OkGMqUUnIjmptLR0588qcvGmQiciOen000/n7LPPZv369aGjSD1ToRORnLN48WL+/Oc/8+ijj9K0adPQcaSeqdCJSE5xd6655hoArrnmGjp27Bg4kdQ3FToRySkLFy7k1VdfpXPnzowZMyZ0HGkAKnQikjO2b99OQUEBANdffz1t2rQJnEgaggqdiOSMefPmsXr1anr37s15550XOo40EBU6EckZa9eupUmTJtxwww00b948dBxpICp0IpIzZsyYwapVqxg6dGjoKNKANDOKiOSUXr16hY4gDUwtOhGJvZtvvpknnngCdw8dRQJQiy4gMxsMDO7Zs2foKCKxVVxczPjx49mxYwfvvvsu+n3LPWrRBaT16ETq34QJEygtLWXkyJEqcjlKhU5EYuvVV1/lgQceoGXLlkyZMiV0HAlEhU5EYsndGTduHACXX345Xbt2DZxIQlGhE5FYWrRoEc899xy77bYb48ePDx1HAlKhE5FYuvnmmwEoKCigffv2gdNISOp1KSKxtHDhQn7zm9/w85//PHQU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\n", "text/plain": [ "<Figure size 432x432 with 1 Axes>" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Plot the error versus the grid-spacing size.\n", "pyplot.figure(figsize=(6.0, 6.0))\n", "pyplot.grid()\n", "pyplot.xlabel(r'$\\Delta x$')\n", "pyplot.ylabel('Relative $L_2$-norm\\nof the error')\n", "dx_values = L / (numpy.array(nx_values) - 1)\n", "pyplot.loglog(dx_values, errors,\n", " color='black', linestyle='--', linewidth=2, marker='o')\n", "pyplot.axis('equal');" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "That looks good! See how for each quadrant we go right, the error drops two quadrants going down (and even a bit better!)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "##### Dig deeper" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's re-do the spatial convergence, but comparing at a much later time, say $t=1000$." ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [], "source": [ "# Set parameters.\n", "dt = 0.1 # time-step size\n", "t = 1000.0 # final time\n", "nt = int(t / dt) # number of time steps to compute\n", "\n", "# Create a list with the grid-spacing sizes to use.\n", "nx_values = [11, 21, 41, 81, 161]\n", "\n", "# Create an empty list to store the errors.\n", "errors = []\n", "\n", "# Compute the numerical solutions and errors.\n", "for nx in nx_values:\n", " dx = L / (nx - 1) # grid spacing\n", " x = numpy.linspace(0.0, L, num=nx) # grid points\n", " # Set the initial conditions for the grid.\n", " T0 = numpy.zeros(nx)\n", " T0[0] = 100.0\n", " # Compute the solution using Crank-Nicolson scheme.\n", " T = crank_nicolson(T0, nt, dt, dx, alpha, q)\n", " # Compute the analytical solution.\n", " T_exact = analytical_temperature(x, t, alpha, L, 100)\n", " # Compute and record the L2-norm of the error.\n", " errors.append(l2_error(T, T_exact))" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAbkAAAGHCAYAAAAtJCz1AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADl0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uIDIuMi4yLCBodHRwOi8vbWF0cGxvdGxpYi5vcmcvhp/UCwAAIABJREFUeJzt3Xl4lOW9//H3NwkBgghl0VotRLFasVL1YLU/S01YKouICMomSF3Apa1HbSuCimwuSBU31FQUxaDIZguoZZEgWKwFRS2KWvSIS6XliGAIS0i+vz9myMGYkMxkMs8sn9d1zUXmWe7nCxfDh/uZ+7lvc3dERERSUUbQBYiIiNQXhZyIiKQshZyIiKQshZyIiKQshZyIiKQshZyIiKQshZyIiKQshZyIiKQshZyIiKSsrKALSHetWrXy3NzcoMtICDt37qRJkyZBlyEicVKXz/y6deu2unvrmo5TyAUsNzeXtWvXBl1GQigqKiIvLy/oMkQkTurymTezj2tznG5XiohIylLIiYhIylLIiYhIylLIiYhIylLIiYhIylLIiYhIylLIiYhIylLIiYhIylLIiYhIylLIiYhIylLIiYhIXBUWFpKbm0vnzp3Jzc2lsLCw3q6luStFRCRuCgsLGTFiBCUlJQB8/PHHjBgxAoAhQ4bE/HrqyYmISNyMGTOmIuD2KykpYcyYMfVyPYWciIjEzebNmyPaXlcKORERiYsPP/yQjIyqY6dNmzb1ck2FnIiI1Lt33nmHTp06UVZW9q2gy8nJYdKkSfVyXYWciIjUq9dff52zzjqLzz//nLPOOouCggLatm2LmdG2bVsKCgrqZdAJaHSliIjUo/LycoYNG8bWrVvp0aMHc+fOJScnh0svvbROK4PXlnpyIiJSbzIyMpg7dy4jR47kueeeIycnJ77Xj+vVREQkLXzwwQcVP//whz/k4YcfJjs7O+51KORERCSmnnrqKU444QTuv//+oEtRyImISOw89NBDDB06lLKyMv79738HXY5CTkREYuPOO+/kqquuqvh5woQJAVek0ZUiIlJH7s5NN93Ebbfdhpkxbdo0rrjiiqDLAhRyIiJSRxMnTuS2224jMzOTJ554ot6eeYuGblfGgJm1MLPpZna/md1rZn8ysx8EXZeISDwMGjSI3Nxc5s2bl1ABBynekzOzI4DHgbPd3erxUm2A3e7+6/B1fwU8CpxVj9cUEQlMWVkZmZmZABx77LFs3LiRhg0bBlzVt6VsT87M+gJrgHY1HHeYmRWa2Xvh11wzOyqSa7n7ene/+oBNHwFHRF61iEjiKykp4ZxzzmHKlCkV2xIx4CCFQw4YBXQDXqnuADPLBpYC2cCJQHtgJ7DCzA6pw7V7Aw/X4XwRkYS0Y8cOunfvzosvvsjkyZP58ssvgy7poFL5duWZ7r7P7KB3KS8GOgB93X0fgJndAHwGXAncFd62Bvh+NW2c4e6f7n9jZr2AZsDUOv8OREQSyP/+7//SvXt31q5dy5FHHsnSpUtp0aJF0GUdVMqG3P7QqkE/YLO7f3jAeV+Y2TvhfXeFt/20NtcMB1wfYKi7l0detYhIYvrXv/5Ft27d2LBhA8cccwzLli3j6KOPDrqsGqXy7cra6EDo+7PKPgJOiqQhM7uA0O3RkeEe5L0xqE9EJHD/8z//Q6dOndiwYQPt27dn1apVSRFwkMI9uVpqBayrYvsOIMfMGrv7rpoaMbMOwNPAVmBg+BZpM+Caao4fAYwAOPzwwykqKoqq+FRTXFysPwuRBPTFF1+wY8cOjjvuOG677Tbef/993n///Tq3G4/PfLqHXHUietzA3d8igj9Ldy8ACgA6duzo9b2eUrKIx9pSIhKd0047jVatWtGsWbOYtan15OrfVqBpFdubAiW16cWJiKSiNWvW8Ic//KHifbt27WIacPGS7j25t4AfVrH9aODtONciIpIQli9fTp8+fdi5cyfHHXccvXv3DrqkqKV7T24+0NbMcvdvMLPDgROAeQHVJCISmD//+c/07NmTnTt3MmzYMHr06BF0SXWS7iE3g1CP7U4zyzKzDOAOQqMrHwqyMBGReJs1axbnn38+e/fu5eqrr+bxxx8nKyu5b/ilbMiZ2V1mth44N/x+ffhVsf66u+8lNOy/DHgHeBc4FOjs7sUBlC0iEoiCggIuuugiysrKuPHGG7n//vvJyEj+iEjuiD4Id/9dLY/bAgyu53JERBJWSUkJd9xxB+7O7bffzqhRo4IuKWZSNuRERKR2cnJyWLp0KUVFRVx66aVBlxNTyd8XFRGRiLk7L7zwQsX7du3apVzAgUJORCTtlJWVcfnll9OzZ89vLJeTinS7UkQkjezdu5dhw4Yxe/ZsGjduzEknRTRNb9JRyAXEzHoDvY899tigSxGRNLFr1y4uuOACFi9eTNOmTVm8eDGdOnUKuqx6pduVAXH3he4+IhmnyRGR5PP111/Ts2dPFi9eTMuWLXnppZdSPuBAPTkRkbRwxRVXUFRUxBFHHMHSpUs58cQTgy4pLhRyIiJp4LbbbuPTTz/lscceo127dkGXEzcKORGRFLVt2zaaN2+OmdG2bVuKiooIr3eZNvSdnIhICvrggw/48Y9/zMSJEyu2pVvAgUJORCTlvPXWW3Tq1IlPPvmEF154gb179wZdUmAUciIiKeS1114jLy+PLVu20KVLF5YsWUJ2dnbNJ6YohZyISIooKiqiS5cubNu2jT59+rBo0SIOOeSQoMsKlEJORCQFLF++nB49elBcXMzgwYOZM2cOjRo1CrqswGl0pYhICvjhD3/IEUccwS9+8QumTZuWEmvBxYJCTkQkBRx55JH87W9/o1WrVmk5irI6inoRkSQ1depUxowZU/G+devWCrhK1JMLiCZoFpFouTsTJ07klltuAaBv37507Ngx4KoSk3pyAdEEzSISDXfn97//PbfccgsZGRlMnz5dAXcQ6smJiCSJsrIyrr76ah555BGysrIoLCzkwgsvDLqshKaQExFJAqWlpQwfPpxZs2bRqFEj5s2bR8+ePYMuK+Ep5EREksD27dv5+9//ziGHHMLChQvJy8sLuqSkoJATEUkCrVq1YtmyZWzZsoXTTjst6HKShgaeiIgkqK+++ooHHngAdwegTZs2CrgIqScnIpKA/v3vf3P22Wezfv16SktLufbaa4MuKSkp5EREEsynn35K165dee+99/jBD35Av379gi4pael2pYhIAtm0aRM/+9nPeO+99+jQoQOrVq2iTZs2QZeVtBRyIiIJYsOGDXTq1ImPP/6Y008/nRUrVnD44YcHXVZSU8iJiCQAd+eqq67iX//6F/n5+SxdupQWLVoEXVbSU8iJiCQAM+Ppp5/myiuvZPHixTRt2jToklKCQk5EJEAbNmyoeETge9/7HtOmTaNx48YBV5U6FHIBMbPeZlawffv2oEsRkYDMmzePU045hdGjRwddSspSyAVEqxCIpLcnnniCCy+8kNLSUnbv3l3Rm5PYUsiJiMTZAw88wPDhwykvL2fs2LHcfffdWuy0nuhhcBGROLr99tsrbk9OmTKF66+/PuCKUptCTkQkTh54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\n", "text/plain": [ "<Figure size 432x432 with 1 Axes>" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "# Plot the error versus the grid-spacing size.\n", "pyplot.figure(figsize=(6.0, 6.0))\n", "pyplot.grid()\n", "pyplot.xlabel(r'$\\Delta x$')\n", "pyplot.ylabel('Relative $L_2$-norm\\nof the error')\n", "dx_values = L / (numpy.array(nx_values) - 1)\n", "pyplot.loglog(dx_values, errors,\n", " color='black', linestyle='--', linewidth=2, marker='o')\n", "pyplot.axis('equal');" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[0.011922719076357474,\n", " 0.006181593859790544,\n", " 0.003142664307189285,\n", " 0.0015838621626866334,\n", " 0.0007950070915380142]" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "errors" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Wait, convergence is not that great now! It's not as good as second order, but not as bad as first order. *What is going on?*\n", "\n", "Remember our implementation of the boundary conditions? We used\n", "\n", "$$\n", "\\begin{equation}\n", "\\frac{T^{n}_{N-1} - T^{n}_{N-2}}{\\Delta x} = q\n", "\\end{equation}\n", "$$\n", "\n", "Well, that is a **first-order** approximation! \n", "\n", "But, why doesn't this affect our solution at an earlier time? Initially, temperature on the right side of the rod is zero and the gradient is very small in that region; at that point in time, errors there were negligible. Once temperature starts picking up, we start having problems.\n", "\n", "**Boundary conditions can affect the convergence and accuracy of your solution!**" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "---\n", "###### The cell below loads the style of the notebook" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "data": { "text/html": [ "<link href='http://fonts.googleapis.com/css?family=Alegreya+Sans:100,300,400,500,700,800,900,100italic,300italic,400italic,500italic,700italic,800italic,900italic' rel='stylesheet' type='text/css'>\n", "<link href='http://fonts.googleapis.com/css?family=Arvo:400,700,400italic' rel='stylesheet' type='text/css'>\n", "<link href='http://fonts.googleapis.com/css?family=PT+Mono' rel='stylesheet' type='text/css'>\n", "<link href='http://fonts.googleapis.com/css?family=Shadows+Into+Light' rel='stylesheet' type='text/css'>\n", "<link href='http://fonts.googleapis.com/css?family=Nixie+One' rel='stylesheet' type='text/css'>\n", "<link href='https://fonts.googleapis.com/css?family=Source+Code+Pro' rel='stylesheet' type='text/css'>\n", "<style>\n", "\n", "@font-face {\n", " font-family: \"Computer Modern\";\n", " src: url('http://mirrors.ctan.org/fonts/cm-unicode/fonts/otf/cmunss.otf');\n", "}\n", "\n", "#notebook_panel { /* main background */\n", " background: rgb(245,245,245);\n", "}\n", "\n", "div.cell { /* set cell width */\n", " width: 750px;\n", "}\n", "\n", "div #notebook { /* centre the content */\n", " background: #fff; /* white background for content */\n", " width: 1000px;\n", " margin: auto;\n", " padding-left: 0em;\n", "}\n", "\n", "#notebook li { /* More space between bullet points */\n", " margin-top:0.8em;\n", "}\n", "\n", "/* draw border around running cells */\n", "div.cell.border-box-sizing.code_cell.running { \n", " border: 1px solid #111;\n", "}\n", "\n", "/* Put a solid color box around each cell and its output, visually linking them*/\n", "div.cell.code_cell {\n", " background-color: rgb(256,256,256); \n", " border-radius: 0px; \n", " padding: 0.5em;\n", " margin-left:1em;\n", " margin-top: 1em;\n", "}\n", "\n", "div.text_cell_render{\n", " font-family: 'Alegreya Sans' sans-serif;\n", " line-height: 140%;\n", " font-size: 125%;\n", " font-weight: 400;\n", " width:600px;\n", " margin-left:auto;\n", " margin-right:auto;\n", "}\n", "\n", "\n", "/* Formatting for header cells */\n", ".text_cell_render h1 {\n", " font-family: 'Nixie One', serif;\n", " font-style:regular;\n", " font-weight: 400; \n", " font-size: 45pt;\n", " line-height: 100%;\n", " color: rgb(0,51,102);\n", " margin-bottom: 0.5em;\n", " margin-top: 0.5em;\n", " display: block;\n", "}\n", "\n", ".text_cell_render h2 {\n", " font-family: 'Nixie One', serif;\n", " font-weight: 400;\n", " font-size: 30pt;\n", " line-height: 100%;\n", " color: rgb(0,51,102);\n", " margin-bottom: 0.1em;\n", " margin-top: 0.3em;\n", " display: block;\n", "}\t\n", "\n", ".text_cell_render h3 {\n", " font-family: 'Nixie One', serif;\n", " margin-top:16px;\n", " font-size: 22pt;\n", " font-weight: 600;\n", " margin-bottom: 3px;\n", " font-style: regular;\n", " color: rgb(102,102,0);\n", "}\n", "\n", ".text_cell_render h4 { /*Use this for captions*/\n", " font-family: 'Nixie One', serif;\n", " font-size: 14pt;\n", " text-align: center;\n", " margin-top: 0em;\n", " margin-bottom: 2em;\n", " font-style: regular;\n", "}\n", "\n", ".text_cell_render h5 { /*Use this for small titles*/\n", " font-family: 'Nixie One', sans-serif;\n", " font-weight: 400;\n", " font-size: 16pt;\n", " color: rgb(163,0,0);\n", " font-style: italic;\n", " margin-bottom: .1em;\n", " margin-top: 0.8em;\n", " display: block;\n", "}\n", "\n", ".text_cell_render h6 { /*use this for copyright note*/\n", " font-family: 'PT Mono', sans-serif;\n", " font-weight: 300;\n", " font-size: 9pt;\n", " line-height: 100%;\n", " color: grey;\n", " margin-bottom: 1px;\n", " margin-top: 1px;\n", "}\n", "\n", ".CodeMirror{\n", " font-family: \"Source Code Pro\";\n", " font-size: 90%;\n", "}\n", "\n", ".alert-box {\n", " padding:10px 10px 10px 36px;\n", " margin:5px;\n", "}\n", "\n", ".success {\n", " color:#666600;\n", " background:rgb(240,242,229);\n", "}\n", "</style>\n", "\n", "<script>\n", " MathJax.Hub.Config({\n", " TeX: {\n", " extensions: [\"AMSmath.js\"],\n", " equationNumbers: { autoNumber: \"AMS\", useLabelIds: true}\n", " },\n", " tex2jax: {\n", " inlineMath: [ ['$','$'], [\"\\\\(\",\"\\\\)\"] ],\n", " displayMath: [ ['$$','$$'], [\"\\\\[\",\"\\\\]\"] ]\n", " },\n", " displayAlign: 'center', // Change this to 'center' to center equations.\n", " \"HTML-CSS\": {\n", " styles: {'.MathJax_Display': {\"margin\": 4}}\n", " }\n", " });\n", " MathJax.Hub.Queue(\n", " [\"resetEquationNumbers\", MathJax.InputJax.TeX],\n", " [\"PreProcess\", MathJax.Hub],\n", " [\"Reprocess\", MathJax.Hub]\n", " );\n", "</script>\n" ], "text/plain": [ "<IPython.core.display.HTML object>" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from IPython.core.display import HTML\n", "css_file = '../../styles/numericalmoocstyle.css'\n", "HTML(open(css_file, 'r').read())" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (MOOC)", "language": "python", "name": "py36-mooc" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.6.6" } }, "nbformat": 4, "nbformat_minor": 1 }