diff --git a/examples/ExercisesA-Structures-ExerciseSheet.ipynb b/examples/ExercisesA-Structures-ExerciseSheet.ipynb new file mode 100644 index 0000000..57fb46a --- /dev/null +++ b/examples/ExercisesA-Structures-ExerciseSheet.ipynb @@ -0,0 +1,560 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + " Example extracted from the CIVIL-321 repository by Guillaume Anciaux, more on: https://gitlab.epfl.ch/anciaux/mnss-notebooks.\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + " CIVIL-321 \"Modélisation Numérique des Solides et Structures\"

\n", + " Comment utiliser ce Jupyter Notebook?\n", + "

\n", + " Ce Notebook est constitué de cellules de texte et de cellule de code. Les cellules de codes doivent être executées pour voir le résultat du programme. Certaines cellules doivent être remplies par vos soins. Pour exécuter une cellule, cliquez dessus simplement et ensuite cliquez sur le bouton \"play\" () dans la barre de menu au dessus du notebook. Vous pouvez aussi taper la combinaison de touches shift + enter. Il est important d'éxécuter les cellules de code en respectant leur ordre d'arrivée dans le notebook.\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "\n", + "
\n", + " Vous avez une question ?

\n", + " SpeakUp: https://speakup.epfl.ch/ng/room/05096\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from lib.plot import *" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Série d'exercices : Systèmes de ressorts" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Introduction\n", + "\n", + "Cette séance d'exercice contient des exercices à faire à la main ainsi que par programmation sur Python. Tout peut être fait dans ce *Notebook*. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## À lire avant de commencer\n", + "\n", + "\n", + "- Les index sur Python commence à 0 (et non à 1 **contrairement à Matlab**). \n", + "- Les matrices sont crées via le module *Numpy* (https://numpy.org/doc/stable/reference/arrays.ndarray.html)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# exemple, creation d'une matrice \n", + "import numpy as np\n", + "A = np.array([[1,2],[3, 4]])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- La fonction `plot_matrix(matrix, matrix_name)` permet de visualiser les matrices. \n", + " Elle prend en entrée: \n", + " - matrix : le nom de la variable \n", + " - matrix_name = 'nom_matrix'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# exemple d'affichage\n", + "plot_matrix(A, 'A')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- l'extraction de bloc d'un vecteur ou d'une matrice se fait via les `slice` (https://numpy.org/doc/stable/reference/arrays.indexing.html)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# exraction d'une ligne\n", + "plot_matrix(A[0, :], 'A_{{0, x}}')\n", + "\n", + "# exraction d'une colonne\n", + "plot_matrix(A[:, 1], 'A_{{x, 1}}')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercice 1: Assemblage de matrice (à la main)\n", + "\n", + "![](figs/ex1.svg)\n", + "\n", + "*Système de ressorts considéré. $u_i$ sont les déplacements nodaux, $F_i$ sont les forces nodales (appliquées aux noeuds).*" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "1. Calculer la matrice de rigidité gloable:\n", + " 1. en utilisant les équations d'équilibre pour chaque noeud \n", + " 2. en assemblant les matrices de rigidités locales des ressorts." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "\n", + " **Place your answer here** \n", + "\n", + " ---\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " \n", + "2. On applique les conditions limites $u_1 = u_3 = 0$ et $u_4 = \\delta > 0$, et on pose $F_2 = 0$ (aucune force appliquée sur 2). Quelle est la valeur de $u_2$ ? Quelle est la force de réaction au noeud 4 ($F_4$) ?" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "\n", + " **Place your answer here** \n", + "\n", + " ---\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "3. Sur le système initial, quel déplacement faut-il bloquer pour que les degrés de libertés restants soient indépendants les uns des autres ? Quelle est alors la particularité de la matrice de rigidité réduite ?" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "\n", + " **Place your answer here** \n", + "\n", + " ---\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercice 2: Approximation d'une solution analytique (à la main + Python)\n", + "\n", + "On considère un système de quatre ressorts en série. La rigidité totale du système est $k$. Il découle donc que $k_l = 4k$.\n", + "\n", + "![](figs/ex2.svg)\n", + "\n", + "1. Donner, en fonction de $k_l$, la matrice de rigidité d'un élément." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "\n", + " **Place your answer here** \n", + "\n", + " ---\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2. Assembler la matrice de rigidité globale, et donner son expression en fonction de $k$." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "\n", + " **Place your answer here** \n", + "\n", + " ---\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "On applique les conditions limites $u_1 = u_5 = 0$. On applique les forces:\n", + "$$F_2 = \\frac{f}{4},\\quad F_3 = \\frac{f}{4},\\quad F_4 = \\frac{f}{4}$$\n", + "\n", + "\n", + "3. Calculer les déplacements $u_2$, $u_3$ et $u_4$ (en fonction de $f$ et de $k$)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "\n", + " **Place your answer here** \n", + "\n", + " ---\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "4.Comparer ces valeurs avec le champ de déplacement analytique d'une barre bi-encastrée de longueur~$1$, de rigidité axiale $EA/L$ = $k$, soumise à une force axiale répartie: $q(x) = f$. Pour rappel, l'équation différentielle est:\n", + " $$k\\frac{\\text{d}^2 u}{\\text{d}x^2} = -q(x),\\quad \\text{avec}\\ u(0) = 0\\ \\text{et}\\ u(1) = 0$$" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "\n", + " **Place your answer here** \n", + "\n", + " ---\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "5. **Avec Python**, nous allons refaire les questions 1 à 4 pour un système à $n$ ressorts ($n$ sera une variable). \n", + "\n", + " **Attention**: la rigidité de chaque ressort dépend de n afin de conserver la rigidité totale\n", + "k.\n", + "\n", + " - Puisque chaque ressort a la même matrice de rigidité, créer une variable la contenant." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Place your answer here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " - Écrire la boucle d'assemblage de la matrice de rigidité globale (boucle sur les éléments). " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Place your answer here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " - Écrire la boucle qui remplit le vecteur des forces ($F_i = \\frac{f}{n}$) (boucle sur les noeuds). " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Place your answer here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " - Appliquer les conditions limites puis résoudre le système $[K]\\{u\\} = \\{F\\}$. " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Place your answer here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + " - Afficher la solution obtenue. Vous pouvez résoudre un système linéaire avec le fonction `solve` du Numpy (https://numpy.org/doc/stable/reference/generated/numpy.linalg.solve.html)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Place your answer here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- Afficher la solution analytique sous forme de graphique. Vous pourrez utiliser la fonction `plot` du module `matplotlib.pyplot` (https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.plot.html)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Place your answer here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "6. Faire varier le nombre de ressorts pour montrer que la solution éléments finis se rapproche de la solution analytique quand le nombre de ressorts est grand." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Place your answer here" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercice 3: Système de ressorts (à la main)\n", + "\n", + "Pour le système de ressorts représenté ci dessous:\n", + "\n", + "![](figs/ex3.svg)\n", + "\n", + "1. Pour chaque ressort, calculez l'énergie élastique du système ($E_\\text{el}$) en fonction des déplacements.\n", + "\n", + " Rappel de l'énergie potentielle d'un ressort:\n", + " $$E = \\frac{1}{2}k\\Delta l^2$$\n", + " Où $\\Delta l$ est la variation de longeur du ressort." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "\n", + " **Place your answer here** \n", + "\n", + " ---\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2. Calculez le travail des forces extérieures $F_1$ et $F_3$ ($E_\\text{Fext}$)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "\n", + " **Place your answer here** \n", + "\n", + " ---\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "3. Calculez l'énergie potentielle totale du système $\\Pi = E_\\text{el} - E_\\text{Fext}$, en fonction de $u_1$, $u_2$ et $u_3$." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "\n", + " **Place your answer here** \n", + "\n", + " ---\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "4. Donnez les équations que doivent satisfaire $u_1$, $u_2$ et $u_3$ pour minimiser l'énergie potentielle $\\Pi$.\n", + " Donner l'expression de la matrice de rigidité globale $K$." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "\n", + " **Place your answer here** \n", + "\n", + " ---\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "5. Retrouver $K$ par la méthode de rigidité directe." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "\n", + " **Place your answer here** \n", + "\n", + " ---\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "votre_opinion_compte('Exercice-Ressorts')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "hide_input": false, + "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.6.9" + }, + "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": { + "height": "calc(100% - 180px)", + "left": "10px", + "top": "150px", + "width": "384px" + }, + "toc_section_display": true, + "toc_window_display": true + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/examples/ExercisesA-Structures-Solution.ipynb b/examples/ExercisesA-Structures-Solution.ipynb new file mode 100644 index 0000000..ec8a921 --- /dev/null +++ b/examples/ExercisesA-Structures-Solution.ipynb @@ -0,0 +1,855 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + " Example extracted from the CIVIL-321 repository by Guillaume Anciaux, more on: https://gitlab.epfl.ch/anciaux/mnss-notebooks.\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + " CIVIL-321 \"Modélisation Numérique des Solides et Structures\"

