7. Analyse du changement climatique sur des données hydrologiques

[1]:
# Imports
# Hide INFO-level logs
import logging
from pathlib import Path

import hvplot.xarray  # noqa
import numpy as np
import pooch
import xarray as xr
import xclim

import xhydro as xh
from xhydro.testing.helpers import deveraux

logger = logging.getLogger()
logger.setLevel(logging.CRITICAL)

D = deveraux()

# Streamflow file (1 file - Hydrotel driven by BCC-CSM-1.1(m))
streamflow_file = D.fetch(
    "cc_indicators/streamflow_BCC-CSM1.1-m_rcp45.nc",
)

# Reference QMOYAN (6 platforms)
reference_files = D.fetch("cc_indicators/reference.zip", pooch.Unzip())

# QMOYAN deltas (63 simulations x 6 platforms)
deltas_files = D.fetch("cc_indicators/deltas.zip", pooch.Unzip())
ERROR 1: PROJ: proj_create_from_database: Open of /home/docs/checkouts/readthedocs.org/user_builds/xhydro-fr/conda/latest/share/proj failed

Bien qu’il existe une grande variété d’analyses qui pourraient être effectuées pour évaluer les impacts du changement climatique sur l’hydrologie, ce notebook passera en revue certaines des étapes les plus courantes :

  • Calculer une liste d’indicateurs pertinents sur des périodes climatologiques

  • Calculer des deltas futurs

  • Calculer des statistiques d’ensemble pour évaluer les changements futurs

INFO

Plusieurs fonctions dans xh.indicators et xh.cc proviennent de la librairie xscen et sont rendues accessibles aux utilisateurs de xhydro. Pour plus d’informations sur ces fonctions, il est recommandé de consulter :

7.1. Calculer des indicateurs hydrologiques sur une période donnée

[2]:
# The file used as an example is a daily timeseries of streamflow data generated from the Hydrotel hydrological model
# driven by bias-adjusted data from the BCC-CSM-1.1(m) climatological model (RCP4.5), from 1950 to 2100.
# For this example, the dataset covers only 2 stations.
ds = xr.open_dataset(streamflow_file)
ds.streamflow.hvplot(x="time", grid=True, widget_location="bottom", groupby="station")
[2]:

Les indicateurs hydrologiques peuvent être séparés en deux grandes catégories :

  • Indicateurs fréquentiels, tels que le débit maximum sur 20 ans (Qmax20) ou le débit minimum moyenné sur 7 jours de récurrence 2 ans en été (Q7min2_summer). Leur calcul est déjà couvert dans le notebook Analyses fréquentielles locales.

  • Indicateurs non fréquentiels, comme le débit annuel moyen.

Puisque les indicateurs fréquentiels ont déjà été abordés dans un autre exemple, ce notebook examinera plutôt la méthodologie qui serait utilisée pour calculer les indicateurs non fréquentiels à l’aide de xhydro.indicators.compute_indicators. Les entrées de cette fonction sont :

  • ds: le jeu de données.

  • indicators : une liste d’indicateurs à calculer, ou le chemin d’accès à un fichier YAML contenant ceux-ci.

  • periods (facultatif) : soit [début, fin], soit une liste de [début, fin] pour des périodes continues sur lesquelles calculer les indicateurs.

INFO

Les indicateurs personnalisés sont construits en suivant le formatage YAML requis par xclim. Plus d’informations sont disponibles dans la documentation xclim.

La liste des identifiants Yaml est disponible ici.

[3]:
# We'll define 2 indicators to compute by using dictionaries.
#
# We minimally need to define three things under `data`:
#    1. 'base': A base indicator for the computation, identified through its Yaml ID (here, 'stats').
#    2. 'parameters': Specific parameters to use instead of the defaults.
#      - This potentially includes a 'indexer' parameter to focus on particular periods of the year.
#    3. 'input': The name of the input variable. The key here must be the variable name used by xclim (here, 'da').
#
# The 'identifier' is the label that will be given by 'xclim' to the new indicator. The 'module' can be anything.

indicators = [
    # 1st indicator: Mean annual flow
    xclim.core.indicator.Indicator.from_dict(
        data={
            "base": "stats",
            "input": {"da": "streamflow"},
            "parameters": {"op": "mean"},
        },
        identifier="QMOYAN",
        module="hydro",
    ),
    # 2nd indicator: Mean summer-fall flow
    xclim.core.indicator.Indicator.from_dict(
        data={
            "base": "stats",
            "input": {"da": "streamflow"},
            "parameters": {"op": "mean", "indexer": {"month": [6, 7, 8, 9, 10, 11]}},
        },  # The indexer is used to restrict available data to the relevant months only
        identifier="QMOYEA",
        module="hydro",
    ),
]

# Call compute_indicators
dict_indicators = xh.indicators.compute_indicators(ds, indicators=indicators)

