Dimensionnement d’un bassin de rétention — Méthodologie SPW

Ce notebook illustre l’utilisation de la classe MockupSPWXLSX du module wolfhece.mockup_spw_xlsx pour dimensionner un bassin de rétention d’eaux pluviales selon la méthodologie du SPW (Service Public de Wallonie).

Sommaire

  1. Imports et initialisations

  2. Définition du projet

  3. Paramètres d’infiltration et de rejet

  4. Calcul de la capacité de rétention

  5. Rapport de synthèse

  6. Graphiques

  7. Export / Import JSON

  8. Analyse de sensibilité

  9. Impact du changement climatique

  10. Factory ``MockupSPWXLSX.make()` <#10.-Factory-MockupSPWXLSX.make()>`__

1. Imports et initialisations

On importe la classe principale MockupSPWXLSX, le registre d’unités UNITS (basé sur pint) et l’énumération LandUse qui regroupe les types d’occupation du sol avec leurs coefficients de ruissellement.

Note : pour une introduction à pint et à la manipulation des unités de surface, de débit et de longueur en hydrologie, voir le notebook dédié : pint_unites.ipynb.

[ ]:

from wolfhece import check_version check_version("2.2.74") from wolfhece.mockup_spw_xlsx import MockupSPWXLSX, UNITS, LandUse # Pour l'affichage des graphiques dans le notebook %matplotlib inline import matplotlib.pyplot as plt
INFO:root:Version de wolfhece : 2.2.73 ou supérieure est installée.

Rappel des types d’occupation du sol disponibles

Chaque membre de LandUse possède un nom, une description et un coefficient de ruissellement (C) :

[2]:
LandUse.print_summary()
Name                      Description                                              C [-]
----------------------------------------------------------------------------------------
Forest                    Forêts et bois                                            0.05
Grassland                 Prairies, jardins et zones enherbées                      0.15
Fields                    Champs cultivés, landes et broussailles                   0.25
Green Roofs               Dalles de gazon et toitures vertes                        0.40
Bare Soil                 Terres battues et toitures vertes                         0.50
Drained Paving            Pavés à joints écartés et pavés drainants                 0.70
Impervious Surfaces       Allées pavées, trottoirs pavés et parkings                0.90
Water and Roofs           Toitures, routes et plans d'eau                           1.00

2. Définition du projet

On crée une instance de MockupSPWXLSX et on configure :

  • La localité (commune belge, identifiée par son code NIS ou son nom) ;

  • Les sous-bassins avec leur type d’occupation du sol et leur superficie.

Les superficies peuvent être exprimées en (valeur numérique brute) ou en toute autre unité de surface via UNITS (hectare, km², …).

[3]:
m = MockupSPWXLSX()

# Choix de la localité — détermine les courbes IDF de l'IRM
m.set_locality("Liège")
print(f"Localité : {m.locality_name}  (NIS {m._locality_nsi})")
Localité : Liège  (NIS 62063)
[4]:
# Ajout des sous-bassins
# Chaque appel à add_area(clé, type_occupation, superficie)

m.add_area("parking",     LandUse.IMPERVIOUS_SURFACES,  800)                   # 800 m²
m.add_area("toitures",    LandUse.WATER_AND_ROOFS,      350)                   # 350 m²
m.add_area("trottoirs",   LandUse.DRAINED_PAVING,       200)                   # 200 m²
m.add_area("jardin",      LandUse.GRASSLANDS,           0.15 * UNITS.hectare)  # 1500 m²
m.add_area("potager",     LandUse.CULTIVATED_FIELDS,    300)                   # 300 m²
m.add_area("boisement",   LandUse.FORESTS,              0.2 * UNITS.hectare)   # 2000 m²

print(f"Surface totale          : {m.total_area.to('m^2'):.0f}")
print(f"Surface pondérée (C·A)  : {m.total_area_ponderated.to('m^2'):.1f}")
Surface totale          : 5150 meter ** 2
Surface pondérée (C·A)  : 1610.0 meter ** 2

3. Paramètres d’infiltration et de rejet

