{ "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": [ "# Ensamblaje de la matriz global" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Este notebook explica cómo construir el sistema de ecuaciones para un sistema de masas y resortes, proceso que suele denominarse **ensamblaje** de ecuaciones. Para ello, se presenta un ejemplo paso a paso en el que se calculan las matrices de rigidez de cada elemento y luego se suman (ensamblan) a la matriz global.\n", "\n", "Adicionalmente, el [notebook auxiliar](./06c_ensamble_paso_a_paso.ipynb) presenta de manera automática las matrices de rigidez locales para cada elemento y la matriz de rigidez global luego de ensamblar el elemento correspondiente.\n", "\n", "**Nota:** Este notebook utiliza los mismos archivos de texto del sistema de resortes del notebook principal y disponibles en la carpeta `files` del repositorio. Para poder continuar con el resto del notebook es necesario que estos archivos estén disponibles en memoria." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import numpy as np" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "def readin():\n", " nodes = np.loadtxt('files/sprnodes.txt', ndmin=2)\n", " mats = np.loadtxt('files/sprmater.txt', ndmin=2)\n", " elements = np.loadtxt('files/spreles.txt', ndmin=2, dtype=np.int)\n", " loads = np.loadtxt('files/sprloads.txt', ndmin=2)\n", " return nodes, mats, elements, loads" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Introducción" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "En este notebook se describen los detalles del proceso de **ensamblaje** de la matriz de rigidez global en el cual se suma la contribución de cada uno de los resortes. Mientras mas elementos se sumen, mas rígido será el sistema resultante. El proceso simplemente obtiene la \"dirección\" en la matriz de rigidez global en la que se deben ubicar los diferentes valores de las matrices locales de cada uno de los resortes. Estas direcciones se encuentran almacenadas, en forma de numero de ecuación, en un arreglo que tiene tantas filas como resortes tenga el sistema.\n", "\n", "**Al completar este notebook usted debería estar en la capacidad de:**\n", "\n", "* Entender el papel que desempeñan en el programa los arreglos de condiciones de frontera, de conectividades y de ensamblaje de ecuaciones, `IBC`, `IELCON` y `DME_mat` respectivamente.\n", "\n", "* Entender los detalles del algoritmo de ensamblaje de matrices de rigidez globales." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Sistema estructural = sistema de ecuaciones" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Todo programa de análisis estructural basado en el método de rigidez resuelve un sistema de ecuaciones de la forma general\n", "\n", "$$[K_G] \\{U_G\\} = \\{F_G\\}\\, ,$$\n", "\n", "en el que $[K_G]$ es la matriz de coeficientes del sistema y representa la rigidez de toda la estructura, la cual resulta del aporte de todos los elementos del sistema; $\\{U_G\\}$ es el vector de desplazamientos (o grados de libertad) del sistema; y $\\{F_G\\}$ es el vector de fuerzas externas aplicadas al sistema.\n", "\n", "Una vez resuelto el sistema de ecuaciones y se determinen los desplazamiento es posible usar relaciones fuerza-desplazamiento para cada elemento y determinar así las fuerzas internas. En las secciones que siguen se explican los pasos necesarios para armar el sistema de ecuaciones en un programa típico de análisis estructural. A esta operación se le conoce como **ensamblaje** del sistema." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Estructura de un programa y arreglos fundamentales" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Considere el sistema masa-resortes discutido en el Notebook principal y mostrado nuevamente en la figura. En esta sección discutiremos solamente el proceso de ensamblaje de la de matriz rigidez global mediante la suma de las contribuciones de las rigideces de cada uno de los resortes.\n", "\n", "En la figura los números encerrados en hexágonos azules representan masas o puntos de conexión de resortes, también denominados nodos. En el sistema del ejemplo el nodo $0$ se encuentra \"amarrado\" y por ende no puede desplazarse, impidiendo a la vez que bajo la acción de cargas el sistema se desplace como un cuerpo rígido.\n", "\n", "\n", "<center>\n", " <img src=\"img/sisfull.png\"\n", " alt=\"Sistema masa resorte\"\n", " style=\"width:500px\">\n", "</center>\n", "\n", "Además, hemos nombrado los resortes con letras para facilitar la explicación. Para referirnos a los elementos de la matriz local de cada resorte usaremos subíndices para denotar la posición del elemento en la matriz local y un superíndice para indicar el nombre del resorte al que pertenece el elemento. Por ejemplo la matriz de rigidez local del resorte $A$ la representaremos como:\n", "\n", "$$\n", "k^A=k\\begin{bmatrix}\n", "1 &-1\\\\\n", "-1 &1\n", "\\end{bmatrix}\n", "\\equiv\\begin{bmatrix}\n", "k_{00}^A &k_{01}^A\\\\\n", "k_{10}^A &k_{11}^A\n", "\\end{bmatrix}\n", "$$\n", "\n", "de manera que $k_{01}^A$ hace referencia a un coeficiente de rigidez que pertenece al resorte $A$ y que en su matriz local esta ubicado en la fila $0$ columna $1$. Nótese, además, que hemos iniciado el conteo de elementos desde $0$ para ser consistentes con lo usado en Python.\n", "\n", "El objetivo del ejemplo es indicar en que posiciones de la matriz global o del sistema de ecuaciones debemos colocar los elementos de las matrices de cada resorte.\n", "\n", "Para realizar el ensamblaje necesitamos usar varios arreglos que se explican a continuación." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Arreglo de identificadores de ecuaciones: `IBC`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "El arreglo de ecuaciones `IBC` contiene los identificadores de las ecuaciones asignadas a cada nodo o masa. Los nodos que se encuentren restringidos no tendrán ecuación asignada (pues su valor, nulo, es conocido) mientras que a cada nodo cuyo desplazamiento sea desconocido se le asignará un numero de ecuación. En este caso esta información se especifica al programa mediante un código que indica si el nodo se puede desplazar (valor de $0$) o si se encuentra restringido (valor de $-1$). Esta información hace parte del modelo y se encuentra en el archivo de nodos. El programa extrae estos códigos del archivo de nodos y los pasa a una primera versión del arreglo `IBC`. Este tendrá tantas filas como nodos y tantas columnas como grados de libertad tenga el problema. En este ejemplo cada nodo podrá tener asignado un solo grado de libertad.\n", "\n", "<div class=\"alert alert-warning\">\n", "\n", "En el archivo de nodos del presente ejemplo identifique donde se especifica la información de ecuaciones asignadas a cada nodo. Compare este información contra el sistema mostrado en la figura.\n", "\n", "</div>\n", "\n", "Posteriormente, la función `eqcounter()` utiliza la primera versión del arreglo `IBC` y asigna números de ecuaciones a los grados de libertad activos (indicados por código 0) y los almacena en el mismo arreglo `IBC`. En otras palabras, esta función cambia los ceros por números de ecuaciones.\n", "\n", "Por ejemplo, el nodo $0$ se encuentra restringido como se indica con el valor de $-1$. Por lo tanto, a este nodo no se le asignará una ecuación. Por su parte, el nodo 1 tiene asignado un valor de $0$ y a este se le asignará el primer número de ecuación correspondiente también a $0$. Siguiendo con el conteo, el nodo 2 también tiene asignado un valor de $0$ y dado que es el siguiente nodo en la lista al mismo se le asignará la ecuación $1$.\n", "\n", "<center>\n", " <img src=\"img/ibcarray.png\"\n", " alt=\"Arreglo indicador de ecuaciones\"\n", " style=\"width:400px\">\n", "</center>\n", "\n", "La rutina es la siguiente." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "def eqcounter(nodes):\n", " nn = nodes.shape[0]\n", " IBC = np.zeros((nn, 1), dtype=np.integer)\n", " neq = 0\n", " for cont in range(nn):\n", " IBC[cont] = int(nodes[cont, 2])\n", " if IBC[cont] == 0:\n", " IBC[cont] = neq\n", " neq = neq + 1\n", " return neq, IBC" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([[-1],\n", " [ 0],\n", " [ 1],\n", " [ 2]])" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "nodes, mats, elements, loads = readin()\n", "neq, IBC = eqcounter(nodes)\n", "IBC" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Arreglo de conectividades de los elementos: `IELCON`\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "El siguiente arreglo necesario en el proceso es el arreglo que almacena los nodos a los que está conectado cada resorte. En el lenguaje comúnmente usado en el método de rigideces, a los nodos que definen un resorte se le conocen como las **conectividades** del elemento. En este programa nos referiremos al arreglo de conectividades como `IELCON`. Nuevamente, note que cada fila del arreglo almacena la información de un elemento. Por ejemplo, según la información almacenada en `IELCON` el resorte B está definido por los nodos 1 y 2.\n", "\n", "<center>\n", " <img src=\"img/ielcon2.png\"\n", " alt=\"Arreglo de conectividades\"\n", " style=\"width:200px\">\n", "</center>\n", "\n", "<div class=\"alert alert-warning\">\n", " \n", "En el archivo de elementos del presente ejemplo identifique donde se especifica la información de conectividades de cada elemento. Compare este información contra el sistema del ejemplo.\n", "\n", "</div>" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Arreglo de ensamblaje: `DME_mat`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "El siguiente paso en el proceso es la creación de la matriz ensambladora denominada como `DME_mat`. Este arreglo es una combinación del arreglo de conectividades `IELCON` y del arreglo de ecuaciones nodales `IBC`.\n", "\n", "Cada fila de esta matriz contiene los identificadores de ecuaciones asociados con cada uno de los nodos del elemento y será la que indique como distribuir los diferentes elementos de las matrices locales en la matriz global.\n", "\n", "Para formar esta matriz se recorre un elemento a la vez el arreglo de conectividades `IELCON`; se identifican los nodos correspondientes a cada elemento y posteriormente se extraen las ecuaciones correspondientes a cada uno de estos nodos del arreglo `IBC`.\n", "\n", "<center>\n", " <img src=\"img/dmefull.png\"\n", " alt=\"Arreglo de ensamblaje\"\n", " style=\"width:200px\">\n", "</center>\n", "\n", "\n", "El siguiente bloque de código ensambla la matriz `DME_mat`." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "def DME(nodes, elements):\n", " nels = elements.shape[0]\n", " DME_mat = np.zeros((nels, 2), dtype=np.integer)\n", " neq, IBC = eqcounter(nodes)\n", " ndof = 2\n", " nnodes = 2\n", " for ele in range(nels):\n", " for node in range(nnodes):\n", " pos = elements[ele, node + 3]\n", " DME_mat[ele, node] = IBC[pos]\n", " return DME_mat, IBC, neq" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[-1 0]\n", " [ 0 1]\n", " [ 0 1]\n", " [ 1 2]]\n" ] } ], "source": [ "DME_mat, IBC, neq = DME(nodes, elements)\n", "print(DME_mat)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Localización de la matriz de un elemento en la matriz global" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "En el proceso de ensamble cada elemento de la matriz local es colocado en la dirección de la matriz global extraída del arreglo `DME_mat`.\n", "\n", "<center>\n", " <img src=\"img/assexa.png\"\n", " alt=\"Mapeo de enumeración local a global\"\n", " style=\"width:600px\">\n", "</center>\n", "\n", "\n", "La matriz resultante para el problema del ejemplo se muestra en la figura y en lo que sigue se muestra el proceso paso a paso.\n", "\n", "\n", "<center>\n", " <img src=\"img/kmatrixfull.png\"\n", " alt=\"Matriz después de ensamblar\"\n", " style=\"width:400px\">\n", "</center>" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Resorte A" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "El resorte A esta conectado a los nodos 0 y 1. Sin embargo, en el nodo 0 no hay ecuación asignada como se indica por el valor de -1 en el arreglo `DME_mat`, mientras que al nodo 1 se le asigna la ecuación 0. Por lo tanto, como se ilustra en la figura el único valor de la matriz local del resorte A que es necesario ensamblar es el $k_{11}^A$. En este proceso, en el que las componentes de la matriz asociadas a grados de libertad restringidos no se ensamblan, evita tener que eliminar dichos grados de libertad de la matriz global en un paso posterior.\n", "\n", "<center>\n", " <img src=\"img/ensam_A.png\"\n", " alt=\"DME resorte A\"\n", " style=\"width:500px\">\n", "</center>\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Resorte B" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "El resorte B esta conectado a los nodos 1 y 2 los cuales tienen asignadas las ecuaciones 0 y 1. Por lo tanto esta matriz local se localizará en las direcciones $(0,0)$, $(0,1)$ y $(1,0)$.\n", "\n", "<center>\n", " <img src=\"img/ensam_B.png\"\n", " alt=\"DME resorte B\"\n", " style=\"width:500px\">\n", "</center>\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Resorte C" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Nótese que los resortes B y C se encuentran dispuestos en paralelo, lo que hace el sistema más rígido y por ende sus valores se localizan en las misma posiciones de la matriz global.\n", "\n", "<center>\n", " <img src=\"img/ensam_C.png\"\n", " alt=\"DME resorte C\"\n", " style=\"width:500px\">\n", "</center>" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Resorte D\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "El resorte D está conectado a los nodos 2 y 3 los cuales tienen asignadas las ecuaciones 1 y 2. Por lo tanto, esta matriz local se localizará en las direcciones $(1,1)$, $(1,2)$ y $(2,2)$. Nótese ahora que cada que adicionamos al sistema un resorte en serie este se conecta a través de una sola posición con la matriz de rigidez global la cual a la vez aumenta su tamaño.\n", "\n", "<center>\n", " <img src=\"img/ensam_D.png\"\n", " alt=\"DME resorte D\"\n", " style=\"width:600px\">\n", "</center>\n", "\n", "La función `assembly()` que se se presenta a continuación realiza la operación de cálculo de las matrices de rigidez locales y al mismo tiempo las ensambla en la matriz de rigidez global. Note que el algoritmo está conformado por un ciclo principal que recorre el sistema elemento por elemento. Una vez dentro del ciclo la rutina obtiene de los arreglos que almacenan el modelo la información del elemento actual, calcula su matriz local (ver `uelspring()`) y posteriormente obtiene su dirección en la matriz global. La última parte del ciclo asigna cada elemento a su posición en la matriz." ] }, { "cell_type": "code", "execution_count": 7, "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 = 2\n", " for el in range(nels):\n", " elcoor = np.zeros((nnodes))\n", " im = np.int(elements[el, 2])\n", " par = mats[im]\n", " for j in range(nnodes):\n", " IELCON[j] = elements[el, j+3]\n", " elcoor[j] = nodes[IELCON[j], 1]\n", " kloc = uelspring(par)\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 `uelspring` calcula para cada elemento su matriz de rigidez local para que esta sea ensamblada posteriormente usando las direcciones extraídas del arreglo `DME_mat`." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [], "source": [ "def uelspring(kcof):\n", " \"\"\"\n", " Esta rutina calcula la matriz de rigidez para\n", " un elemento tipo resorte conformado por 2 nodos.\n", "\n", " Parámetros\n", " ----------\n", " kcof : float\n", " Coeficiente de rigidez del resorte (>0).\n", "\n", " Retorna\n", " -------\n", " kloc : ndarray\n", " Matriz de coeficientes de rigidez local para\n", " el elemento tipo resorte (2, 2).\n", "\n", "\n", " \"\"\"\n", " kloc = np.array([\n", " [kcof, -kcof],\n", " [-kcof, kcof]])\n", " return kloc" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Similarmente, la función `loadassem` ensambla las cargas aplicadas sobre cada masa. Para esto la función utiliza el arreglo `IBC` que almacena el identificador de ecuación correspondiente a cada masa." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "def loadasem(loads, IBC, neq, nl):\n", " \"\"\"\n", " Ensambla el vector de cargas o de valores conocidos\n", " en el sistema global de ecuaciones.\n", "\n", " Parámetros\n", " ----------\n", " loads : ndarray\n", " Arreglo con las cargas impuestas a las partículas.\n", " IBC : ndarray (int)\n", " Arreglo que almacena el identificador de grado de libertad\n", " a cada partícula.\n", " neq : int\n", " Numero de ecuaciones en el sistema.\n", " nl : int\n", " Numero de cargas en el sistema.\n", "\n", " Retorna\n", " -------\n", " rhs_glob : ndarray\n", " Arreglo con las cargas impuestas a las partículas,\n", " rhs se refiere a lado derecho (del inglés right-hand-side).\n", "\n", " \"\"\"\n", " rhs_glob = np.zeros((neq))\n", " for cont in range(nl):\n", " il = int(loads[cont, 0])\n", " ilx = IBC[il]\n", " if ilx != -1:\n", " rhs_glob[ilx] = loads[cont, 1]\n", " return rhs_glob" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Programa principal" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "El programa principal consiste entonces en un ensamblador de la matriz global, o lo que es lo mismo, en un ensamblador de la matriz de coeficientes del sistema global de ecuaciones y en un ensamblador de un vector de valores conocidos, correspondiente en este problema a el vector de cargas." ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "KG = assembly(elements, mats, nodes, neq, DME_mat)\n", "RHSG = loadasem(loads, IBC, neq, 3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Una vez ensamblado el sistema de ecuaciones este se resuelve para determinar el vector de desplazamientos conocidos." ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[0.002 0.0025 0.0045]\n" ] } ], "source": [ "UG = np.linalg.solve(KG, RHSG)\n", "print(UG)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Un aspecto importante a tener en cuenta es que en muchos programas de análisis estructural se ensambla la contribución de todos los elementos sin tener en cuenta los grados de libertad restringidos. Si en este punto se intenta resolver el sistema de ecuaciones resultante, la matriz de coeficientes será singular y no será posible invertirla reflejando el hecho de que el sistema no se encuentra en equilibrio ya que se puede desplazar como un cuerpo rígido: en términos matemáticos esto equivale a que el sistema de ecuaciones tiene infinitas soluciones. Para poder resolver el sistema es necesario, entonces, modificar la matriz de coeficientes y el vector de cargas de manera que se tengan en cuenta los grados de libertad restringidos (valores iguales a 0).\n", "\n", "Alternativamente, se puede proceder como se ha discutido en este notebook, en donde en el proceso de ensamblaje ya se han tenido en cuenta las condiciones de apoyo o restricciones de cuerpo rígido del sistema. En este procedimiento el sistema de ecuaciones es soluble sin tener que realizar modificaciones adicionales." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Actividades para la clase" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "<div class=\"alert alert-warning\">\n", "\n", "* En las figuras se muestra una parte de un sistema de masas conectadas por resortes conjuntamente con su bloque en el arreglo `DME_mat` almacenando las direcciones de ensamblaje. Usando la notación adoptada en el notebook para referirse a los diferentes elementos de las matrices locales se pide realizar el ensamblaje de cada subsistema.\n", "\n", "**Subsistema 1**\n", "<center>\n", " <img src=\"img/probasem_1.png\"\n", " alt=\"Problema de ensamble 1.\"\n", " style=\"width:400px\">\n", "</center>\n", "\n", "**Subsistema 2**\n", "<center>\n", " <img src=\"img/probasem_2.png\"\n", " alt=\"Problema de ensamble 1.\"\n", " style=\"width:500px\">\n", "</center>\n", "\n", "\n", "</div>" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Glosario de términos" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "**Ensamblaje:** Operación mediante la cual se considera el aporte de un sistema de resortes a la rigidez de todo el sistema.\n", "\n", "**Conectividades:** Identificadores de nodos que definen un elemento y se almacenan en un arreglo denominado `IELCON`. Su representación en términos de grados de libertad indica las direcciones de la matriz de rigidez global en las que se ensambla el elemento.\n", "\n", "\n", "**Operador ensamblador `DME_mat`:** Arreglo que tiene tantas filas como elementos en el sistema y en cada fila contiene las direcciones en las que se ensambla la matriz local correspondiente al elemento en la global.\n" ] }, { "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": 12, "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": 12, "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()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "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.1" }, "toc": { "base_numbering": 1, "nav_menu": {}, "number_sections": true, "sideBar": true, "skip_h1_title": false, "title_cell": "Table of Contents", "title_sidebar": "Contents", "toc_cell": false, "toc_position": {}, "toc_section_display": true, "toc_window_display": false }, "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 }