{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "Contenido bajo licencia Creative Commons BY 4.0 y código bajo licencia MIT. © Juan Gómez y Nicolás Guarín-Zapata 2020. Este material es parte del curso Modelación Computacional en el programa de Ingeniería Civil de la Universidad EAFIT." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Interpolación en 2D" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Introducción" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Acá extenderemos el esquema de interpolación unidimensional estudiado previamente al caso mas general de un dominio bidimensional. Desde el punto de vista geométrico también veremos como un **elemento finito** es solo un dominio espacial canónico descrito por puntos nodales y el correspondiente grupo de funciones de interpolación (o de **forma**).\n", "\n", "\n", "**Al completar este notebook usted debería estar en la capacidad de:**\n", "\n", "* Reconocer el problema de interpolación en dominios bidimensionales como uno de aplicación de los esquemas unidimensionales.\n", "\n", "* Formalizar el concepto de un elemento finito como un espacio de interpolación canónico con funciones de interpolación predefinidas.\n", "\n", "* Proponer esquemas de interpolación para dominios bidimensionales arbitrarios." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Dominio bidimensional\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Consideremos el dominio cuadrado mostrado en la figura y en el cual queremos aproximar, por medio de interpolación, una función escalar (o vectorial) $f=f(x,y)$. Para ese propósito los puntos negros en la figura representan puntos nodales donde asumimos que la función es conocida. En este caso el polinomio de interpolación, denotado por $p(x,y)$ se construye como:\n", "\n", "$$p(x,y) = \\sum_{Q=1}^N H_Q(x,y)f_Q$$\n", "\n", "donde $Q = 1,...,N$ para un dominio de *N* puntos nodales y donde $H_Q(x,y)$ son las funciones de interpolación o funciones de forma.\n", "\n", "\n", "Como se detallará a continuación para construir las funciones de interpolación bidimensionales $ H_Q(x,y)$ en realidad aplicamos un proceso de interpolaciones unidimensionales iteradas.\n", "\n", "Denotemos como $x_A$ y $x_B$ a las coordenadas de los puntos A y B en el dominio cuadrilátero mostrado en la figura y supongamos que queremos encontrar el valor de la función en el punto A." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", " \"Dominio\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "El punto A tiene una coordenada en $y$ que es arbitraria pero una coordenada en $x$ constante correspondiente a $x = x_A$ de manera que para un punto A arbitrario a lo largo de la dirección 1-4 (ver figura) el esquema de interpolación es aún unidimensional solamente con dependencia en $y$ y expresado como $f(y , x= A)$ en la figura. Usando polinomios de interpolación de Lagrange unidimensionales la dependencia en $y$ puede ser capturada por:\n", "\n", "$$f(x_A , y) = L_1(y) f_1 + L_4(y) f_4$$\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", " \"Corte\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Procediendo de manera similar para un punto arbitrario $B$ a lo largo de la dirección 2-3 se tiene que:\n", "\n", "$$f(x_B, y) = L_2(y) f_2 + L_3(y) f_3\\, .$$\n", "\n", "con $f_A$ y $f_B$ conocidos la dependencia en $x$ puede capturarse como:\n", "\n", "$$f(x, y) = L_A(x) f(x_A, y) + L_B(x)f(x_B, y)\\, .$$\n", "\n", "Para llegar a la forma final de las funciones de forma bidimensionales calculamos los polinomios $L_2(y)$, $L_3(y)$, $ L_A(x)$ y $L_B(x)$ y los reemplazamos en las expresiones anteriores. En el caso de un elemento de lado $2.0$ las funciones son:\n", "\n", "\\begin{align*}\n", "H_1(x,y) & = L_1(x)L_1(y) \\equiv \\frac{1}{4}(1-x)(1-y)\\, ,\\\\\n", "H_2(x,y) & = L_2(x)L_1(y) \\equiv \\frac{1}{4}(1+x)(1-y)\\, ,\\\\\n", "H_3(x,y) & = L_2(x)L_2(y) \\equiv \\frac{1}{4}(1+x)(1+y)\\, ,\\\\\n", "H_4(x,y) & = L_1(x)L_2(y) \\equiv \\frac{1}{4}(1-x)(1+y)\\, .\n", "\\end{align*}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Elemento finito canónico\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "En la siguiente subrutina codificamos la forma final $H_Q(x,y)$ de las funciones de forma en vez de calcular directamente los polinomios fundamentales en una dimensión de la forma $L_I(y)$ para posteriormente realizar la interpolación iterada. La subrutina llamada ``sha4`` almacena las funciones en una estructura matricial que depende de $x$ e $y$. Asumimos que el elemento es un cuadradado perfecto de lado $\\mathcal{l}=2.0$ con puntos nodales en las esquinas correspondiente a una interpolación lineal a lo largo de cada cara." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "import matplotlib.pyplot as plt\n", "import sympy as sym" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "%matplotlib notebook\n", "sym.init_printing()" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "def sha4(x, y):\n", " \"\"\"\n", " Compute the shape functions for bi-linear\n", " square element of size 2.0.\n", " \"\"\"\n", " sh = sym.Matrix([[\n", " (1 - x)*(1 - y),\n", " (1 + x)*(1 - y),\n", " (1 + x)*(1 + y),\n", " (1 - x)*(1 + y)]])/4\n", " return sh" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Este elemento cuadrado es un elemento **canónico** o de referencia en el cual es fácil la realización de las operaciones de interpolación. En una malla real de elementos finitos es de esperar que los elementos estén distorsionados en relación con este elemento canónico. En esos casos la interpolación también se realiza en el espacio del elemento canónico pero ahora tanto la geometría como las funciones son transformadas usando operaciones matemáticas. Estos detalles sin embargo no se discutirán acá.\n", "\n", "Las funciones de forma almacenadas en la subrutina corresponden a:\n", "\n", "$$H = \\frac{1}{4}\\begin{bmatrix}(1-x)(1-y)&(1+x)(1-y)&(1+x)(1+y)&(1-x)(1+y)\\end{bmatrix}$$\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "**Preguntas**\n", " \n", "- Escriba las funciones de forma asumiendo que el sub-dominio el mismo cuadrado discutido hasta el momento, pero además de los nodos de la esquina también incluye nodos en la mitad de las caras para completar un total de 8 puntos nodales.\n", "\n", "- Haga una copia de la subrutina `sha4` y modifíquela para que calcule las funciones de forma para el elemento de 8 nodos.\n", "
" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/latex": [ "$\\displaystyle \\left[\\begin{matrix}\\frac{\\left(1 - x\\right) \\left(1 - y\\right)}{4} & \\frac{\\left(1 - y\\right) \\left(x + 1\\right)}{4} & \\frac{\\left(x + 1\\right) \\left(y + 1\\right)}{4} & \\frac{\\left(1 - x\\right) \\left(y + 1\\right)}{4}\\end{matrix}\\right]$" ], "text/plain": [ "⎡(1 - x)⋅(1 - y) (1 - y)⋅(x + 1) (x + 1)⋅(y + 1) (1 - x)⋅(y + 1)⎤\n", "⎢─────────────── ─────────────── ─────────────── ───────────────⎥\n", "⎣ 4 4 4 4 ⎦" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "x, y= sym.symbols('x y')\n", "H = sha4(x, y)\n", "display(H)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Interpolación en un dominio cuadrado" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "En este paso consideramos un elemento cuadrado conformado por 4 puntos nodales localizados en las esquinas y donde se asumen conocidos los valores de la función. Usaremos estos valores, conjuntamente con las funciones de forma para encontrar un polinomio de interpolación. El polinomio resultante se usa posteriormente para generar valores aproximados de la función en una serie de puntos que conforman una grilla usada para visualizar la solución. La grilla de puntos de observación se genera usando la función `mgrid` de `numpy`.\n", "\n", "Note que el sistema de referencia se localiza en el centro del elemento por lo tanto $x \\in [-1, 1]$ and $y \\in [-1, 1]$. El arreglo unidimensional `u_interp` almacenará los valores interpolados en cada punto de la grilla.\n", "\n", "Para realizar la interpolación asumiremos valores nodales de la función en un punto dado $(x , y)$ de manera que podemos obtener el valor interpolado como:\n", "\n", "$$u(x,y)\\;=\\;\\left[H(x,y)\\right]\\left\\{u\\right\\}$$" ] }, { "cell_type": "code", "execution_count": 5, "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 = $('