On définit :

Paramètre

Description

Unité par défaut

infiltration_area

Surface d’infiltration du bassin

infiltration_darcy

Conductivité hydraulique (loi de Darcy)

m/s

admissible_outflow

Débit de fuite admissible vers le réseau

L/s/ha (défaut 5)

Toutes les grandeurs physiques acceptent des valeurs brutes (interprétées dans l’unité par défaut) ou des pint.Quantity pour une conversion automatique.

[5]:
# Surface d'infiltration : 150 m²
m.infiltration_area = 150 * UNITS.meter**2

# Conductivité hydraulique : 1×10⁻⁵ m/s (on peut aussi écrire en mm/h)
m.infiltration_darcy = 1e-5 * UNITS.meter / UNITS.second
# Équivalent : m.infiltration_darcy = 36 * UNITS.mm / UNITS.hour

# Débit de fuite admissible : 5 L/s/ha
m.admissible_outflow = 5.0  # valeur numérique → L/s/ha par défaut

print(f"Surface infiltration    : {m.infiltration_area:.0f}")
print(f"Darcy                   : {m.infiltration_darcy:.2e}")
print(f"    (soit               : {m.infiltration_darcy.to('mm/h'):.2f})")
print(f"Débit admissible        : {m.admissible_outflow:.1f}")
Surface infiltration    : 150 meter ** 2
Darcy                   : 1.00e-05 meter / second
    (soit               : 36.00 millimeter / hour)
Débit admissible        : 5.0 liter / hectare / second

4. Calcul de la capacité de rétention

La méthode get_retention_capacity() réalise les opérations suivantes :

  1. Récupération du hyétogramme de Chicago pour la période de retour choisie (courbes IDF de l’IRM, localité sélectionnée) ;

  2. Conversion de la pluie brute en apport net via le coefficient de ruissellement pondéré ;

  3. Calcul du débit de fuite (infiltration + rejet réseau) ;

  4. Détermination du volume de rétention nécessaire (cumul des excédents positifs au pas de temps dt = 5 min).

Le résultat est un pint.Quantity en . Les propriétés design_rainfall_duration et emptying_time sont également calculées.

[6]:
# Période de retour de 25 ans (valeur par défaut)
volume = m.get_retention_capacity(return_period=25)

print(f"Volume de rétention     : {volume:.2f}")
print(f"Durée pluie de projet   : {m.design_rainfall_duration.to('hour'):.2f}")
print(f"Temps de vidange        : {m.emptying_time.to('hour'):.2f}")
print(f"Volume spécifique       : {volume.magnitude / m.total_area.magnitude * 1000:.1f} L/m²")
Volume de rétention     : 43.05 meter ** 3
Durée pluie de projet   : 1.00 hour
Temps de vidange        : 3.60 hour
Volume spécifique       : 8.4 L/m²

Calcul pour d’autres périodes de retour

[7]:
for T in [2, 5, 10, 25, 50, 100]:
    vol = m.get_retention_capacity(return_period=T)
    print(f"  T = {T:>3d} ans  →  V = {vol.to('m^3').magnitude:>8.2f} m³  |  "
          f"Durée pluie = {m.design_rainfall_duration.to('hour').magnitude:.1f} h  |  "
          f"Vidange = {m.emptying_time.to('hour').magnitude:.1f} h")
  T =   2 ans  →  V =    15.13 m³  |  Durée pluie = 0.5 h  |  Vidange = 1.3 h
  T =   5 ans  →  V =    24.56 m³  |  Durée pluie = 0.7 h  |  Vidange = 2.1 h
  T =  10 ans  →  V =    32.06 m³  |  Durée pluie = 0.8 h  |  Vidange = 2.7 h
  T =  25 ans  →  V =    43.05 m³  |  Durée pluie = 1.0 h  |  Vidange = 3.6 h
  T =  50 ans  →  V =    52.37 m³  |  Durée pluie = 1.2 h  |  Vidange = 4.4 h
  T = 100 ans  →  V =    62.68 m³  |  Durée pluie = 1.3 h  |  Vidange = 5.2 h