\n", + " Comment utiliser ce Jupyter Notebook?\n", + "

\n", + " Ce Notebook est constitué de cellules de texte et de cellule de code. Les cellules de codes doivent être executées pour voir le résultat du programme. Certaines cellules doivent être remplies par vos soins. Pour exécuter une cellule, cliquez dessus simplement et ensuite cliquez sur le bouton \"play\" () dans la barre de menu au dessus du notebook. Vous pouvez aussi taper la combinaison de touches shift + enter. Il est important d'éxécuter les cellules de code en respectant leur ordre d'arrivée dans le notebook.\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "
\n", + " Vous avez une question ?

\n", + " SpeakUp: https://speakup.epfl.ch/ng/room/05096\n", + "
" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from lib.plot import *" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Série d'exercices : Systèmes de ressorts" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Introduction\n", + "\n", + "Cette séance d'exercice contient des exercices à faire à la main ainsi que par programmation sur Python. Tout peut être fait dans ce *Notebook*." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## À lire avant de commencer\n", + "\n", + "\n", + "- Les index sur Python commence à 0 (et non à 1 **contrairement à Matlab**). \n", + "- Les matrices sont crées via le module *Numpy* (https://numpy.org/doc/stable/reference/arrays.ndarray.html)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# exemple, creation d'une matrice \n", + "import numpy as np\n", + "A = np.array([[1,2],[3, 4]])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- La fonction `plot_matrix(matrix, matrix_name)` permet de visualiser les matrices. \n", + " Elle prend en entrée: \n", + " - matrix : le nom de la variable \n", + " - matrix_name = 'nom_matrix'" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# exemple d'affichage\n", + "plot_matrix(A, 'A')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- l'extraction de bloc d'un vecteur ou d'une matrice se fait via les `slice` (https://numpy.org/doc/stable/reference/arrays.indexing.html)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# exraction d'une ligne\n", + "plot_matrix(A[0, :], 'A_{{0, x}}')\n", + "\n", + "# exraction d'une colonne\n", + "plot_matrix(A[:, 1], 'A_{{x, 1}}')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercice 1: Assemblage de matrice (à la main)\n", + "\n", + "![](figs/ex1.svg)\n", + "\n", + "*Système de ressorts considéré. $u_i$ sont les déplacements nodaux, $F_i$ sont les forces nodales (appliquées aux noeuds).*" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "1. Calculer la matrice de rigidité gloable:\n", + " 1. en utilisant les équations d'équilibre pour chaque noeud \n", + " 2. en assemblant les matrices de rigidités locales des ressorts." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "\n", + " **Solution:**\n", + "\n", + " ---\n", + "\n", + "\n", + "\n", + "- Isolons le noeud 2:\n", + " ![](figs/ex1-1.svg)\n", + " \n", + " *Figure: Équilibre du noeud 2. La force appliquée est $F_2$. Les forces $f_1$, $f_2$ et $f_3$ sont les forces de rappel des ressorts 1, 2, et 3.*\n", + "\n", + " L'équilibre donne comme équation: $F_2 - f_1 - f_2 - f_3 = 0$\n", + " \n", + " On remplace $f_1$, $f_2$, $f_3 \\qquad \\Longrightarrow \\qquad F_2 -k_1(u_2 - u_1) + k_2(u_3 - u_2) + k_3(u_4-u_2) = 0$\n", + " \n", + " En répétant le processus pour chaque noeud, nous trouvons un système d'équations linéaires dont la matrice est la matrice de rigidité globale:\n", + " $$ \\mathbf{K} = \\begin{bmatrix}\n", + " k_1 & -k_1 & 0 & 0\\\\\n", + " -k_1 & k_1 + k_2 + k_3 & -k_2 & -k_3\\\\\n", + " 0 & -k_2 & k_2 & 0\\\\\n", + " 0 & -k_3 & 0 & k_3\n", + " \\end{bmatrix}$$\n", + " \n", + "- La matrice de rigidité globale est l'assemblage des matrices de rigidité de chaque ressort:\n", + " $$\\mathbf{K} = \\sum_{e=1}^N {\\mathbf{k}^e}$$\n", + " \n", + " Pour chaque ressort, la matrice de rigidité locale est:\n", + " $$\\mathbf{k}^e = \\begin{bmatrix}\n", + " k_e & -k_e\\\\\n", + " -k_e & k_e\n", + " \\end{bmatrix}$$\n", + "\n", + " Il faut cependant être attentif et se demander pour chaque noeud quels ressorts contribuent à la rigidité. \n", + " Par exemple:\n", + " - Pour le noeud 1, seul le ressort 1 contribue. La première ligne et la première colonne de $\\mathbf{K}$ vont donc être déterminées par la matrice de rigidité du ressort 1.\n", + " - Le noeud 2 est relié à tous les ressorts. La deuxième ligne et la deuxième colonne de $\\mathbf{K}$ seront donc déterminées par les trois matrices de rigidité.\n", + "\n", + " En applicant ce raisonnement pour chaque noeud, on obtient:\n", + " \n", + " $$\\mathbf{K} = \\begin{bmatrix}\n", + " k_1 & -k_1 & 0 & 0\\\\\n", + " -k_1 & k_1 + k_2 + k_3 & -k_2 & -k_3\\\\\n", + " 0 & -k_2 & k_2 & 0\\\\\n", + " 0 & -k_3 & 0 & k_3\n", + " \\end{bmatrix}$$" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2. On applique les conditions limites $u_1 = u_3 = 0$ et $u_4 = \\delta > 0$, et on pose $F_2 = 0$ (aucune force appliquée sur 2). Quelle est la valeur de $u_2$ ? Quelle est la force de réaction au noeud 4 ($F_4$) ?" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "\n", + " **Solution:**\n", + "\n", + " ---\n", + "\n", + "\n", + "\n", + "On applique les conditions limite suivantes:\n", + " - $u_1 = 0$\n", + " - $u_3 = 0$\n", + " - $u_4 = \\delta$\n", + "\n", + "Les deux premières conditions sont des conditions **homogènes**. On peut donc supprimer les lignes et colones de $\\mathbf{K}$ correspondant à $u_1$ et $u_3$. Le système $\\mathbf{K}u = F$ devient:\n", + "\n", + "$$\\begin{pmatrix}\n", + "k_1 + k_2 + k_3 & -k_3\\\\\n", + "-k_3 & k_3\n", + "\\end{pmatrix} \\begin{pmatrix}\n", + "u_2\\\\\n", + "u_4\n", + "\\end{pmatrix} = \\begin{pmatrix}\n", + "0\\\\\n", + "F_4\n", + "\\end{pmatrix}$$\n", + "\n", + "Ce système a deux équations et deux inconnues: $u_2$ et $F_4$, puisque $u_4 = \\delta$. La résolution donne:\n", + "$$\\begin{eqnarray*}\n", + "u_2 & = & \\frac{k_3 \\delta}{k_1 + k_2 + k_3}\\\\\n", + "F_4 & = & k_3 \\delta \\left( 1 - \\frac{k_3}{k_1 + k_2 + k_3} \\right)\n", + "\\end{eqnarray*}$$" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "3. Sur le système initial, quel déplacement faut-il bloquer pour que les degrés de libertés restants soient indépendants les uns des autres ? Quelle est alors la particularité de la matrice de rigidité réduite ?" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "\n", + " **Solution:**\n", + "\n", + " ---\n", + "\n", + "\n", + "\n", + "- Si le noeud 2 est bloqué, des forces ou des déplacements appliqués aux noeuds restants n'auront pas d'effet sur les autres noeuds. Si l'on applique la condition limite homogène $u_2 = 0$, la matrice de rigidité devient:\n", + " $$\\mathbf{K} = \\begin{bmatrix}\n", + " k_1 & 0 & 0\\\\\n", + " 0 & k_2 & 0\\\\\n", + " 0 & 0 & k_3\n", + " \\end{bmatrix}$$\n", + " \n", + " $\\mathbf{K}$ est diagonale, ce qui exprime bien le fait qu'il n'y ai plus de relation entre les degrés de liberté du système." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercice 2: Approximation d'une solution analytique (à la main + Python)\n", + "\n", + "On considère un système de quatre ressorts en série. La rigidité totale du système est $k$. Il découle donc que $k_l = 4k$.\n", + "\n", + "![](figs/ex2.svg)\n", + "\n", + "1. Donner, en fonction de $k_l$, la matrice de rigidité d'un élément." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "\n", + " **Solution:**\n", + "\n", + " ---\n", + "\n", + "\n", + "\n", + "$$\\mathbf{k}^e = \\begin{bmatrix}\n", + " k_l & -k_l\\\\\n", + " -k_l & k_l\n", + " \\end{bmatrix}$$" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2. Assembler la matrice de rigidité globale, et donner son expression en fonction de $k$." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "\n", + " **Solution:**\n", + "\n", + " ---\n", + "\n", + "\n", + "\n", + "- $$\\mathbf{K} = k \\begin{pmatrix}\n", + " 4 & -4 & 0 & 0 & 0\\\\\n", + " -4 & 8 & -4 & 0 & 0\\\\\n", + " 0 & -4 & 8 & -4 & 0\\\\\n", + " 0 & 0 & -4 & 8 & -4\\\\\n", + " 0 & 0 & 0 & -4 & 4\\\\\n", + " \\end{pmatrix}$$" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "On applique les conditions limites $u_1 = u_5 = 0$. On applique les forces:\n", + "$$F_2 = \\frac{f}{4},\\quad F_3 = \\frac{f}{4},\\quad F_4 = \\frac{f}{4}$$\n", + "\n", + "\n", + "3. Calculer les déplacements $u_2$, $u_3$ et $u_4$ (en fonction de $f$ et de $k$)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "\n", + " **Solution:**\n", + "\n", + " ---\n", + "\n", + "\n", + "\n", + "$$k\\begin{pmatrix}\n", + " 8 & -4 & 0\\\\\n", + " -4 & 8 & -4\\\\\n", + " 0 & -4 & 8\n", + " \\end{pmatrix} \\begin{pmatrix}\n", + " u_2\\\\\n", + " u_3\\\\\n", + " u_4\n", + " \\end{pmatrix} = \\frac{f}{4}\\begin{pmatrix}\n", + " 1\\\\\n", + " 1\\\\\n", + " 1\n", + " \\end{pmatrix}$$\n", + " Ce qui donne:\n", + " $$\\begin{pmatrix}\n", + " u_2\\\\\n", + " u_3\\\\\n", + " u_4\n", + " \\end{pmatrix} = \\frac{f}{4k}\n", + " \\begin{pmatrix}\n", + " \\frac{3}{8}\\\\[0.1cm]\n", + " \\frac{1}{2}\\\\[0.1cm]\n", + " \\frac{3}{8}\n", + " \\end{pmatrix}$$" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "4.Comparer ces valeurs avec le champ de déplacement analytique d'une barre bi-encastrée de longueur~$1$, de rigidité axiale $EA/L$ = $k$, soumise à une force axiale répartie: $q(x) = f$. Pour rappel, l'équation différentielle est:\n", + " $$k\\frac{\\text{d}^2 u}{\\text{d}x^2} = -q(x),\\quad \\text{avec}\\ u(0) = 0\\ \\text{et}\\ u(1) = 0$$" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "\n", + " **Solution:**\n", + "\n", + " ---\n", + "\n", + "\n", + "\n", + "- L'équation différentielle se résoud par intégration successive, pour\n", + " donner: $u(x) = \\frac{f}{2k}(x-x^2)$\n", + " \n", + " Les déplacements aux positions de $u_2$, $u_3$ et $u_4$ sont:\n", + " $$\\begin{eqnarray*}\n", + " u(\\frac{1}{4}) & = & \\frac{3f}{32k} = u_2\\\\\n", + " u(\\frac{1}{2}) & = & \\frac{f}{8k} = u_3\\\\\n", + " u(\\frac{3}{4}) & = & \\frac{3f}{32k} = u_4\n", + " \\end{eqnarray*}$$" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "5. **Avec Python**, nous allons refaire les questions 1 à 4 pour un système à $n$ ressorts ($n$ sera une variable). \n", + "\n", + " **Attention**: la rigidité de chaque ressort dépend de n afin de conserver la rigidité totale\n", + "k.\n", + "\n", + " - Puisque chaque ressort a la même matrice de rigidité, créer une variable la contenant." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "###########\n", + "# Solution:\n", + "##########\n", + "\n", + "\n", + "n = 4\n", + "k = 1\n", + "kl = n*k\n", + "kloc = kl*np.array([[1, -1], [-1, 1]])\n", + "plot_matrix(kloc, 'k^{{loc}}')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- Écrire la boucle d'assemblage de la matrice de rigidité globale (boucle sur les éléments)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "###########\n", + "# Solution:\n", + "##########\n", + "\n", + "\n", + "# On se sert de la connectivité pour assembler les matrices locales\n", + "# dans la matrice globale\n", + "# La taille de K est (N+1, N+1) car il y a N+1 noeuds\n", + "\n", + "K = np.zeros((n+1, n+1))\n", + "\n", + "for e in range(n):\n", + " for i in range(2):\n", + " for j in range(2):\n", + " K[e+i, e+j] = K[e+i, e+j] + kloc[i, j]\n", + " # ce qui s'écrit aussi\n", + " # K[e+i, e+j] += kloc[i, j]\n", + " \n", + "plot_matrix(K, 'K')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- Écrire la boucle qui remplit le vecteur des forces ($F_i = \\frac{f}{n}$) (boucle sur les noeuds)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "###########\n", + "# Solution:\n", + "##########\n", + "\n", + "\n", + "# On remplit le vecteur force, de taille N+1\n", + "# les valeurs de F(1) et F(N+1) ne sont pas importantes,\n", + "# elles sont ignorées lors de la résolution de Ku=F\n", + "\n", + "f = 1\n", + "F = np.ones(n+1)*f/n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- Appliquer les conditions limites puis résoudre le système $[K]\\{u\\} = \\{F\\}$." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "###########\n", + "# Solution:\n", + "##########\n", + "\n", + "\n", + "# On bloque les noeuds 1 et N+1\n", + "# Les noeuds libres sont donc les noeuds de 2 à N\n", + "\n", + "noeuds_libres = range(1, n)\n", + "K_libre = K[noeuds_libres, :][:, noeuds_libres]\n", + "F_libre = F[noeuds_libres]\n", + "\n", + "plot_matrix(K_libre, 'K^{{libre}}')\n", + "plot_matrix(F_libre, 'F^{{libre}}')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- Afficher la solution obtenue. Vous pouvez résoudre un système linéaire avec le fonction `solve` du Numpy (https://numpy.org/doc/stable/reference/generated/numpy.linalg.solve.html)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "###########\n", + "# Solution:\n", + "##########\n", + "\n", + "\n", + "# On construit le vecteur des déplacements complet\n", + "u = np.zeros(n+1)\n", + "\n", + "# Résolution de Ku = F\n", + "u[noeuds_libres] = np.linalg.solve(K_libre, F_libre)\n", + "plot_matrix(u, 'u')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- Afficher la solution analytique sous forme de graphique. Vous pourrez utiliser la fonction `plot` du module `matplotlib.pyplot` (https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.plot.html)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "###########\n", + "# Solution:\n", + "##########\n", + "\n", + "\n", + "import matplotlib.pyplot as plt\n", + "\n", + "x_numeric = np.linspace(0, 1, n+1)\n", + "x_analytic = np.linspace(0, 1, 1000)\n", + "u_analytic = f / (2 * k) * (x_analytic - x_analytic**2);\n", + "plt.plot(x_numeric, u, label='numeric')\n", + "plt.plot(x_analytic, u_analytic, '--', label='analytic')\n", + "plt.legend()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "6. Faire varier le nombre de ressorts pour montrer que la solution éléments finis se rapproche de la solution analytique quand le nombre de ressorts est grand." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "###########\n", + "# Solution:\n", + "##########\n", + "\n", + "\n", + "# On écrit une fonction qui résoud notre problème pour un n donné\n", + "def solve_problem(n):\n", + " kl = n*k\n", + " kloc = kl*np.array([[1, -1], [-1, 1]])\n", + "\n", + " K = np.zeros((n+1, n+1))\n", + "\n", + " for e in range(n):\n", + " for i in range(2):\n", + " for j in range(2):\n", + " K[e+i, e+j] += kloc[i, j]\n", + " \n", + " f = 1\n", + " F = np.ones(n+1)*f/n\n", + " \n", + " noeuds_libres = range(1, n)\n", + " K_libre = K[noeuds_libres, :][:, noeuds_libres]\n", + " F_libre = F[noeuds_libres]\n", + "\n", + " u = np.zeros(n+1)\n", + " u[noeuds_libres] = np.linalg.solve(K_libre, F_libre)\n", + " x = np.linspace(0, 1, n+1)\n", + " return x, u\n", + "\n", + "# on fait une boucle pour faire varier n\n", + "for n in range(2, 10, 2):\n", + " x, u = solve_problem(n)\n", + " plt.plot(x, u, label=f'analytic $n = {n}$')\n", + " \n", + "plt.plot(x_analytic, u_analytic, '--', label='analytic')\n", + "plt.legend()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Exercice 3: Système de ressorts (à la main)\n", + "\n", + "Pour le système de ressorts représenté ci dessous:\n", + "\n", + "![](figs/ex3.svg)\n", + "\n", + "1. Pour chaque ressort, calculez l'énergie élastique du système ($E_\\text{el}$) en fonction des déplacements.\n", + "\n", + " Rappel de l'énergie potentielle d'un ressort:\n", + " $$E = \\frac{1}{2}k\\Delta l^2$$\n", + " Où $\\Delta l$ est la variation de longeur du ressort." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "\n", + " **Solution:**\n", + "\n", + " ---\n", + "\n", + "\n", + " \n", + "$$\\begin{equation*}\n", + " E_\\text{el} = \\frac{1}{2} k_1 {\\delta_1}^2 + \\frac{1}{2} k_2 {\\delta_2}^2 +\n", + " \\frac{1}{2} k_3 {\\delta_3}^2 + \\frac{1}{2} k_4 {\\delta_4}^2\n", + " \\end{equation*}$$\n", + "\n", + "où $\\delta_i$ est l'allongement du $i^\\text{ème}$ ressort. Exprimons ces allongement en fonction des déplacements:\n", + "\n", + "$$\\begin{align*}\n", + " \\delta_{1} &= u_1 - u_2 \\\\\n", + " \\delta_{2} &= u_2 \\\\\n", + " \\delta_{3} &= u_3 - u_2 \\\\\n", + " \\delta_{4} &= -u_3.\n", + " \\end{align*}$$\n", + "\n", + "L'énergie potentielle totale peut donc être réécrite en fonction des déplacements:\n", + "\n", + "$$\\begin{equation*}\n", + " E_\\text{el} = \\frac{1}{2} k_1 (u_1 - u_2)^2 + \\frac{1}{2} k_2 {u_2}^2 +\n", + " \\frac{1}{2} k_3 (u_3 - u_2)^2 + \\frac{1}{2} k_4 {u_3}^2\n", + " \\end{equation*}$$" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2. Calculez le travail des forces extérieures $F_1$ et $F_3$ ($E_\\text{Fext}$)." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "\n", + " **Solution:**\n", + "\n", + " ---\n", + "\n", + "\n", + "\n", + "Le travail des forces extérieures est:\n", + " $$E_\\text{Fext} = F_1 u_1 + F_3 u_3$$" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "3. Calculez l'énergie potentielle totale du système $\\Pi = E_\\text{el} - E_\\text{Fext}$, en fonction de $u_1$, $u_2$ et $u_3$." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "\n", + " **Solution:**\n", + "\n", + " ---\n", + "\n", + "\n", + "\n", + "L'énergie potentielle totale du système est:\n", + " $$\\Pi(u_1, u_2, u_3) = \\frac{1}{2} k_1 (u_1 - u_2)^2 + \\frac{1}{2} k_2 {u_2}^2 +\n", + " \\frac{1}{2} k_3 (u_3 - u_2)^2 + \\frac{1}{2} k_4 {u_3}^2 - F_1\n", + " u_1 - F_3 u_3$$" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "4. Donnez les équations que doivent satisfaire $u_1$, $u_2$ et $u_3$ pour minimiser l'énergie potentielle $\\Pi$.\n", + " Donner l'expression de la matrice de rigidité globale $K$." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "\n", + " **Solution:**\n", + "\n", + " ---\n", + "\n", + "\n", + " \n", + "Minimiser $\\Pi$ par rapport à $u_1$,$u_2$ et $u_3$ nécessite\n", + "\n", + "$$\\begin{equation*}\n", + " \\frac{\\partial \\Pi}{\\partial u_i} = 0 \\quad\\quad i=1,2,3.\n", + " \\end{equation*}$$\n", + "\n", + "Les équations en résultant sont:\n", + "\n", + "$$\\begin{align*}\n", + " \\frac{\\partial \\Pi}{\\partial u_1} &= k_1 \\left(u_1 - u_2\\right) - F_1 = 0 \\\\\n", + " \\frac{\\partial \\Pi}{\\partial u_2} &= -k_1 \\left(u_1 - u_2\\right) + k_2 u_2 - k_3 \\left(u_3 - u_2\\right) = 0\\\\\n", + " \\frac{\\partial \\Pi}{\\partial u_3} &= k_3 \\left(u_3 - u_2\\right) + k_4 u_3 - F_3 = 0.\n", + " \\end{align*}$$" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "5. Retrouver $K$ par la méthode de rigidité directe." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "---\n", + "\n", + " **Solution:**\n", + "\n", + " ---\n", + "\n", + "\n", + "\n", + "Elles peuvent être réécrites sous la forme matricielle\n", + "\n", + "$$\\begin{equation*}\n", + " \\left[\\begin{array}{ccc}\n", + " k_1 & -k_1 & 0 \\\\\n", + " -k_1 & k_1+k_2+k_3 & -k_3 \\\\\n", + " 0 & -k_3 & k_3+k_4\n", + " \\end{array}\\right] \\left\\{\\begin{array}{c}\n", + " u_1 \\\\ u_2 \\\\ u_3\n", + " \\end{array}\\right\\} = \\left\\{\\begin{array}{c}\n", + " F_1 \\\\ 0 \\\\ F_3\n", + " \\end{array}\\right\\}\n", + " \\end{equation*}$$" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "votre_opinion_compte('Exercice-Ressorts')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "hide_input": false, + "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.6.9" + }, + "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": { + "height": "calc(100% - 180px)", + "left": "10px", + "top": "150px", + "width": "384px" + }, + "toc_section_display": true, + "toc_window_display": true + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/examples/figs/ex1-1.svg b/examples/figs/ex1-1.svg new file mode 100644 index 0000000..5c93d56 --- /dev/null +++ b/examples/figs/ex1-1.svg @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/figs/ex1.svg b/examples/figs/ex1.svg new file mode 100644 index 0000000..8190dfd --- /dev/null +++ b/examples/figs/ex1.svg @@ -0,0 +1,158 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/figs/ex2.svg b/examples/figs/ex2.svg new file mode 100644 index 0000000..b2332b4 --- /dev/null +++ b/examples/figs/ex2.svg @@ -0,0 +1,137 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/figs/ex3.svg b/examples/figs/ex3.svg new file mode 100644 index 0000000..f0b484f --- /dev/null +++ b/examples/figs/ex3.svg @@ -0,0 +1,1055 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/lib/plot.py b/examples/lib/plot.py new file mode 100644 index 0000000..8b93fc3 --- /dev/null +++ b/examples/lib/plot.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python3 + +########## + +from IPython.display import IFrame, display +from sympy import Matrix +from Slides import math_helper as mh + + +def plot_matrix(matrix, matrix_name): + mh.print_latex(matrix_name+"= {0}", Matrix(matrix)) + + +def plot_matrix_product(matrix1, matrix2, matrix3, matrix_name): + mh.print_latex(matrix_name + '= {0}{1}{2}', matrix1, matrix2, matrix3) + + +def votre_opinion_compte(name): + display(IFrame('https://www.surveymonkey.com/r/NOTOSURVEY?notebook_set=CIVIL-321¬ebook_id=CIVIL-321'+name, 600, 1000)) + +def vous_avez_des_questions(): + display(IFrame('https://speakup.epfl.ch/ng/room/05096', 600, 600))