{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Vibrations modes of a hanging chain using the Ritz method\n", "\n", "The equation of the vibration of a hanging chain\n", "\n", "$$\\mu\\frac{\\partial^2}{\\partial t^2} u(z, t) = \\frac{\\partial}{\\partial z}\\left(gz\\frac{\\partial}{\\partial z}u(z,t)\\right)$$\n", "\n", "If we assume a solution of the form $u(z, t) = e^{i\\omega t} w(z)$, we can rewrite the\n", "differential equation as\n", "\n", "$$-k^2 w(z) = \\frac{\\partial}{\\partial z}\\left(z\\frac{\\partial}{\\partial z}w(z)\\right)$$\n", "\n", "with $k^2 = \\mu \\omega^2/g$, and $z(0)=0$, $\\partial w(L)/\\partial z = 0$.\n", "\n", "This can be written in variational form as\n", "\n", "$$J = \\int_0^L z \\left[\\frac{\\partial w}{\\partial z}\\right]^2 dz + k^2\\int_0^L w^2 dz$$" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "from sympy import *\n", "from scipy.linalg import eigh\n", "from scipy.special import jn_zeros as Jn_zeros, jn as Jn\n", "import matplotlib.pyplot as plt" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "IPython console for SymPy 1.2 (Python 3.6.6-64-bit) (ground types: gmpy)\n", "\n", "These commands were executed:\n", ">>> from __future__ import division\n", ">>> from sympy import *\n", ">>> x, y, z, t = symbols('x y z t')\n", ">>> k, m, n = symbols('k m n', integer=True)\n", ">>> f, g, h = symbols('f g h', cls=Function)\n", ">>> init_printing()\n", "\n", "Documentation can be found at http://docs.sympy.org/1.2/\n", "\n" ] } ], "source": [ "%matplotlib notebook\n", "\n", "init_session()" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "k, L = symbols('k L', positive=True)" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "def u_fun(x, m):\n", " \"\"\" Trial function. \"\"\"\n", " c = symbols('c0:%i' % m)\n", " w = (1 - z)**2 * sum(c[k]*x**k for k in range (0, m))\n", " return w, c" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/latex": [ "$$\\left(- z + 1\\right)^{2} \\left(c_{0} + c_{1} z + c_{2} z^{2} + c_{3} z^{3} + c_{4} z^{4} + c_{5} z^{5} + c_{6} z^{6} + c_{7} z^{7} + c_{8} z^{8} + c_{9} z^{9}\\right)$$" ], "text/plain": [ " 2 ⎛ 2 3 4 5 6 7 8 \n", "(-z + 1) ⋅⎝c₀ + c₁⋅z + c₂⋅z + c₃⋅z + c₄⋅z + c₅⋅z + c₆⋅z + c₇⋅z + c₈⋅z +\n", "\n", " 9⎞\n", " c₉⋅z ⎠" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "m = 10\n", "w, coef = u_fun(z, m)\n", "display(w)" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "T_inte = w**2\n", "U_inte = z*diff(w, z)**2" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [], "source": [ "T = integrate(T_inte, (z, 0, 1))\n", "U = integrate(U_inte, (z, 0, 1))" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "K = Matrix(m, m, lambda ii, jj: diff(U, coef[ii], coef[jj]))\n", "M = Matrix(m, m, lambda ii, jj: diff(T, coef[ii], coef[jj]))" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "Kn = np.array(K).astype(np.float64)\n", "Mn = np.array(M).astype(np.float64)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can compare the eigenvalues obtained using the Ritz method and the analytic ones,\n", "that are given by\n", "\n", "$$k_n = \\frac{\\alpha}{2\\sqrt{L}}\\, ,$$\n", "\n", "where $\\alpha_n$ is the $n$th zero of the Bessel function of the first kind and zero order\n", "$\\mathrm{J}_0$." ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ 1.20697368, 2.77048517, 4.34317319, 5.91785046, 7.49327331,\n", " 9.0664579 , 10.70798059, 12.66038181, 16.73615486, 23.4575171 ])" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "vals, vecs = eigh(Kn, Mn, eigvals=(0, m-1))\n", "np.sqrt(vals)" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ 1.20241278, 2.76003906, 4.32686396, 5.89576722, 7.46545885,\n", " 9.03553198, 10.60581831, 12.17623577, 13.74673957, 15.31730323])" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "lam = Jn_zeros(0, m)/2\n", "lam" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "application/javascript": [ "/* Put everything inside the global mpl namespace */\n", "window.mpl = {};\n", "\n", "\n", "mpl.get_websocket_type = function() {\n", " if (typeof(WebSocket) !== 'undefined') {\n", " return WebSocket;\n", " } else if (typeof(MozWebSocket) !== 'undefined') {\n", " return MozWebSocket;\n", " } else {\n", " alert('Your browser does not have WebSocket support.' +\n", " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", " 'Firefox 4 and 5 are also supported but you ' +\n", " 'have to enable WebSockets in about:config.');\n", " };\n", "}\n", "\n", "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n", " this.id = figure_id;\n", "\n", " this.ws = websocket;\n", "\n", " this.supports_binary = (this.ws.binaryType != undefined);\n", "\n", " if (!this.supports_binary) {\n", " var warnings = document.getElementById(\"mpl-warnings\");\n", " if (warnings) {\n", " warnings.style.display = 'block';\n", " warnings.textContent = (\n", " \"This browser does not support binary websocket messages. \" +\n", " \"Performance may be slow.\");\n", " }\n", " }\n", "\n", " this.imageObj = new Image();\n", "\n", " this.context = undefined;\n", " this.message = undefined;\n", " this.canvas = undefined;\n", " this.rubberband_canvas = undefined;\n", " this.rubberband_context = undefined;\n", " this.format_dropdown = undefined;\n", "\n", " this.image_mode = 'full';\n", "\n", " this.root = $('
');\n", " this._root_extra_style(this.root)\n", " this.root.attr('style', 'display: inline-block');\n", "\n", " $(parent_element).append(this.root);\n", "\n", " this._init_header(this);\n", " this._init_canvas(this);\n", " this._init_toolbar(this);\n", "\n", " var fig = this;\n", "\n", " this.waiting = false;\n", "\n", " this.ws.onopen = function () {\n", " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n", " fig.send_message(\"send_image_mode\", {});\n", " if (mpl.ratio != 1) {\n", " fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n", " }\n", " fig.send_message(\"refresh\", {});\n", " }\n", "\n", " this.imageObj.onload = function() {\n", " if (fig.image_mode == 'full') {\n", " // Full images could contain transparency (where diff images\n", " // almost always do), so we need to clear the canvas so that\n", " // there is no ghosting.\n", " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", " }\n", " fig.context.drawImage(fig.imageObj, 0, 0);\n", " };\n", "\n", " this.imageObj.onunload = function() {\n", " fig.ws.close();\n", " }\n", "\n", " this.ws.onmessage = this._make_on_message_function(this);\n", "\n", " this.ondownload = ondownload;\n", "}\n", "\n", "mpl.figure.prototype._init_header = function() {\n", " var titlebar = $(\n", " '
');\n", " var titletext = $(\n", " '
');\n", " titlebar.append(titletext)\n", " this.root.append(titlebar);\n", " this.header = titletext[0];\n", "}\n", "\n", "\n", "\n", "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n", "\n", "}\n", "\n", "\n", "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n", "\n", "}\n", "\n", "mpl.figure.prototype._init_canvas = function() {\n", " var fig = this;\n", "\n", " var canvas_div = $('
');\n", "\n", " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n", "\n", " function canvas_keyboard_event(event) {\n", " return fig.key_event(event, event['data']);\n", " }\n", "\n", " canvas_div.keydown('key_press', canvas_keyboard_event);\n", " canvas_div.keyup('key_release', canvas_keyboard_event);\n", " this.canvas_div = canvas_div\n", " this._canvas_extra_style(canvas_div)\n", " this.root.append(canvas_div);\n", "\n", " var canvas = $('');\n", " canvas.addClass('mpl-canvas');\n", " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n", "\n", " this.canvas = canvas[0];\n", " this.context = canvas[0].getContext(\"2d\");\n", "\n", " var backingStore = this.context.backingStorePixelRatio ||\n", "\tthis.context.webkitBackingStorePixelRatio ||\n", "\tthis.context.mozBackingStorePixelRatio ||\n", "\tthis.context.msBackingStorePixelRatio ||\n", "\tthis.context.oBackingStorePixelRatio ||\n", "\tthis.context.backingStorePixelRatio || 1;\n", "\n", " mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n", "\n", " var rubberband = $('');\n", " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n", "\n", " var pass_mouse_events = true;\n", "\n", " canvas_div.resizable({\n", " start: function(event, ui) {\n", " pass_mouse_events = false;\n", " },\n", " resize: function(event, ui) {\n", " fig.request_resize(ui.size.width, ui.size.height);\n", " },\n", " stop: function(event, ui) {\n", " pass_mouse_events = true;\n", " fig.request_resize(ui.size.width, ui.size.height);\n", " },\n", " });\n", "\n", " function mouse_event_fn(event) {\n", " if (pass_mouse_events)\n", " return fig.mouse_event(event, event['data']);\n", " }\n", "\n", " rubberband.mousedown('button_press', mouse_event_fn);\n", " rubberband.mouseup('button_release', mouse_event_fn);\n", " // Throttle sequential mouse events to 1 every 20ms.\n", " rubberband.mousemove('motion_notify', mouse_event_fn);\n", "\n", " rubberband.mouseenter('figure_enter', mouse_event_fn);\n", " rubberband.mouseleave('figure_leave', mouse_event_fn);\n", "\n", " canvas_div.on(\"wheel\", function (event) {\n", " event = event.originalEvent;\n", " event['data'] = 'scroll'\n", " if (event.deltaY < 0) {\n", " event.step = 1;\n", " } else {\n", " event.step = -1;\n", " }\n", " mouse_event_fn(event);\n", " });\n", "\n", " canvas_div.append(canvas);\n", " canvas_div.append(rubberband);\n", "\n", " this.rubberband = rubberband;\n", " this.rubberband_canvas = rubberband[0];\n", " this.rubberband_context = rubberband[0].getContext(\"2d\");\n", " this.rubberband_context.strokeStyle = \"#000000\";\n", "\n", " this._resize_canvas = function(width, height) {\n", " // Keep the size of the canvas, canvas container, and rubber band\n", " // canvas in synch.\n", " canvas_div.css('width', width)\n", " canvas_div.css('height', height)\n", "\n", " canvas.attr('width', width * mpl.ratio);\n", " canvas.attr('height', height * mpl.ratio);\n", " canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n", "\n", " rubberband.attr('width', width);\n", " rubberband.attr('height', height);\n", " }\n", "\n", " // Set the figure to an initial 600x600px, this will subsequently be updated\n", " // upon first draw.\n", " this._resize_canvas(600, 600);\n", "\n", " // Disable right mouse context menu.\n", " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n", " return false;\n", " });\n", "\n", " function set_focus () {\n", " canvas.focus();\n", " canvas_div.focus();\n", " }\n", "\n", " window.setTimeout(set_focus, 100);\n", "}\n", "\n", "mpl.figure.prototype._init_toolbar = function() {\n", " var fig = this;\n", "\n", " var nav_element = $('
')\n", " nav_element.attr('style', 'width: 100%');\n", " this.root.append(nav_element);\n", "\n", " // Define a callback function for later on.\n", " function toolbar_event(event) {\n", " return fig.toolbar_button_onclick(event['data']);\n", " }\n", " function toolbar_mouse_event(event) {\n", " return fig.toolbar_button_onmouseover(event['data']);\n", " }\n", "\n", " for(var toolbar_ind in mpl.toolbar_items) {\n", " var name = mpl.toolbar_items[toolbar_ind][0];\n", " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", " var image = mpl.toolbar_items[toolbar_ind][2];\n", " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", "\n", " if (!name) {\n", " // put a spacer in here.\n", " continue;\n", " }\n", " var button = $('