5. Rapport de synthèse

La méthode generate_report() produit un rapport texte structuré reprenant l’ensemble des données d’entrée et des résultats.

[8]:
# On recalcule pour T=25 afin d'avoir le rapport correspondant
m.get_retention_capacity(return_period=25)

rapport = m.generate_report()
print(rapport)
======================================================================
  STORMWATER RETENTION BASIN — SIZING REPORT (SPW methodology)
======================================================================

Locality            : Liège  (NSI 62063)
Return period       : 25 years

----------------------------------------------------------------------
Key             Land use                C [-]    Area [m²]
----------------------------------------------------------------------
parking         Impervious Surfaces      0.90        800.0
toitures        Water and Roofs          1.00        350.0
trottoirs       Drained Paving           0.70        200.0
jardin          Grassland                0.15       1500.0
potager         Fields                   0.25        300.0
boisement       Forest                   0.05       2000.0
----------------------------------------------------------------------
Total                                    0.31       5150.0
Weighted area                                       1610.0

----------------------------------------------------------------------
Infiltration & outflow parameters
----------------------------------------------------------------------
  Infiltration area          : 150.0 m²
  Darcy velocity             : 1.00e-05 m/s  (36.00 mm/h)
  Security factor            : 2.0
  Infiltration outflow       : 0.7500 L/s
  Admissible outflow         : 5.00 L/s/ha  (2.5750 L/s)
  Total outflow              : 3.3250 L/s

======================================================================
  RESULTS
======================================================================
  Retention capacity         : 43.05 m³
  Design rainfall duration   : 1.00 h
  Emptying time              : 3.60 h
  Specific volume            : 8.4 L/m²
======================================================================

6. Graphiques

Quatre méthodes de visualisation sont disponibles :

Méthode

Contenu

plot_hyetograph()

Hyétogramme de Chicago (intensité vs temps)

plot_volume_balance()

Bilan volumique : débit entrant, sortant et volume stocké

plot_land_use()

Diagramme circulaire de la répartition des surfaces

plot_summary()

Figure composite regroupant les trois graphiques

Chaque méthode accepte un paramètre ax optionnel pour intégrer le graphique dans une figure personnalisée.

6.1 Hyétogramme de Chicago

[9]:
m.plot_hyetograph(show=False)
plt.show()
../_images/tutorials_bassin_retention_spw_18_0.png

6.2 Bilan volumique

Le graphique à double axe montre :

  • En bleu : le débit net entrant (pluie × C × A) en L/s

  • En rouge pointillé : le débit de fuite total en L/s

  • En vert (aire remplie) : le volume cumulé stocké en m³

[10]:
m.plot_volume_balance(show=False)
plt.show()
../_images/tutorials_bassin_retention_spw_20_0.png

6.3 Répartition des surfaces par occupation du sol

[11]:
m.plot_land_use(show=False)
plt.show()
../_images/tutorials_bassin_retention_spw_22_0.png

6.4 Figure de synthèse

[12]:
fig = m.plot_summary(show=False)
plt.show()

# Pour sauvegarder la figure :
# fig.savefig("rapport_bassin_retention.png", dpi=150, bbox_inches="tight")
../_images/tutorials_bassin_retention_spw_24_0.png

7. Export / Import JSON

Le projet peut être sauvegardé au format JSON pour archivage ou rechargement ultérieur. Toutes les grandeurs sont sérialisées en unités SI (m², m/s, L/s/ha).

[13]:
import tempfile, json
from pathlib import Path

# Export
output_dir = Path(tempfile.mkdtemp())
json_path = output_dir / "projet_bassin.json"
m.to_json(json_path)

