{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "raw_mimetype": "text/latex"
   },
   "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": [
    "# Pórticos planos"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Introducción"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "En este Notebook se agrega un elemento adicional al programa de análisis estructural, iniciado con el problema simple de resortes unidimesionales y extendido para considerar armaduras planas. En particular, ahora se adicionan elementos tipo viga para abordar problemas en los cuales los elementos funcionen principalmente a flexión. Adicionalmente, en una implementación independiente, es posible acoplar el comportamiento a carga axial de la cercha con el comportamiento a flexión de la viga.\n",
    "\n",
    "El modelo de viga que se discute en este notebook corresponde a un modelo de Euler-Bernoulli en el cual se desprecian las deformaciones por cortante y por lo tanto válido para elementos con secciones transversales de baja esbeltez.\n",
    "\n",
    "**Al completar este notebook usted debería estar en la capacidad de:**\n",
    "\n",
    "* Reconocer las modificaciones necesarias para convertir un programa fundamental de ensamblaje de resortes en uno para estructuras conformadas por vigas.\n",
    "\n",
    "* Resolver problemas simples de estructuras conformadas por vigas sometidas a cargas puntuales."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Ensamblaje de elementos tipo viga"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Consideremos un elemento tipo viga en su sistema local de referencia como el mostrado en la figura. En el sistema local el elemento tiene 2 grados de libertad por nodo, correspondientes al desplazamiento transversal y una rotación con respecto a un eje perpendicular al plano de la imagen.\n",
    "\n",
    "<center>\n",
    "    <img src=\"img/viga_local.svg\"\n",
    "         alt=\"Viga en el sistema de referencia local\"\n",
    "         style=\"width:400px\">\n",
    "</center>\n",
    "\n",
    "El vector de grados de libertad (o desplazamientos generalizados) del elemento es:\n",
    "\n",
    "$$\n",
    "u^T=\\begin{bmatrix}v_1 &\\theta_1 &v_2 &\\theta_2\\end{bmatrix}\n",
    "$$\n",
    "\n",
    "mientras que el vector de fuerza (momentos y cortantes) esta dado por:\n",
    "\n",
    "$$\n",
    "f^T=\\begin{bmatrix}f_1 &m_1 &f_2 &m_2\\end{bmatrix}\n",
    "$$\n",
    "\n",
    "\n",
    "En el sistema de referencia local la matriz de rigidez relacionando fuerzas con desplazamientos es:\n",
    "\n",
    "$$\n",
    "\\begin{Bmatrix} f_1\\\\ m_1\\\\ f_2\\\\ m_2\\end{Bmatrix} =\n",
    "\\begin{bmatrix}\n",
    "12\\frac{EI}{\\mathcal l^3} &6\\frac{EI}{\\mathcal l^3} &-12\\frac{EI}{\\mathcal l^3} &6\\frac{EI}{\\mathcal l^2}\\\\\n",
    "6\\frac{EI}{\\mathcal l^3}&4\\frac{EI}{\\mathcal l}&-6\\frac{EI}{\\mathcal l^2}&2\\frac{EI}{\\mathcal l}\\\\\n",
    "12\\frac{EI}{\\mathcal l^3}&-6\\frac{EI}{\\mathcal l^2}&12\\frac{EI}{\\mathcal l^3}&-6\\frac{EI}{\\mathcal l^2}\\\\\n",
    "6\\frac{EI}{\\mathcal l^2}&2\\frac{EI}{\\mathcal l}&-6\\frac{EI}{\\mathcal l^2}&4\\frac{EI}{\\mathcal l}\n",
    "\\end{bmatrix}\n",
    "\\begin{Bmatrix} v_1\\\\ \\theta_1\\\\ v_2\\\\ \\theta_2\\end{Bmatrix}\n",
    "$$\n",
    "\n",
    "\n",
    "\n",
    "\n",
    "<div class=\"alert alert-warning\">\n",
    "\n",
    "**Nota:** La matriz de rigidez puede formularse por diferentes métodos que serán cubiertos en el curso de Análisis de Estructuras.\n",
    "\n",
    "</div>\n",
    "\n",
    "Para obtener la matriz de rigidez global de la estructura es necesario considerar nuevamente la contribución de todos los elementos en el sistema **global** de referencia. Con ese propósito procedemos como con el problema de la cercha. Usando la matriz de transformación bajo rotación $\\lambda$ se tiene que:\n",
    "\n",
    "$$K = \\lambda^T k\\lambda$$\n",
    "\n",
    "donde $K$ es la matriz de rigidez para el elemento tipo viga en el sistema global de referencia. Note que en este sistema el elemento tiene ahora 3 grados de libertad por nodo."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Estructura aporticada simple"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Considere el siguiente modelo simple conformado por un ensamblaje de 3 elementos. (Los archivos de datos de entrada están disponibles en la carpeta `files`).\n",
    "\n",
    "<center>\n",
    "    <img src=\"img/portico_ejemplo.svg\"\n",
    "         alt=\"Esquema de la estructura del ejemplo.\"\n",
    "         style=\"width:500px\">\n",
    "</center>\n",
    "\n",
    "Se requiere determinar el desplazamiento lateral de la estructura cuando es sometida a la carga lateral $P$.\n",
    "\n",
    "<div class=\"alert alert-warning\">\n",
    "\n",
    "Encuentre la matriz de transformación bajo rotación $\\lambda$ requerida para la formulación de la matriz de rigidez en el sistema de referencia global.\n",
    "\n",
    "</div>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Las modificacions que se deben aplicar al código de resortes (o al de cerchas) solo estan relacionadas con el hecho de que ahora hay 3 grados de libertad en cada nodo."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "import sympy as sym"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Lea los archivos de entrada de la carpeta `files`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "def readin():\n",
    "    nodes = np.loadtxt('files/Fnodes.txt', ndmin=2)\n",
    "    mats = np.loadtxt('files/Fmater.txt', ndmin=2)\n",
    "    elements = np.loadtxt('files/Feles.txt', ndmin=2)\n",
    "    loads = np.loadtxt('files/Floads.txt', ndmin=2)\n",
    "    return nodes, mats, elements, loads"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "La función `eqcounter` cuenta ecuaciones y genera el arreglo de condiciones de frontera."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "def eqcounter(nodes):\n",
    "    nnodes = nodes.shape[0]\n",
    "    IBC = np.zeros([nnodes, 3], dtype=np.integer)\n",
    "    for i in range(nnodes):\n",
    "        for k in range(3):\n",
    "            IBC[i, k] = int(nodes[i, k+3])\n",
    "    neq = 0\n",
    "    for i in range(nnodes):\n",
    "        for j in range(3):\n",
    "            if IBC[i, j] == 0:\n",
    "                IBC[i, j] = neq\n",
    "                neq = neq + 1\n",
    "    return neq, IBC"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Ahora, la función `DME` calcula la matriz de ensamblaje de ecuaciones."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "def DME(nodes, elements):\n",
    "\n",
    "    nels = elements.shape[0]\n",
    "    IELCON = np.zeros([nels, 2], dtype=np.integer)\n",
    "    DME_mat = np.zeros([nels, 6], dtype=np.integer)\n",
    "    neq, IBC = eqcounter(nodes)\n",
    "    ndof = 6\n",
    "    nnodes = 2\n",
    "    for i in range(nels):\n",
    "        for j in range(nnodes):\n",
    "            IELCON[i, j] = elements[i, j+3]\n",
    "            kk = IELCON[i, j]\n",
    "            for l in range(3):\n",
    "                DME_mat[i, 3*j+l] = IBC[kk, l]\n",
    "    return DME_mat, IBC, neq"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "La función `assembly` usa el modelo y la matriz `DME_mat` para calcular la matriz de rigidez global."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "def assembly(elements, mats, nodes, neq, DME_mat):\n",
    "    IELCON = np.zeros([2], dtype=np.integer)\n",
    "    KG = np.zeros((neq, neq))\n",
    "    nels = elements.shape[0]\n",
    "    nnodes = 2\n",
    "    ndof = 6\n",
    "    for el in range(nels):\n",
    "        elcoor = np.zeros([nnodes, 2])\n",
    "        im = np.int(elements[el, 2])\n",
    "        par0 = mats[im, 0]\n",
    "        par1 = mats[im, 1]\n",
    "        for j in range(nnodes):\n",
    "            IELCON[j] = elements[el, j+3]\n",
    "            elcoor[j, 0] = nodes[IELCON[j], 1]\n",
    "            elcoor[j, 1] = nodes[IELCON[j], 2]\n",
    "        kloc = uelbeam2DU(elcoor, par0, par1)\n",
    "        dme = DME_mat[el, :ndof]\n",
    "        for row in range(ndof):\n",
    "            glob_row = dme[row]\n",
    "            if glob_row != -1:\n",
    "                for col in range(ndof):\n",
    "                    glob_col = dme[col]\n",
    "                    if glob_col != -1:\n",
    "                        KG[glob_row, glob_col] = KG[glob_row, glob_col] +\\\n",
    "                            kloc[row, col]\n",
    "    return KG"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "La función `uelbeam2D` usa las coordenadas de los nodos y los parámetros de material para calcular la matriz de rigidez local ya transformada al sistema de referencia global.\n",
    "\n",
    "\n",
    "<div class=\"alert alert-warning\">\n",
    "    \n",
    "Agregue un comentario a cada línea relevante de los códigos de las siguientes funciones y úselos para escribir los pseudocódigos correspondientes. En particular identifique el calculo de la matriz de transformación bajo rotación $\\lambda$.\n",
    "\n",
    "</div>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "def uelbeam2DU(coord, I, Emod):\n",
    "    \"\"\"2D-2-noded beam element\n",
    "       without axial deformation\n",
    "\n",
    "    Parametros\n",
    "    ----------\n",
    "    coord : ndarray\n",
    "      Cordenadas nodales (2, 2).\n",
    "    A : float\n",
    "      Area de la seccion transversal.\n",
    "    Emod : float\n",
    "      Modulo de elasticidad (>0).\n",
    "\n",
    "    Returna\n",
    "    -------\n",
    "    kl : ndarray\n",
    "      Matriz de rigidez local para el elemento (4, 4).\n",
    "\n",
    "    \"\"\"\n",
    "    vec = coord[1, :] - coord[0, :]\n",
    "    nx = vec[0]/np.linalg.norm(vec)\n",
    "    ny = vec[1]/np.linalg.norm(vec)\n",
    "    L = np.linalg.norm(vec)\n",
    "    Q = np.array([\n",
    "        [-ny, nx, 0,  0,  0, 0],\n",
    "        [0,  0, 1.0,  0,  0, 0],\n",
    "        [0,  0, 0, -ny, nx, 0],\n",
    "        [0,  0, 0,  0,  0, 1.0]])\n",
    "    kl = (I*Emod/(L*L*L)) * np.array([\n",
    "        [12.0, 6, -12.0, 6*L],\n",
    "        [6,  4*L*L, -6*L, 2*L*L],\n",
    "        [-12.0,  -6*L, 12.0, -6*L],\n",
    "        [6*L,  2*L*L, -6*L, 4*L*L]])\n",
    "    kG = np.dot(np.dot(Q.T, kl), Q)\n",
    "    return kG"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "La rutina `loadassem` forma el vector de cargas en los nodos."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "def loadasem(loads, IBC, neq, nl):\n",
    "    RHSG = np.zeros([neq])\n",
    "    for i in range(nl):\n",
    "        il = int(loads[i, 0])\n",
    "        ilx = IBC[il, 0]\n",
    "        ily = IBC[il, 1]\n",
    "        ilT = IBC[il, 2]\n",
    "        if ilx != -1:\n",
    "            RHSG[ilx] = loads[i, 1]\n",
    "        if ily != -1:\n",
    "            RHSG[ily] = loads[i, 2]\n",
    "        if ilT != -1:\n",
    "            RHSG[ilT] = loads[i, 3]\n",
    "    return RHSG"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "El programa principal mantiene la misma estructura que el programa de resortes, es decir, se tienen siguientes pasos:\n",
    "\n",
    "* Lee el modelo.\n",
    "\n",
    "* Determina la matriz de ensamblaje `DME_mat`.\n",
    "\n",
    "* Ensambla el sistema global de ecuaciones.\n",
    "\n",
    "* Determina los desplazamientos globales `UG` tras resolver el sistema global."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 2.25000000e+01  2.00000000e+01  1.27557539e-16 -1.25918779e-15\n",
      "  2.00000000e+01  4.88970566e-16]\n"
     ]
    }
   ],
   "source": [
    "nodes, mats, elements, loads = readin()\n",
    "DME_mat, IBC, neq = DME(nodes, elements)\n",
    "KG = assembly(elements, mats, nodes, neq, DME_mat)\n",
    "RHSG = loadasem(loads, IBC, neq, 1)\n",
    "UG = np.linalg.solve(KG, RHSG)\n",
    "print(UG)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div class=\"alert alert-warning\">\n",
    "    \n",
    "### Problemas propuestos\n",
    "\n",
    "#### Problema 1\n",
    "\n",
    "Implemente una función que calcule las fuerzas nodales en cada elemento y que verifique el equilibrio del sistema.\n",
    "\n",
    "#### Problema 2\n",
    "\n",
    "Determine la rigidez lateral de la estructura usando la siguiente expresión:\n",
    "\n",
    "$$k = \\frac{P}{\\delta}\\, .$$\n",
    "\n",
    "#### Problema 3\n",
    "\n",
    "Repotencie la estructura de tal forma que la rigidez lateral se incremente por un factor de 2.0\n",
    "\n",
    "#### Problema 4\n",
    "\n",
    "Repare el pórtico mostrado en la figura adicionando elementos y/o imponiendo restricciones apropiadas a los desplazamientos. (Cree un nuevo paquete de archivos de datos).\n",
    "\n",
    "#### Problema 5\n",
    "\n",
    "Para el portico de la figura asuma que la conexión del nudo 5 es articulada e indique como esta condición cambia los resultados.\n",
    "\n",
    "<center>\n",
    "    <img src=\"img/portico_ejercicio.svg\"\n",
    "         alt=\"Esquema del pórtico para el ejercicio propuesto.\"\n",
    "         style=\"width:500px\">\n",
    "</center>\n",
    "\n",
    "</div>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Referencias"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "* Bathe, Klaus-Jürgen. (2006) Finite element procedures. Klaus-Jurgen Bathe. Prentice Hall International.\n",
    "\n",
    "* Juan Gómez, Nicolás Guarín-Zapata (2018). SolidsPy: 2D-Finite Element Analysis with Python, <https://github.com/AppliedMechanics-EAFIT/SolidsPy>."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Formato del notebook"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "La siguiente celda cambia el formato del Notebook."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "\n",
       "<link href='http://fonts.googleapis.com/css?family=Fenix' rel='stylesheet' type='text/css'>\n",
       "<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=Source+Code+Pro:300,400' rel='stylesheet' type='text/css'>\n",
       "\n",
       "<style>\n",
       "\n",
       "/*\n",
       "Template for Notebooks for Modelación computacional.\n",
       "\n",
       "Based on Lorena Barba template available at:\n",
       "\n",
       "    https://github.com/barbagroup/AeroPython/blob/master/styles/custom.css\n",
       "*/\n",
       "\n",
       "/* Fonts */\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",
       "/* Text */\n",
       "div.cell{\n",
       "width:800px;\n",
       "margin-left:16% !important;\n",
       "margin-right:auto;\n",
       "}\n",
       "h1 {\n",
       "font-family: 'Alegreya Sans', sans-serif;\n",
       "}\n",
       "h2 {\n",
       "font-family: 'Fenix', serif;\n",
       "}\n",
       "h3{\n",
       "font-family: 'Fenix', serif;\n",
       "margin-top:12px;\n",
       "margin-bottom: 3px;\n",
       "}\n",
       "h4{\n",
       "font-family: 'Fenix', serif;\n",
       "}\n",
       "h5 {\n",
       "font-family: 'Alegreya Sans', sans-serif;\n",
       "}\t\n",
       "div.text_cell_render{\n",
       "font-family: 'Alegreya Sans',Computer Modern, \"Helvetica Neue\", Arial, Helvetica, Geneva, sans-serif;\n",
       "line-height: 135%;\n",
       "font-size: 120%;\n",
       "width:600px;\n",
       "margin-left:auto;\n",
       "margin-right:auto;\n",
       "}\n",
       ".CodeMirror{\n",
       "font-family: \"Source Code Pro\";\n",
       "font-size: 90%;\n",
       "}\n",
       "/* .prompt{\n",
       "display: None;\n",
       "}*/\n",
       ".text_cell_render h1 {\n",
       "font-weight: 200;\n",
       "font-size: 50pt;\n",
       "line-height: 100%;\n",
       "color:#CD2305;\n",
       "margin-bottom: 0.5em;\n",
       "margin-top: 0.5em;\n",
       "display: block;\n",
       "}\t\n",
       ".text_cell_render h5 {\n",
       "font-weight: 300;\n",
       "font-size: 16pt;\n",
       "color: #CD2305;\n",
       "font-style: italic;\n",
       "margin-bottom: .5em;\n",
       "margin-top: 0.5em;\n",
       "display: block;\n",
       "}\n",
       ".warning{\n",
       "color: rgb( 240, 20, 20 )\n",
       "}\n",
       "</style>\n",
       "\n",
       "<script>\n",
       "/* Equations */\n",
       "\n",
       "MathJax.Hub.Config({\n",
       "TeX: {\n",
       "extensions: [\"AMSmath.js\"]\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",
       "</script>\n",
       "\n",
       "\n"
      ],
      "text/plain": [
       "<IPython.core.display.HTML object>"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from IPython.core.display import HTML\n",
    "def css_styling():\n",
    "    styles = open('./nb_style.css', 'r').read()\n",
    "    return HTML(styles)\n",
    "css_styling()"
   ]
  }
 ],
 "metadata": {
  "celltoolbar": "Raw Cell Format",
  "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.7.3"
  },
  "varInspector": {
   "cols": {
    "lenName": 16,
    "lenType": 16,
    "lenVar": 40
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}