Files
cds-numerical-methods/Week 6/10 Hyperbolic PDEs.ipynb
2022-03-15 10:46:16 +01:00

556 lines
47 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"deletable": false,
"editable": false,
"nbgrader": {
"cell_type": "markdown",
"checksum": "4ec40081b048ce2f34f3f4fedbb0be10",
"grade": false,
"grade_id": "cell-98f724ece1aacb67",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
}
},
"source": [
"# CDS: Numerical Methods Assignments\n",
"\n",
"- See lecture notes and documentation on Brightspace for Python and Jupyter basics. If you are stuck, try to google or get in touch via Discord.\n",
"\n",
"- Solutions must be submitted via the Jupyter Hub.\n",
"\n",
"- Make sure you fill in any place that says `YOUR CODE HERE` or \"YOUR ANSWER HERE\".\n",
"\n",
"## Submission\n",
"\n",
"1. Name all team members in the the cell below\n",
"2. make sure everything runs as expected\n",
"3. **restart the kernel** (in the menubar, select Kernel$\\rightarrow$Restart)\n",
"4. **run all cells** (in the menubar, select Cell$\\rightarrow$Run All)\n",
"5. Check all outputs (Out[\\*]) for errors and **resolve them if necessary**\n",
"6. submit your solutions **in time (before the deadline)**"
]
},
{
"cell_type": "raw",
"metadata": {},
"source": [
"team_members = \"Koen Vendrig, Kees van Kempen\""
]
},
{
"cell_type": "markdown",
"metadata": {
"deletable": false,
"editable": false,
"nbgrader": {
"cell_type": "markdown",
"checksum": "62fbcf7aaa9e165abd27319c5bd35555",
"grade": false,
"grade_id": "cell-e9dc85dd9ad77a5e",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
}
},
"source": [
"## Dynamic Behavior from Hyperbolic PDEs\n",
"\n",
"In the following you will derive and implement finite-difference methods to study generalized hyperbolic partial differential equations."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"deletable": false,
"nbgrader": {
"cell_type": "code",
"checksum": "910692c2f4b93f251a3a128caf2b0c37",
"grade": true,
"grade_id": "cell-acb87410eaef9fe1",
"locked": false,
"points": 0,
"schema_version": 3,
"solution": true,
"task": false
}
},
"outputs": [],
"source": [
"import numpy as np\n",
"from matplotlib import pyplot as plt"
]
},
{
"cell_type": "markdown",
"metadata": {
"deletable": false,
"editable": false,
"nbgrader": {
"cell_type": "markdown",
"checksum": "7238a56701aaf868838ffdb706f5eb8b",
"grade": false,
"grade_id": "cell-a27c54a734bf2232",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
}
},
"source": [
"### Task 1: finite-difference hyperbolic PDE solver\n",
"\n",
"Our aim is to implement a Python function to find the solution of the following PDE:\n",
"\n",
"\\begin{align*}\n",
" \\frac{\\partial^2}{\\partial t^2} u(x,t)\n",
" - \\alpha^2 \\frac{\\partial^2}{\\partial x^2} u(x,t) = 0,\n",
" \\qquad\n",
" 0 \\leq x \\leq l,\n",
" \\qquad\n",
" 0 \\leq t\n",
"\\end{align*}\n",
"\n",
"with the boundary conditions\n",
"\n",
"\\begin{align*}\n",
" u(0,t) = u(l,t) &= 0, \n",
" &&\\text{for } t > 0 \\\\\n",
" u(x,0) &= f(x) \\\\\n",
" \\frac{\\partial}{\\partial t} u(x,0) &= g(x)\n",
" &&\\text{for } 0 \\leq x \\leq l.\n",
"\\end{align*}\n",
" \n",
"By approximating the partial derivatives with finite differences we can recast the problem into the following form\n",
"\t\t\n",
"\\begin{align*}\n",
" \\vec{w}_{j+1} = \\mathbf{A} \\vec{w}_{j}\n",
" - \\vec{w}_{j-1}.\n",
"\\end{align*}\n",
"\n",
"Here $\\vec{w}_j$ is a vector of length $m$ in the discretized spatial coordinate $x_i$ at time step $t_j$. The spatial coordinates are defined as $x_i = i h$, where $i=0,1,\\dots,m-1$ and $h = l/(m-1)$. The time steps are defined as $t_j = j k$, where $j = 0, 1, \\dots, n-1$.\n",
"\n",
"The tri-diagonal matrix $\\mathbf{A}$ has size $(m-2)\\times(m-2)$ and is defined by\n",
"\n",
"\\begin{align*}\n",
" \\mathbf{A} =\n",
" \\left( \\begin{array}{cccc}\n",
" 2(1-\\lambda^2) & \\lambda^2 & & 0\\\\\n",
" \\lambda^2 & \\ddots & \\ddots & \\\\\n",
" & \\ddots & \\ddots & \\lambda^2 \\\\\n",
" 0 & & \\lambda^2 & 2(1-\\lambda^2) \n",
" \\end{array} \\right),\n",
"\\end{align*}\n",
" \n",
"where $\\lambda = \\alpha k / h$. This $(m-2)\\times(m-2)$ structure accounts for the first set of boundary conditions. Note that the product $\\mathbf{A} \\vec{w}_{j}$ is thus only performed over the $m-2$ subset, i.e. $i=1,2,\\dots,m-2$. The other boundary conditions are accounted for by initializing the first two time steps with\n",
"\n",
"\\begin{align*}\n",
" w_{i,j=0} &= f(x_i) \\\\\n",
" w_{i,j=1} &= (1-\\lambda^2) f(x_i)\n",
" + \\frac{\\lambda^2}{2} f(x_{i+1})\n",
" + \\frac{\\lambda^2}{2} f(x_{i-1})\n",
" + kg(x_i).\n",
"\\end{align*}\n",
" \n",
"Implement a Python function of the form $\\text{pdeHyperbolic(a, x, t, f, g)}$, where $\\text{a}$ represents the PDE parameter $\\alpha$, $\\text{x}$ and $\\text{t}$ are the discretized spatial and time grids, and $\\text{f}$ and $\\text{g}$ are the functions defining the boundary conditions. This function should return a two-dimensional array $\\text{w[:,:]}$, which stores the spatial vector $\\vec{w}_j$ at each time coordinate $t_j$."
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"deletable": false,
"nbgrader": {
"cell_type": "code",
"checksum": "95d463713a216d57cbf814a0f40a482d",
"grade": true,
"grade_id": "cell-1f9655333f2dc3cb",
"locked": false,
"points": 3,
"schema_version": 3,
"solution": true,
"task": false
}
},
"outputs": [],
"source": [
"def pdeHyperbolic(a, x, t, f, g):\n",
" \"\"\"\n",
" Numerically solves the hyperbolic differential equation ∂^2u(x,t)/∂t^2 - a*∂^2u(x,t)/∂x^2 = 0\n",
" with constant a for boundary conditions given by\n",
" u(0, t) = 0 = u(x[-1], t) for all t\n",
" y(x, 0) = f(x)\n",
" ∂u(x, t)/∂t = g(x) for t = 0 and all x\n",
"\n",
" Args:\n",
" a: numerical constant in the PDE\n",
" x: array of evenly spaced space values x in the PDE\n",
" t: array of evenly spaced times values t in the PDE\n",
" f: callable function of numerical x giving a boundary condition to solution u of the PDE\n",
" g: callable function of numerical x giving a boundary condition to derivative ∂u/∂t of the PDE\n",
"\n",
" Returns:\n",
" An |t| by |x| matrix w giving approximate solutions to the PDE over the grid\n",
" imposed by arrays x and t, such that w[j, i] corresponds to u[x[i], y[j]].\n",
" \"\"\"\n",
" \n",
" n = len(t)\n",
" m = len(x)\n",
" \n",
" # TODO: The stepsize is defined by fixed h and, but the input x and t\n",
" # could allow variable step size. What should it be?\n",
" #h = x[1] - x[0]\n",
" l = x[-1]\n",
" h = l/(m - 1)\n",
" k = t[1] - t[0]\n",
" λ = a*k/h\n",
" \n",
" # Create the tri-diagonal matrix A of size (m - 2) by (m - 2).\n",
" A = np.eye(m - 2)*2*(1 - λ**2) + ( np.eye(m - 2, m - 2, 1) + np.eye(m - 2, m - 2, -1) )*λ**2\n",
" \n",
" # Create empty matrix w for the result.\n",
" w = np.zeros((n, m))\n",
" \n",
" # Set initial values for w[0, i] and w[1, i].\n",
" w[0] = f(x)\n",
" w[1, 1:m - 1] = (1 - λ**2)*f(x[1:m - 1]) + λ**2/2*f(x[2:m]) + λ**2/2*f(x[0:m - 2]) + k*g(x[1:m - 1])\n",
" \n",
" # Loop over all times t[j] to find w[j, i].\n",
" for j in range(2, n):\n",
" w[j, 1:m - 1] = np.dot(A, w[j, 1:m - 1]) - w[j - 1, 1:m - 1]\n",
" \n",
" return w"
]
},
{
"cell_type": "markdown",
"metadata": {
"deletable": false,
"editable": false,
"nbgrader": {
"cell_type": "markdown",
"checksum": "d5ee65aba16eef98296a6a66af3c0888",
"grade": false,
"grade_id": "cell-047f2dfab5489a88",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
}
},
"source": [
"### Task 2 \n",
"\n",
"Use your implementation to solve the following problems. Compare in the first problem your numerical solution to the analytic one and use it to debug your code.\n",
"\n",
"#### Problem 1:\n",
"\\begin{align*}\n",
" \\frac{\\partial^2}{\\partial t^2} u(x,t)\n",
" - \\frac{\\partial^2}{\\partial x^2} u(x,t) &= 0,\n",
" &&\\text{for }0 \\leq x \\leq 1 \\text{ and } 0 \\leq t \\leq 1\\\\\n",
" u(0,t) = u(l,t) &= 0, \n",
" &&\\text{for } t > 0 \\\\\n",
" u(x,0) &= \\operatorname{sin}\\left(2 \\pi x \\right), \\\\\n",
" \\frac{\\partial}{\\partial t} u(x,0) &= 2 \\pi \\operatorname{sin}\\left(2 \\pi x \\right)\n",
" &&\\text{for } 0 \\leq x \\leq 1.\n",
"\\end{align*}\n",
"\n",
"Compare your numerical solution to the analytic one and use it to debug your code. The corresponding analytic solution is\n",
"\n",
"\\begin{equation}\n",
" u(x,t) = \\operatorname{sin}(2 \\pi x) (\\operatorname{cos}(2 \\pi t) + \\operatorname{sin}(2 \\pi t)).\n",
"\\end{equation}\n",
"\n",
"Then write a unit test for your function based on this problem."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"deletable": false,
"nbgrader": {
"cell_type": "code",
"checksum": "17a4067a37c5edfaffd6ebffa47942d6",
"grade": true,
"grade_id": "cell-8b8cb282dfe95a03",
"locked": false,
"points": 0,
"schema_version": 3,
"solution": true,
"task": false
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"1.020779125224177\n"
]
},
{
"data": {
"text/plain": [
"[<matplotlib.lines.Line2D at 0x14c317fea760>]"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
"image/png": "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\n",
"text/plain": [
"<Figure size 432x288 with 1 Axes>"
]
},
"metadata": {
"needs_background": "light"
},
"output_type": "display_data"
}
],
"source": [
"# There is an 𝑙 in the boundary conditions we assume should be a 1. (-1 pts)\n",
"a = 1\n",
"x = np.linspace(0, 1, 300)\n",
"t = np.linspace(0, 1, 300)\n",
"f = lambda x: np.sin(2*np.pi*x)\n",
"g = lambda x: 2*np.pi*np.sin(2*np.pi*x)\n",
"\n",
"w = pdeHyperbolic(a, x, t, f, g)\n",
"u = lambda x, t: np.sin(2*np.pi*x)*(np.cos(2*np.pi*t) + np.sin(2*np.pi*t))\n",
"\n",
"#plt.plot(t[1:], w[1:, ])\n",
"sub = np.arange(1, 300)\n",
"#plt.plot(t[sub], w[sub, sub])\n",
"#plt.plot(t, u(x, t))\n",
"print(np.max(w))\n",
"\n",
"# Now we hope that w[j, i] \\approx u(x[i], t[j]).\n",
"jlist = np.arange(1, 300)\n",
"ilist = np.arange(1, 300)\n",
"\n",
"#plt.plot(t[jlist], u(x[ilist], t[jlist]))\n",
"#plt.plot(t[jlist], w[jlist, ilist])\n",
"\n",
"plt.plot(t, u(x, t))\n",
"plt.plot(t, w[np.arange(300), np.arange(300)])"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"deletable": false,
"nbgrader": {
"cell_type": "code",
"checksum": "fbb85c41f7de70517abcdc482a875fd5",
"grade": true,
"grade_id": "cell-e83b24067743e433",
"locked": false,
"points": 3,
"schema_version": 3,
"solution": true,
"task": false
}
},
"outputs": [],
"source": [
"def test_pdeHyperbolic():\n",
" # YOUR CODE HERE\n",
" raise NotImplementedError()\n",
" \n",
"test_pdeHyperbolic()"
]
},
{
"cell_type": "markdown",
"metadata": {
"deletable": false,
"editable": false,
"nbgrader": {
"cell_type": "markdown",
"checksum": "42880f6025ac92dc08f1c44a5bbf4312",
"grade": false,
"grade_id": "cell-99399435c164c96d",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
}
},
"source": [
"#### Problem 2:\n",
"\n",
"\\begin{align*}\n",
" \\frac{\\partial^2}{\\partial t^2} u(x,t)\n",
" - \\frac{\\partial^2}{\\partial x^2} u(x,t) &= 0,\n",
" &&\\text{for }0 \\leq x \\leq 1 \\text{ and } 0 \\leq t \\leq 2\\\\\n",
" u(0,t) = u(l,t) &= 0, \n",
" &&\\text{for } t > 0 \\\\\n",
" u(x,0) &= \\left\\{ \\begin{array}{cc} +1 & \\text{for } x<0.5 \\\\ -1 & \\text{for } x \\geq 0.5 \\end{array} \\right., \\\\\n",
" \\frac{\\partial}{\\partial t} u(x,0) &= 0\n",
" &&\\text{for } 0 \\leq x \\leq 1.\n",
"\\end{align*}\n",
"\n",
"Use $m=200$ and $n=400$ to discretize the spatial and time grids, respectively."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"deletable": false,
"nbgrader": {
"cell_type": "code",
"checksum": "1b6e620f32a96a23c736b827e282bc6b",
"grade": true,
"grade_id": "cell-ea865d2efbc574d6",
"locked": false,
"points": 2,
"schema_version": 3,
"solution": true,
"task": false
}
},
"outputs": [],
"source": [
"# YOUR CODE HERE\n",
"raise NotImplementedError()"
]
},
{
"cell_type": "markdown",
"metadata": {
"deletable": false,
"editable": false,
"nbgrader": {
"cell_type": "markdown",
"checksum": "3bb27614fe36d18302f4ace6442c67d9",
"grade": false,
"grade_id": "cell-a783908a0db32a24",
"locked": true,
"schema_version": 3,
"solution": false,
"task": false
}
},
"source": [
"### Task 3\n",
"\n",
"Animate your solutions! To this end you can use the following code:\n",
"\n",
"```python\n",
"\n",
"# use matplotlib's animation package\n",
"import matplotlib.pylab as plt\n",
"import matplotlib\n",
"import matplotlib.animation as animation\n",
"# set the animation style to \"jshtml\" (for the use in Jupyter)\n",
"matplotlib.rcParams['animation.html'] = 'jshtml'\n",
"\n",
"# create a figure for the animation\n",
"fig = plt.figure()\n",
"plt.grid(True)\n",
"plt.xlim( ... ) # fix x limits\n",
"plt.ylim( ... ) # fix y limits\n",
"\n",
"# Create an empty plot object and prevent its showing (we will fill it each frame)\n",
"myPlot, = plt.plot([0], [0])\n",
"plt.close()\n",
"\n",
"# This function is called each frame to generate the animation (f is the frame number)\n",
"def animate(f): \n",
" myPlot.set_data( ... ) # update plot\n",
"\n",
"# Show the animation\n",
"frames = np.arange(1, np.size(t)) # t is the time grid here\n",
"myAnimation = animation.FuncAnimation(fig, animate, frames, interval = 20)\n",
"myAnimation\n",
"\n",
"```"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"deletable": false,
"nbgrader": {
"cell_type": "code",
"checksum": "5fa181b7e8df93bd0dd35613bc553701",
"grade": true,
"grade_id": "cell-0bd05d93759bd652",
"locked": false,
"points": 3,
"schema_version": 3,
"solution": true,
"task": false
}
},
"outputs": [],
"source": [
"# Animate problem 1 here ...\n",
"\n",
"# YOUR CODE HERE\n",
"raise NotImplementedError()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"deletable": false,
"nbgrader": {
"cell_type": "code",
"checksum": "d4f93f8615bd3576e0248a27d5c1d664",
"grade": true,
"grade_id": "cell-43b3222743c428f5",
"locked": false,
"points": 0,
"schema_version": 3,
"solution": true,
"task": false
}
},
"outputs": [],
"source": [
"# Animate problem 2 here ...\n",
"\n",
"# YOUR CODE HERE\n",
"raise NotImplementedError()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"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.8.10"
}
},
"nbformat": 4,
"nbformat_minor": 4
}