# Affichage du contenu JSON
with open(json_path) as f:
    print(json.dumps(json.load(f), indent=2, ensure_ascii=False))
{
  "locality_nsi": 62063,
  "reference_area_m2": 0,
  "infiltration_area_m2": 150,
  "infiltration_darcy_m_per_s": 1e-05,
  "infiltration_security_factor": 2.0,
  "admissible_outflow_l_per_s_per_ha": 5.0,
  "climate_delta_t": 0.0,
  "climate_rate": 0.07,
  "areas": {
    "parking": {
      "land_use": "IMPERVIOUS_SURFACES",
      "area_m2": 800
    },
    "toitures": {
      "land_use": "WATER_AND_ROOFS",
      "area_m2": 350
    },
    "trottoirs": {
      "land_use": "DRAINED_PAVING",
      "area_m2": 200
    },
    "jardin": {
      "land_use": "GRASSLANDS",
      "area_m2": 1500.0
    },
    "potager": {
      "land_use": "CULTIVATED_FIELDS",
      "area_m2": 300
    },
    "boisement": {
      "land_use": "FORESTS",
      "area_m2": 2000.0
    }
  }
}
[14]:
# Rechargement depuis le fichier JSON
m2 = MockupSPWXLSX.from_json(json_path)

# Vérification
print(f"Localité rechargée      : {m2.locality_name}")
print(f"Nombre de sous-bassins  : {len(m2.areas)}")
print(f"Surface totale          : {m2.total_area:.0f}")

# Recalcul sur le projet rechargé
vol2 = m2.get_retention_capacity(return_period=25)
print(f"Volume (rechargé)       : {vol2:.2f}")
print(f"Volume (original)       : {volume:.2f}")
Localité rechargée      : Liège
Nombre de sous-bassins  : 6
Surface totale          : 5150 meter ** 2
Volume (rechargé)       : 43.05 meter ** 3
Volume (original)       : 43.05 meter ** 3

8. Analyse de sensibilité

La classe intègre deux méthodes dédiées :

Méthode

Description

run_sensitivity(parameter, values)

Balaye un paramètre sur une plage de valeurs et renvoie un DataFrame (volume, durée pluie, temps de vidange)

plot_sensitivity(parameter, values)

Idem + graphique automatique

Paramètres supportés : "admissible_outflow", "infiltration_darcy", "infiltration_area", "infiltration_security_factor", "return_period".

La valeur originale du paramètre est automatiquement restaurée après le balayage.

[15]:
import numpy as np

# --- 8.1  Influence du débit de fuite admissible ---
ax, df_q = m.plot_sensitivity(
    "admissible_outflow",
    np.linspace(0, 20, 21),   # 0 → 20 L/s/ha
    show=False,
)
ax.axvline(5.0, color='red', ls='--', alpha=0.7, label='Réf. (5 L/s/ha)')
ax.legend()
plt.tight_layout(); plt.show()

# Le DataFrame contient toutes les valeurs calculées
df_q.head()
../_images/tutorials_bassin_retention_spw_29_0.png
[15]:
parameter volume_m3 duration_h emptying_h
0 0.0 67.286378 7.500000 24.920881
1 1.0 57.532655 3.833333 12.633433
2 2.0 51.933546 2.500000 8.104486
3 3.0 48.120372 1.666667 5.824301
4 4.0 45.299546 1.333333 4.478010
[16]:
# --- 8.2  Influence de la conductivité hydraulique (échelle log) ---
ax, df_k = m.plot_sensitivity(
    "infiltration_darcy",
    np.logspace(-7, -3, 30),  # 1e-7 → 1e-3 m/s
    show=False,
)
ax.axvline(1e-5, color='red', ls='--', alpha=0.7, label='Réf. (1e-5 m/s)')
ax.legend()
plt.tight_layout(); plt.show()
../_images/tutorials_bassin_retention_spw_30_0.png
[17]:
# --- 8.3  Influence de la période de retour ---
ax, df_t = m.plot_sensitivity(
    "return_period",
    [2, 5, 10, 25, 50, 100],
    show=False,
)
ax.axvline(25, color='red', ls='--', alpha=0.7, label='Réf. (T = 25 ans)')
ax.legend()
plt.tight_layout(); plt.show()
../_images/tutorials_bassin_retention_spw_31_0.png

Comparaison multi-paramètres

On peut combiner plusieurs analyses dans une même figure grâce au paramètre ax :

[16]:
fig, axes = plt.subplots(1, 3, figsize=(16, 5))