dict_indicators
[3]:
{'YS-JAN': <xarray.Dataset> Size: 4kB
 Dimensions:        (station: 2, time: 151)
 Coordinates:
     lat            (station) float32 8B 49.53 49.53
     lon            (station) float32 8B -77.05 -77.02
     drainage_area  (station) float32 8B 60.76 54.61
   * station        (station) <U9 72B 'ABIT00057' 'ABIT00058'
   * time           (time) datetime64[ns] 1kB 1950-01-01 ... 2100-01-01
 Data variables:
     QMOYAN         (station, time) float32 1kB nan nan nan ... 0.8027 0.743 nan
     QMOYEA         (station, time) float32 1kB nan nan nan ... 0.385 1.035
 Attributes: (12/48)
     institution:                    DEH (Direction de l'Expertise Hydrique)
     institute_id:                   DEH
     contact:                        atlas.hydroclimatique@environnement.gouv....
     date_created:                   2020-05-23
     featureType:                    timeSeries
     cdm_data_type:                  station
     ...                             ...
     cat:bias_adjust_project:        INFO-Crue-CM5
     cat:mip_era:                    CMIP5
     cat:activity:                   CMIP5
     cat:experiment:                 rcp45
     cat:member:                     r1i1p1
     cat:bias_adjust_institution:    OURANOS}
[4]:
dict_indicators["YS-JAN"].QMOYAN.hvplot(
    x="time", grid=True, widget_location="bottom", groupby="station"
)
[4]:

Puisque les indicateurs peuvent être générés à des fréquences variables, compute_indicators renverra un dictionnaire dont les clés sont les fréquences de sortie. Dans cet exemple, nous n’avons qu’une seule clé : AS-JAN (données annuelles commençant en janvier). Les clés suivent la nomenclature pandas.

L’étape suivante consiste à obtenir des moyennes sur des périodes climatologiques. La fonction xh.cc.climatological_op peut être appelée à cet effet. Les entrées de cette fonction sont :

  • ds : le jeu de données à utiliser pour le calcul.

  • op : Opération à effectuer dans le temps. Bien que d’autres opérations soient techniquement possibles, les opérations suivantes sont recommandées et testées : [“max”, “mean”, “median”, “min”, “std”, “sum”, “var”, “linregress”].

  • window (facultatif) : Nombre d’années à utiliser pour la fenêtre mobile. Si None, toutes les données disponibles seront utilisées.

  • min_periods (facultatif) : pour la fenêtre mobile, nombre minimum d’années requis pour qu’une valeur soit calculée.

  • stride : foulée (en années) à laquelle fournir un résultat de l’opération de fenêtre mobile.

  • periods (facultatif) : Soit [début, fin], soit une liste de [début, fin] de périodes continues à prendre en compte.

  • rename_variables : Si True, “clim{op}” sera ajouté aux noms de variables.

  • horizons_as_dim : Si True, la sortie aura « horizon » et la fréquence sous forme de « month », « season » ou « year » comme dimensions et coordonnées.

[5]:
# Define the periods using a list of lists
periods = [[1981, 2010], [2011, 2040], [2041, 2070], [2071, 2100]]
min_periods = 29  # This is an example of a model where the data stops in 2099, so we can use 'min_periods' to still obtain a value for the last period

# Call climatological_op. Here we don't need 'time' anymore, so we can use horizons_as_dim=True
ds_avg = xh.cc.climatological_op(
    dict_indicators["YS-JAN"],
    op="mean",
    periods=periods,
    min_periods=min_periods,
    horizons_as_dim=True,
    rename_variables=False,
).drop_vars(["time"])
ds_avg
[5]:
<xarray.Dataset> Size: 304B
Dimensions:        (horizon: 4, station: 2)
Coordinates:
    lat            (station) float32 8B 49.53 49.53
    lon            (station) float32 8B -77.05 -77.02
    drainage_area  (station) float32 8B 60.76 54.61
  * station        (station) <U9 72B 'ABIT00057' 'ABIT00058'
  * horizon        (horizon) <U9 144B '1981-2010' '2011-2040' ... '2071-2100'
Data variables:
    QMOYAN         (horizon, station) float32 32B 0.8968 0.8041 ... 0.7745
    QMOYEA         (horizon, station) float32 32B 0.9335 0.8379 ... 0.6966
Attributes: (12/48)
    institution:                    DEH (Direction de l'Expertise Hydrique)
    institute_id:                   DEH
    contact:                        atlas.hydroclimatique@environnement.gouv....
    date_created:                   2020-05-23
    featureType:                    timeSeries
    cdm_data_type:                  station
    ...                             ...
    cat:bias_adjust_project:        INFO-Crue-CM5
    cat:mip_era:                    CMIP5
    cat:activity:                   CMIP5
    cat:experiment:                 rcp45
    cat:member:                     r1i1p1
    cat:bias_adjust_institution:    OURANOS

Calculer des deltas est alors aussi simple que d’appeler xh.cc.compute_deltas. Les entrées de cette fonction sont :

  • ds : le jeu de données à utiliser pour le calcul.

  • reference_horizon : soit une chaîne YYYY-YYYY correspondant à la coordonnée « horizon » de la période de référence, soit un xr.Dataset contenant la moyenne climatologique.

  • kind : [“+”, “/”, “%”] Indique s’il faut fournir des deltas absolus, relatifs ou en pourcentage. Peut également être un dictionnaire séparé par nom de variable.

[6]:
# Here, we'll use a string from the 'horizon' dimension.
reference_horizon = "1981-2010"
kind = "%"

ds_deltas = xh.cc.compute_deltas(
    ds_avg, reference_horizon=reference_horizon, kind=kind, rename_variables=False
)
ds_deltas
[6]:
<xarray.Dataset> Size: 304B
Dimensions:        (station: 2, horizon: 4)
Coordinates:
    lat            (station) float32 8B 49.53 49.53
    lon            (station) float32 8B -77.05 -77.02
    drainage_area  (station) float32 8B 60.76 54.61
  * station        (station) <U9 72B 'ABIT00057' 'ABIT00058'
  * horizon        (horizon) <U9 144B '1981-2010' '2011-2040' ... '2071-2100'
Data variables:
    QMOYAN         (horizon, station) float32 32B 0.0 0.0 4.273 ... -3.64 -3.678
    QMOYEA         (horizon, station) float32 32B 0.0 0.0 ... -16.67 -16.86
Attributes: (12/48)
    institution:                    DEH (Direction de l'Expertise Hydrique)
    institute_id:                   DEH
    contact:                        atlas.hydroclimatique@environnement.gouv....
    date_created:                   2020-05-23
    featureType:                    timeSeries
    cdm_data_type:                  station
    ...                             ...
    cat:bias_adjust_project:        INFO-Crue-CM5
    cat:mip_era:                    CMIP5
    cat:activity:                   CMIP5
    cat:experiment:                 rcp45
    cat:member:                     r1i1p1
    cat:bias_adjust_institution:    OURANOS
[7]:
# Show the results as Dataframes
print("30-year averages")
display(ds_avg.QMOYAN.isel(station=0).to_dataframe())
print("Deltas")
display(ds_deltas.QMOYAN.isel(station=0).to_dataframe())
30-year averages
lat lon drainage_area station QMOYAN
horizon
1981-2010 49.529999 -77.050003 60.759998 ABIT00057 0.896769
2011-2040 49.529999 -77.050003 60.759998 ABIT00057 0.935091
2041-2070 49.529999 -77.050003 60.759998 ABIT00057 0.944270
2071-2100 49.529999 -77.050003 60.759998 ABIT00057 0.864129
Deltas
lat lon drainage_area station QMOYAN
horizon
1981-2010 49.529999 -77.050003 60.759998 ABIT00057 0.000000
2011-2040 49.529999 -77.050003 60.759998 ABIT00057 4.273284
2041-2070 49.529999 -77.050003 60.759998 ABIT00057 5.296827
2071-2100 49.529999 -77.050003 60.759998 ABIT00057 -3.639797

7.2. Statistiques d’ensemble

[8]:
# To save time, let's open pre-computed deltas for the RCP4.5 simulations used in the 2022 Hydroclimatic Atlas
ds_dict_deltas = {}
for f in deltas_files:
    id = Path(f).stem
    ds_dict_deltas[id] = xr.open_dataset(f)

C’est une bonne pratique d’utiliser plusieurs modèles climatiques pour effectuer des analyses du changement climatique, d’autant plus que les impacts sur le cycle hydrologique peuvent être non linéaires. Une fois que plusieurs simulations hydrologiques ont été exécutées et sont prêtes à être analysées, xh.cc.ensemble_stats peut être utilisé pour appeler une variété de fonctions disponibles dans xclim.ensemble, comme pour obtenir des quantiles d’ensemble ou l’e “accord sur le signe du changement.

7.2.1. Pondération des simulations

Si l’ensemble de modèles climatiques est hétérogène, par exemple si un modèle climatique donné a fourni davantage de simulations, il est recommandé de pondérer les résultats en conséquence. Bien que cela ne soit pas actuellement disponible via xhydro, xscen.generate_weights peut créer une première approximation des poids à utiliser, basée sur les métadonnées disponibles.

Les attributs suivants sont requis pour que la fonction fonctionne :

  • “cat:source” dans tous les ensembles de données

  • “cat:driving_model” dans les modèles climatiques régionaux

  • “cat:institution” dans tous les jeux de données si independence_level=”institution”

  • “cat:experiment” dans tous les jeux de données si split_experiments=True

Cette fonction a trois niveaux d’indépendance possibles :

  • model : 1 Modèle - 1 Vote

  • GCM : 1 GCM - 1 Vote

  • institution : 1 institution - 1 Vote

[9]:
import xscen

independence_level = "model"  # 1 Model - 1 Vote

weights = xscen.generate_weights(ds_dict_deltas, independence_level=independence_level)

# Show the results. We multiply by 6 for the showcase here simply because there are 6 hydrological platforms in the results.
weights.where(weights.realization.str.contains("LN24HA"), drop=True) * 6
[9]: