{ "cells": [ { "cell_type": "markdown", "id": "301eb125", "metadata": {}, "source": [ "# Manipuler les unités physiques avec `pint`\n", "\n", "Ce notebook présente les fonctionnalités essentielles du paquet\n", "[pint](https://pint.readthedocs.io/) pour la manipulation des unités\n", "physiques, avec un accent sur les **grandeurs courantes en hydrologie** :\n", "\n", "- Longueurs (m, mm, km)\n", "- Surfaces (m², ha, km²)\n", "- Volumes (m³, L)\n", "- Débits (m³/s, L/s, L/s/ha)\n", "- Intensités de pluie (mm/h)\n", "- Vitesses (m/s, mm/h — conductivité hydraulique)\n", "\n", "## Sommaire\n", "\n", "1. [Le registre d'unités (`UnitRegistry`)](#1.-Le-registre-d'unités)\n", "2. [Créer des grandeurs (`Quantity`)](#2.-Créer-des-grandeurs)\n", "3. [Conversions](#3.-Conversions)\n", "4. [Opérations arithmétiques](#4.-Opérations-arithmétiques)\n", "5. [Comparaisons](#5.-Comparaisons)\n", "6. [Formatage de l'affichage](#6.-Formatage-de-l'affichage)\n", "7. [Application hydrologique : bilan sur un bassin versant](#7.-Application-hydrologique)\n", "8. [Pièges courants](#8.-Pièges-courants)" ] }, { "cell_type": "markdown", "id": "e4c9159b", "metadata": {}, "source": [ "## 1. Le registre d'unités\n", "\n", "Toutes les unités sont gérées par un **registre** (`UnitRegistry`).\n", "Il est important d'utiliser **un seul registre** dans tout le programme,\n", "sinon les grandeurs issues de registres différents sont incompatibles.\n", "\n", "Dans `wolfhece`, le registre partagé est `UNITS` :" ] }, { "cell_type": "code", "execution_count": 1, "id": "ff089376", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "meter\n", "hectare\n", "liter\n", "second\n", "hour\n" ] } ], "source": [ "import pint\n", "\n", "# Création d'un registre — en pratique, wolfhece en expose\n", "# un unique dans son __init__ :\n", "# from wolfhece import UNITS\n", "U = pint.UnitRegistry()\n", "\n", "# Exemples d'unités disponibles\n", "print(U.meter)\n", "print(U.hectare)\n", "print(U.liter)\n", "print(U.second)\n", "print(U.hour)" ] }, { "cell_type": "markdown", "id": "2ce49a59", "metadata": {}, "source": [ "## 2. Créer des grandeurs\n", "\n", "Une grandeur (`Quantity`) est un couple **(valeur, unité)**.\n", "On la crée par multiplication d'un nombre par une unité :" ] }, { "cell_type": "code", "execution_count": 2, "id": "391e40c1", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Longueur : 150 meter\n", "Surface : 0.5 hectare\n", "Volume : 42.5 meter ** 3\n", "Débit : 3.2 liter / second\n", "Pluie : 25.0 millimeter / hour\n" ] } ], "source": [ "# Longueurs\n", "longueur = 150 * U.meter\n", "print(f\"Longueur : {longueur}\")\n", "\n", "# Surfaces\n", "surface = 0.5 * U.hectare\n", "print(f\"Surface : {surface}\")\n", "\n", "# Volumes\n", "volume = 42.5 * U.meter**3\n", "print(f\"Volume : {volume}\")\n", "\n", "# Débits\n", "debit = 3.2 * U.liter / U.second\n", "print(f\"Débit : {debit}\")\n", "\n", "# Intensité de pluie\n", "intensite = 25.0 * U.mm / U.hour\n", "print(f\"Pluie : {intensite}\")" ] }, { "cell_type": "markdown", "id": "ceb2f64d", "metadata": {}, "source": [ "Les unités composées se construisent avec `*`, `/` et `**` :" ] }, { "cell_type": "code", "execution_count": 3, "id": "594ef60f", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "K = 1e-05 meter / second\n", "q = 5.0 liter / hectare / second\n" ] } ], "source": [ "# Conductivité hydraulique de Darcy\n", "K = 1e-5 * U.meter / U.second\n", "print(f\"K = {K}\")\n", "\n", "# Débit spécifique (L/s par hectare)\n", "q_spec = 5.0 * U.liter / U.second / U.hectare\n", "print(f\"q = {q_spec}\")" ] }, { "cell_type": "markdown", "id": "a4ffe598", "metadata": {}, "source": [ "## 3. Conversions\n", "\n", "La méthode `.to()` convertit vers une autre unité **compatible** :" ] }, { "cell_type": "code", "execution_count": 4, "id": "dbecf5b3", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2.5 hectare = 25000.0 meter ** 2 = 0.025 kilometer ** 2\n", "12.0 liter / second = 0.012000000000000004 meter ** 3 / second = 43.20000000000001 meter ** 3 / hour\n", "1.00e-05 meter / second = 36.00 millimeter / hour\n", "50.0 millimeter / hour = 1.3889e-05 meter / second\n" ] } ], "source": [ "# Surface : hectare ↔ m²\n", "s = 2.5 * U.hectare\n", "print(f\"{s} = {s.to(U.meter**2)} = {s.to('km^2')}\")\n", "\n", "# Débit : L/s ↔ m³/s ↔ m³/h\n", "q = 12.0 * U.liter / U.second\n", "print(f\"{q} = {q.to('m^3/s')} = {q.to('m^3/hour')}\")\n", "\n", "# Conductivité hydraulique : m/s ↔ mm/h\n", "K = 1e-5 * U.meter / U.second\n", "print(f\"{K:.2e} = {K.to('mm/hour'):.2f}\")\n", "\n", "# Intensité de pluie : mm/h ↔ m/s\n", "i = 50 * U.mm / U.hour\n", "print(f\"{i} = {i.to('m/s'):.4e}\")" ] }, { "cell_type": "markdown", "id": "49afee1d", "metadata": {}, "source": [ "### Extraire la valeur numérique\n", "\n", "L'attribut `.magnitude` donne la valeur brute (sans unité) :" ] }, { "cell_type": "code", "execution_count": 5, "id": "fe5d8a8b", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Magnitude en L/s : 12.0\n", "Magnitude en m³/s : 0.012000000000000004\n", "Unité : liter / second\n" ] } ], "source": [ "q = 12.0 * U.liter / U.second\n", "\n", "print(f\"Magnitude en L/s : {q.magnitude}\")\n", "print(f\"Magnitude en m³/s : {q.to('m^3/s').magnitude}\")\n", "print(f\"Unité : {q.units}\")" ] }, { "cell_type": "markdown", "id": "520ed31d", "metadata": {}, "source": [ "## 4. Opérations arithmétiques\n", "\n", "`pint` gère automatiquement les unités dans les calculs :" ] }, { "cell_type": "code", "execution_count": 6, "id": "e290e9b3", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "800 meter ** 2 + 0.15 hectare = 2300.0 meter ** 2\n", "\n", "Surface × intensité : 1.0 hectare × 50.0 millimeter / hour = 138.9 liter / second\n", "\n", "Débit × temps : 5.0 liter / second × 2 hour = 36.00000000000001 meter ** 3\n" ] } ], "source": [ "# Somme de surfaces (unités différentes mais compatibles)\n", "s1 = 800 * U.meter**2\n", "s2 = 0.15 * U.hectare\n", "s_tot = s1 + s2\n", "print(f\"{s1} + {s2} = {s_tot.to('m^2')}\")\n", "\n", "# Surface × intensité de pluie → débit\n", "A = 1.0 * U.hectare\n", "i = 50 * U.mm / U.hour\n", "Q = (A * i).to('liter/second')\n", "print(f\"\\nSurface × intensité : {A} × {i} = {Q:.1f}\")\n", "\n", "# Débit × temps → volume\n", "Q = 5 * U.liter / U.second\n", "t = 2 * U.hour\n", "V = (Q * t).to('m^3')\n", "print(f\"\\nDébit × temps : {Q} × {t} = {V}\")" ] }, { "cell_type": "markdown", "id": "5a749df1", "metadata": {}, "source": [ "### Multiplication par un coefficient sans dimension\n", "\n", "Un nombre pur (coefficient de ruissellement, facteur de sécurité, …)\n", "n'a pas d'unité et s'utilise naturellement :" ] }, { "cell_type": "code", "execution_count": 7, "id": "a96b1de6", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Débit net = C × A × i = 0.9 × 800 meter ** 2 × 42.0 millimeter / hour = 8.40 liter / second\n" ] } ], "source": [ "C = 0.9 # coefficient de ruissellement (sans dimension)\n", "A = 800 * U.meter**2\n", "i = 42.0 * U.mm / U.hour\n", "\n", "Q_net = (C * A * i).to('liter/second')\n", "print(f\"Débit net = C × A × i = {C} × {A} × {i} = {Q_net:.2f}\")" ] }, { "cell_type": "markdown", "id": "a45ceba5", "metadata": {}, "source": [ "## 5. Comparaisons\n", "\n", "Les comparaisons entre grandeurs de même dimension fonctionnent\n", "directement, même si les unités diffèrent :" ] }, { "cell_type": "code", "execution_count": 8, "id": "16fea749", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "5000 meter ** 2 == 0.5 hectare ? True\n", "5000 meter ** 2 > 0.5 hectare ? False\n", "5000 meter ** 2 < 0.6 hectare ? True\n" ] } ], "source": [ "s1 = 5000 * U.meter**2\n", "s2 = 0.5 * U.hectare\n", "\n", "print(f\"{s1} == {s2} ? {s1 == s2}\")\n", "print(f\"{s1} > {s2} ? {s1 > s2}\")\n", "\n", "s3 = 0.6 * U.hectare\n", "print(f\"{s1} < {s3} ? {s1 < s3}\")" ] }, { "cell_type": "markdown", "id": "3d44e44e", "metadata": {}, "source": [ "## 6. Formatage de l'affichage\n", "\n", "On peut formater les grandeurs avec les spécificateurs habituels :" ] }, { "cell_type": "code", "execution_count": 9, "id": "714e70a8", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Volume : 42.6 meter ** 3\n", "Volume : 43 meter ** 3\n", "Darcy : 1.00e-05 meter / second\n", "Darcy : 36.00 millimeter / hour\n" ] } ], "source": [ "V = 42.567 * U.meter**3\n", "K = 1e-5 * U.meter / U.second\n", "\n", "print(f\"Volume : {V:.1f}\") # 1 décimale\n", "print(f\"Volume : {V:.0f}\") # pas de décimale\n", "print(f\"Darcy : {K:.2e}\") # notation scientifique\n", "\n", "# Convertir avant d'afficher\n", "print(f\"Darcy : {K.to('mm/hour'):.2f}\")" ] }, { "cell_type": "markdown", "id": "dbdf39a2", "metadata": {}, "source": [ "### Affichage compact (`~`)\n", "\n", "Le format `~` utilise les **abréviations** des unités :" ] }, { "cell_type": "code", "execution_count": 10, "id": "f9d67e7b", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Normal : 12.0 liter / second\n", "Compact: 12.0 l / s\n", "Compact: 12.0 l / s\n" ] } ], "source": [ "q = 12.0 * U.liter / U.second\n", "\n", "print(f\"Normal : {q}\") # liter / second\n", "print(f\"Compact: {q:~}\") # l / s\n", "print(f\"Compact: {q:~.1f}\") # l / s avec 1 décimale" ] }, { "cell_type": "markdown", "id": "45ac2132", "metadata": {}, "source": [ "## 7. Application hydrologique\n", "\n", "### Bilan simplifié sur un bassin versant\n", "\n", "Calculons le **volume ruisselé** pour une pluie de projet sur un\n", "bassin composé de plusieurs types d'occupation du sol :" ] }, { "cell_type": "code", "execution_count": 11, "id": "7bbb54ab", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Sous-bassin C Surface Q_net V_ruisselé\n", "------------------------------------------------------------\n", "Parking 0.90 800 meter ** 2 8.40 liter / second 45.36 meter ** 3\n", "Toitures 1.00 350 meter ** 2 4.08 liter / second 22.05 meter ** 3\n", "Trottoirs 0.70 200 meter ** 2 1.63 liter / second 8.82 meter ** 3\n", "Jardin 0.15 1500 meter ** 2 2.62 liter / second 14.18 meter ** 3\n", "Forêt 0.05 2000 meter ** 2 1.17 liter / second 6.30 meter ** 3\n", "------------------------------------------------------------\n", " TOTAL 96.71 meter ** 3\n" ] } ], "source": [ "# Sous-bassins : (nom, coefficient de ruissellement, superficie)\n", "sous_bassins = [\n", " (\"Parking\", 0.9, 800 * U.meter**2),\n", " (\"Toitures\", 1.0, 350 * U.meter**2),\n", " (\"Trottoirs\", 0.7, 200 * U.meter**2),\n", " (\"Jardin\", 0.15, 0.15 * U.hectare),\n", " (\"Forêt\", 0.05, 0.2 * U.hectare),\n", "]\n", "\n", "# Pluie de projet\n", "intensite = 42.0 * U.mm / U.hour\n", "duree = 1.5 * U.hour\n", "\n", "print(f\"{'Sous-bassin':<12} {'C':>4} {'Surface':>12} {'Q_net':>14} {'V_ruisselé':>12}\")\n", "print(\"-\" * 60)\n", "\n", "V_total = 0 * U.meter**3\n", "for nom, C, A in sous_bassins:\n", " Q = (C * A * intensite).to('liter/second')\n", " V = (Q * duree).to('m^3')\n", " V_total += V\n", " print(f\"{nom:<12} {C:>4.2f} {A.to('m^2'):>12.0f} {Q:>14.2f} {V:>12.2f}\")\n", "\n", "print(\"-\" * 60)\n", "print(f\"{'TOTAL':>32} {V_total:>28.2f}\")" ] }, { "cell_type": "markdown", "id": "75537b7b", "metadata": {}, "source": [ "### Débit de fuite (infiltration + réseau)\n", "\n", "Calcul du débit évacué par infiltration (loi de Darcy)\n", "et par le réseau (débit spécifique admissible) :" ] }, { "cell_type": "code", "execution_count": 12, "id": "cd19ac21", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Débit d'infiltration : 0.7500 liter / second\n", "Débit réseau : 2.4250 liter / second\n", "Débit de fuite total : 3.1750 liter / second\n", "\n", "Temps de vidange de 40 meter ** 3 : 3.5 hour\n" ] } ], "source": [ "# Paramètres d'infiltration\n", "A_infil = 150 * U.meter**2\n", "K_darcy = 1e-5 * U.meter / U.second\n", "facteur_secu = 2.0\n", "\n", "Q_infil = (A_infil * K_darcy / facteur_secu).to('liter/second')\n", "print(f\"Débit d'infiltration : {Q_infil:.4f}\")\n", "\n", "# Débit admissible vers le réseau\n", "q_adm = 5.0 * U.liter / U.second / U.hectare\n", "A_tot = sum(A for __, __, A in sous_bassins).to('hectare')\n", "\n", "Q_reseau = (q_adm * A_tot).to('liter/second')\n", "print(f\"Débit réseau : {Q_reseau:.4f}\")\n", "\n", "Q_fuite = Q_infil + Q_reseau\n", "print(f\"Débit de fuite total : {Q_fuite:.4f}\")\n", "\n", "# Temps de vidange d'un bassin de 40 m³\n", "V_bassin = 40 * U.meter**3\n", "t_vidange = (V_bassin / Q_fuite).to('hour')\n", "print(f\"\\nTemps de vidange de {V_bassin} : {t_vidange:.1f}\")" ] }, { "cell_type": "markdown", "id": "5eaf332d", "metadata": {}, "source": [ "## 8. Pièges courants\n", "\n", "### Incompatibilité dimensionnelle\n", "\n", "Additionner des grandeurs de dimensions différentes lève une erreur :" ] }, { "cell_type": "code", "execution_count": 13, "id": "0612b557", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Erreur attendue : Cannot convert from 'meter' ([length]) to 'second' ([time])\n" ] } ], "source": [ "try:\n", " resultat = 10 * U.meter + 5 * U.second\n", "except pint.DimensionalityError as e:\n", " print(f\"Erreur attendue : {e}\")" ] }, { "cell_type": "markdown", "id": "ccab3d69", "metadata": {}, "source": [ "### Registres différents\n", "\n", "Des grandeurs créées à partir de registres différents sont\n", "**incompatibles**, même si les unités ont le même nom :" ] }, { "cell_type": "code", "execution_count": 14, "id": "93c0dd0e", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Erreur : ValueError\n", "→ Toujours utiliser le même registre (UNITS dans wolfhece) !\n" ] } ], "source": [ "U1 = pint.UnitRegistry()\n", "U2 = pint.UnitRegistry()\n", "\n", "a = 10 * U1.meter\n", "b = 5 * U2.meter\n", "\n", "try:\n", " c = a + b\n", "except Exception as e:\n", " print(f\"Erreur : {type(e).__name__}\")\n", " print(\"→ Toujours utiliser le même registre (UNITS dans wolfhece) !\")" ] }, { "cell_type": "markdown", "id": "fb695a8d", "metadata": {}, "source": [ "### Passage à NumPy\n", "\n", "Les `Quantity` fonctionnent avec les tableaux NumPy.\n", "Attention toutefois à extraire `.magnitude` avant de passer\n", "les valeurs à des fonctions qui n'acceptent pas les unités\n", "(matplotlib, fichiers, …) :" ] }, { "cell_type": "code", "execution_count": 15, "id": "d5dba6c7", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Somme : 11.799999999999999 liter / second\n", "Moyenne : 2.9499999999999997 liter / second\n", "Max : 5.0 liter / second\n", "\n", "Tableau brut (m³/s) : [0.0012 0.0035 0.005 0.0021]\n" ] } ], "source": [ "import numpy as np\n", "\n", "debits = np.array([1.2, 3.5, 5.0, 2.1]) * U.liter / U.second\n", "\n", "print(f\"Somme : {debits.sum()}\")\n", "print(f\"Moyenne : {debits.mean()}\")\n", "print(f\"Max : {debits.max()}\")\n", "\n", "# Conversion en m³/s et extraction pour matplotlib\n", "debits_m3s = debits.to('m^3/s').magnitude\n", "print(f\"\\nTableau brut (m³/s) : {debits_m3s}\")" ] }, { "cell_type": "markdown", "id": "6e7ef36d", "metadata": {}, "source": [ "### Chaîne de caractères comme unité\n", "\n", "`.to()` accepte soit un objet unité, soit une **chaîne** :" ] }, { "cell_type": "code", "execution_count": 16, "id": "4c1d9534", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0.5 hectare\n", "0.5 hectare\n", "0.005 kilometer ** 2\n" ] } ], "source": [ "s = 5000 * U.meter**2\n", "\n", "# Objet unité\n", "print(s.to(U.hectare))\n", "\n", "# Chaîne de caractères (syntaxe pint)\n", "print(s.to('hectare'))\n", "print(s.to('km^2'))" ] } ], "metadata": { "kernelspec": { "display_name": "python311", "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.11.9" } }, "nbformat": 4, "nbformat_minor": 5 }