m.plot_sensitivity("admissible_outflow", np.linspace(0, 20, 21),
                   ax=axes[0], show=False)
m.plot_sensitivity("infiltration_darcy", np.logspace(-7, -3, 30),
                   ax=axes[1], show=False)
m.plot_sensitivity("return_period", [2, 5, 10, 25, 50, 100],
                   ax=axes[2], show=False)

fig.suptitle(f"Analyses de sensibilité — {m.locality_name}", fontweight="bold")
fig.tight_layout()
plt.show()
../_images/tutorials_bassin_retention_spw_33_0.png

9. Impact du changement climatique

En Belgique, on admettra qu’un réchauffement climatique entraîne une augmentation des précipitations de 7 % par degré de réchauffement. La classe MockupSPWXLSX intègre ce facteur via deux attributs :

  • climate_delta_t — écart de température en °C (par défaut 0)

  • climate_factor — facteur multiplicatif appliqué aux pluies : \(f = 1 + 0{,}07 \times \Delta T\)

Ainsi, pour un scénario à +2 °C, le facteur vaut 1,14 : l’intensité de pluie utilisée dans le dimensionnement est majorée de 14 %.

[17]:
# Volume de référence sans changement climatique
vol_ref = m.get_retention_capacity(25)
print(f"Volume de référence (ΔT = 0 °C) : {vol_ref.to('m^3'):.1f}")

# Scénario +2 °C
m.climate_delta_t = 2.0
vol_2deg = m.get_retention_capacity(25)
print(f"Volume scénario +2 °C (facteur {m.climate_factor:.2f}) : {vol_2deg.to('m^3'):.1f}")
print(f"Augmentation : +{(vol_2deg - vol_ref).to('m^3'):.1f}"
      f"  ({(vol_2deg / vol_ref - 1) * 100:.1f} %)")

# Retour à la situation actuelle
m.climate_delta_t = 0.0
Volume de référence (ΔT = 0 °C) : 43.0 meter ** 3
Volume scénario +2 °C (facteur 1.14) : 51.1 meter ** 3
Augmentation : +8.0 meter ** 3  (18.6 dimensionless %)

Analyse de sensibilité au réchauffement

On peut balayer une plage de ΔT (de 0 à 4 °C) pour visualiser l’impact sur le volume de rétention :

[18]:
import numpy as np

delta_t_values = np.arange(0, 4.5, 0.5)  # 0 à 4 °C par pas de 0.5
m.plot_sensitivity("climate_delta_t", delta_t_values)
../_images/tutorials_bassin_retention_spw_37_0.png
[18]:
(<Axes: title={'center': 'Sensibilité — climate_delta_t'}, xlabel='Réchauffement climatique ΔT [°C]', ylabel='Volume de rétention [m³]'>,
    parameter  volume_m3  duration_h  emptying_h
 0        0.0  43.045739    1.000000    3.596135
 1        0.5  45.035887    1.166667    3.762397
 2        1.0  47.031086    1.166667    3.929080
 3        1.5  49.026285    1.166667    4.095763
 4        2.0  51.057803    1.333333    4.265481
 5        2.5  53.115367    1.333333    4.437374
 6        3.0  55.172931    1.333333    4.609267
 7        3.5  57.249762    1.500000    4.782770
 8        4.0  59.363952    1.500000    4.959394)

Rapport avec prise en compte du changement climatique

Le rapport de synthèse affiche automatiquement la section « changement climatique » lorsque climate_delta_t est non nul :

[19]:
m.climate_delta_t = 2.0
m.get_retention_capacity(25)
print(m.generate_report())
m.climate_delta_t = 0.0  # reset
======================================================================
  STORMWATER RETENTION BASIN — SIZING REPORT (SPW methodology)
======================================================================

Locality            : Liège  (NSI 62063)
Return period       : 25 years

----------------------------------------------------------------------
Key             Land use                C [-]    Area [m²]
----------------------------------------------------------------------
parking         Impervious Surfaces      0.90        800.0
toitures        Water and Roofs          1.00        350.0
trottoirs       Drained Paving           0.70        200.0
jardin          Grassland                0.15       1500.0
potager         Fields                   0.25        300.0
boisement       Forest                   0.05       2000.0
----------------------------------------------------------------------
Total                                    0.31       5150.0
Weighted area                                       1610.0

----------------------------------------------------------------------
Infiltration & outflow parameters
----------------------------------------------------------------------
  Infiltration area          : 150.0 m²
  Darcy velocity             : 1.00e-05 m/s  (36.00 mm/h)
  Security factor            : 2.0
  Infiltration outflow       : 0.7500 L/s
  Admissible outflow         : 5.00 L/s/ha  (2.5750 L/s)
  Total outflow              : 3.3250 L/s

  Climate change ΔT          : +2.0 °C
  Rainfall increase rate     : 7 %/°C
  Climate factor             : 1.14  (×1.14 on rainfall)

======================================================================
  RESULTS
======================================================================
  Retention capacity         : 51.06 m³
  Design rainfall duration   : 1.33 h
  Emptying time              : 4.27 h
  Specific volume            : 9.9 L/m²
======================================================================

10. Factory MockupSPWXLSX.make()

Les sections précédentes montrent la construction pas à pas d’un projet (localité → sous-bassins → paramètres d’infiltration). Une fois la logique bien comprise, on peut utiliser la factory make() pour tout configurer en un seul appel :

m = MockupSPWXLSX.make(
    locality=...,
    areas={clé: (LandUse.XXX, superficie), ...},
    infiltration_area=...,
    infiltration_darcy=...,
    admissible_outflow=...,
)

Voici le même projet que celui défini dans les sections 2 et 3, reconstruit en une seule instruction :

[20]:
m_fast = MockupSPWXLSX.make(
    locality="Liège",
    areas={
        "parking":   (LandUse.IMPERVIOUS_SURFACES, 800),
        "toitures":  (LandUse.WATER_AND_ROOFS,     350),
        "trottoirs": (LandUse.DRAINED_PAVING,       200),
        "jardin":    (LandUse.GRASSLANDS,            0.15 * UNITS.hectare),
        "potager":   (LandUse.CULTIVATED_FIELDS,     300),
        "boisement": (LandUse.FORESTS,               0.2 * UNITS.hectare),
    },
    infiltration_area=150,
    infiltration_darcy=1e-5,
    admissible_outflow=5.0,
)

# Vérification rapide
vol_fast = m_fast.get_retention_capacity(25)
print(f"Volume (factory)  : {vol_fast:.2f}")
print(f"Volume (original) : {volume:.2f}")
print(f"Identiques ?        {abs(vol_fast.magnitude - volume.magnitude) < 1e-10}")
Volume (factory)  : 43.05 meter ** 3
Volume (original) : 43.05 meter ** 3
Identiques ?        True

On peut aussi intégrer directement le scénario climatique dans l’appel :

[21]:
m_climate = MockupSPWXLSX.make(
    locality="Namur",
    areas={
        "parking":  (LandUse.IMPERVIOUS_SURFACES, 1200),
        "toitures": (LandUse.WATER_AND_ROOFS,      500),
        "jardin":   (LandUse.GRASSLANDS,            0.3 * UNITS.hectare),
    },
    infiltration_area=200,
    infiltration_darcy=5e-6,
    admissible_outflow=5.0,
    climate_delta_t=2.0,
)

vol_cc = m_climate.get_retention_capacity(25)
print(f"Localité           : {m_climate.locality_name}")
print(f"Facteur climatique : ×{m_climate.climate_factor:.2f}")
print(f"Volume de rétention: {vol_cc:.2f}")
print(f"Durée pluie projet : {m_climate.design_rainfall_duration.to('hour'):.2f}")
print(f"Temps de vidange   : {m_climate.emptying_time.to('hour'):.2f}")
Localité           : Namur
Facteur climatique : ×1.14
Volume de rétention: 71.85 meter ** 3
Durée pluie projet : 2.17 hour
Temps de vidange   : 7.00 hour