"""The main function for HSAMI+ model simulation."""
from __future__ import annotations
from copy import copy
import numpy as np
from hsamiplus.hsami2_noyau import hsami2_noyau
[docs]
def hsami2(projet):
"""
Simulation du modèle HSAMI.
Parameters
----------
projet : dict
Dictionnaire contenant des données d'entrée.
Returns
-------
s : dict
Sorties de simulation.
etats: dict
États du bassin versants et du réservoir.
deltas: dict
Composants du bilan massique.
Raises
------
ValueError
Si la superficie maximale de la zone humide équivalente est nulle lorsque le module « mhumide » est utilisé.
Notes
-----
Fonction principale pour la simulation du modèle HSAMI.
Simuler les processus hydrologiques en fonction des paramètres du projet donnés.
projet : dict, un dictionnaire contenant des données d'entrée :
- param : liste, 50 parametres du modèle
- modules : dict, lchoix de modules
- physio : dict, qui contient d'information physiologique
- superficie : liste, superfice du BV est de reservoir
- meteo : ditc, données météo
s : dict, un dictionnaire contenant les sorties de simulation avec les clés :
- 'Qtotal': liste de float
- 'Qbase': liste de float
- 'Qinter': liste de float
- 'Qsurf': liste de float
- 'Qreservoir': liste de float
- 'Qglace': liste de float
- 'ETP': liste de float
- 'ETRtotal': liste de float
- 'ETRsublim': liste de float
- 'ETRPsurN': liste de float
- 'ETRintercept': liste de float
- 'ETRtranspir': liste de float
- 'ETRreservoir': liste de float
- 'ETRmhumide': liste de float
- 'Qmh': liste de float
etats : dict
Un dictionnaire contenant les états de la simulation à chaque pas de temps.
deltas : dict
Un dictionnaire contenant les composants du bilan massique avec les clés :
- 'total': liste de float
- 'glace': liste de float
- 'interception': liste de float
- 'ruissellement': liste de float
- 'vertical': liste de float
- 'mhumide': liste de float
- 'horizontal': liste de float
Développé par J.L. Bisson et F. Roberge dans Matlab, 1983.
Modifié et bonifié par Catherine Guay, Marie Minville, Isabelle Chartier et Jonathan Roy, 2013-2017.
Traduit en Python par Didier Haguma, 2024.
"""
# Extraction de variables de la structure projet
# ----------------------------------------------
superficie = projet["superficie"]
if len(superficie) == 1:
superficie.append(0)
param = projet["param"]
# Replace missing values by np.nan
for i, param_i in enumerate(param):
if param_i is None:
param[i] = np.nan
physio = projet["physio"]
# Valeurs par défaut dans modules
# -----------------------------------
modules = projet["modules"]
modules_par_defaut(modules)
# ------------------------
# Initialisation des etats
# ------------------------
# Dictionnaire états entrants
# ------------------------
etat = {}
etat["eau_hydrogrammes"] = np.zeros((int(projet["memoire"]), 3))
if modules["een"] in ["mdj", "alt"]:
if modules["een"] == "mdj":
n = len(physio["occupation"])
if modules["een"] == "alt":
n = len(physio["occupation_bande"])
etat["modules"] = {}
etat[modules["een"]] = {
"couvert_neige": [0] * n,
"densite_neige": [0] * n,
"albedo_neige": [0.9] * n,
"neige_au_sol": [0] * n,
"fonte": [0] * n,
"gel": [0] * n,
"sol": [0] * n,
"energie_neige": [0] * n,
"energie_glace": 0,
}
etat["neige_au_sol"] = 0
etat["fonte"] = 0
etat["nas_tot"] = 0
etat["fonte_tot"] = 0
etat["derniere_neige"] = 0
etat["gel"] = 0
etat["nappe"] = param[13]
etat["reserve"] = 0
if modules["sol"] == "hsami":
# Initialisation du sol à sol_min.
etat["sol"] = np.array([param[11], np.nan])
elif modules["sol"] == "3couches":
# Initialisation du sol à la capacité au champ.
etat["sol"] = np.array([param[42] * param[39], param[43] * param[40]])
if modules["mhumide"] == 1:
if physio["samax"] == 0:
raise ValueError(
"La superficie maximale du milieu humide \
équivalent est égale à 0."
)
etat["mh_surf"] = param[48] * physio["samax"] * 100 # On considère la surface initiale égale à la surface normale (en hectars)
etat["mh_vol"] = param[48] * (param[47] * physio["samax"] * 100 * 10000) # On considère le volume initial au volume normal (en m^3)
etat["ratio_MH"] = etat["mh_surf"] / (superficie[0] * 100)
if modules["mhumide"] == 0:
etat["mh_vol"] = 0
etat["ratio_MH"] = 0
etat["mh_surf"] = 1
etat["mhumide"] = etat["mh_vol"] * etat["ratio_MH"] / (etat["mh_surf"] * 100)
etat["ratio_qbase"] = 0
# Glace/réservoir
etat["cumdegGel"] = 0
etat["obj_gel"] = -200
etat["dernier_gel"] = 0
etat["reservoir_epaisseur_glace"] = 0
etat["reservoir_energie_glace"] = 0
etat["reservoir_superficie"] = superficie[1]
etat["reservoir_superficie_glace"] = 0
etat["reservoir_superficie_ref"] = etat["reservoir_superficie"]
etat["eeg"] = np.zeros(5000)
etat["ratio_bassin"] = 1
etat["ratio_reservoir"] = 0
etat["ratio_fixe"] = 1
# Structure états sortants
# ------------------------
nb_pas_total = len(projet["meteo"]["bassin"])
etats = {}
f = list(etat.keys())
for i_f in range(len(f)):
etats[f[i_f]] = []
# ----------------------
# Structure des sorties
# ----------------------
s = {
"Qtotal": [],
"Qbase": [],
"Qinter": [],
"Qsurf": [],
"Qreservoir": [],
"Qglace": [],
"ETP": [],
"ETRtotal": [],
"ETRsublim": [],
"ETRPsurN": [],
"ETRintercept": [],
"ETRtranspir": [],
"ETRreservoir": [],
"ETRmhumide": [],
"Qmh": [],
"Dates": projet["dates"],
}
deltas = {
"total": [],
"glace": [],
"interception": [],
"ruissellement": [],
"vertical": [],
"mhumide": [],
"horizontal": [],
}
# Conditions initiales
etat = hsami_etat_initial(projet, param, modules, physio, superficie, etat)
# Simulation
s, etats, deltas = hsami_simulation(projet, param, modules, physio, superficie, etat, nb_pas_total, s, etats, deltas)
return s, etats, deltas
[docs]
def set_default_module(modules, key, default_value):
"""
Set module defaults values.
Parameters
----------
modules : dict
Dictionary of modules.
key : str
Hydrological process.
default_value : str
HSAMI+ module name.
"""
if key not in modules:
modules[key] = default_value
[docs]
def modules_par_defaut(modules):
"""
Check projet modules definition.
Parameters
----------
modules : dict
Dictionary of modules.
"""
valeurs_default = {
"etp_bassin": "hsami",
"etp_reservoir": "hsami",
"een": "hsami",
"infiltration": "hsami",
"qbase": "hsami",
"sol": "hsami",
"radiation": "hsami",
"reservoir": 0,
"mhumide": 0,
"glace_reservoir": 0,
}
for key, value in valeurs_default.items():
set_default_module(modules, key, value)
[docs]
def hsami_etat_initial(projet, param, modules, physio, superficie, etat):
"""
Tour de chauffe (1 an).
Parameters
----------
projet : dict
Données du projet HSAMI+.
param : list
Paramètres pour la simulation.
modules : dict
Les modules pour la simulation.
physio : dict
Les données physiographiques.
superficie : list
La superficie du bassin versant et la superficie moyenne du réservoir.
etat : dict
État du bassin versant et du réservoir.
Returns
-------
dict
État du bassin versant et du réservoir.
"""
pas = 1
for i_pas in range(365):
# Construction du projet pour hsami_noyau
p = {}
if "hu_surface" in projet:
p["hu_surface"] = projet["hu_surface"]
if "hu_inter" in projet:
p["hu_inter"] = projet["hu_inter"]
p["date"] = projet["dates"][i_pas]
p["nb_pas_par_jour"] = projet["nb_pas_par_jour"]
p["superficie"] = superficie
p["memoire"] = projet["memoire"]
p["param"] = param
p["meteo"] = {
"bassin": projet["meteo"]["bassin"][i_pas],
"reservoir": projet["meteo"]["reservoir"][i_pas],
}
p["modules"] = modules
p["physio"] = copy(physio)
p["pas"] = pas
if "niveau" in physio.keys():
p["physio"]["niveau"] = physio["niveau"][i_pas]
# Simulation
_, etat, _ = hsami2_noyau(p, etat)
# On avance d'un pas de temps
if pas == projet["nb_pas_par_jour"]:
pas = 1
else:
pas = pas + 1
return etat
# ----------
# Simulation
# ----------
[docs]
def hsami_simulation(projet, param, modules, physio, superficie, etat, nb_pas_total, s, etats, deltas):
"""
Simulation avec HASMAI+.
Parameters
----------
projet : dict
Dictionnaire contenant des données d'entrée.
param : list
Paramètres pour la simulation.
modules : dict
Les modules pour la simulation.
physio : dict
Les données physiographiques.
superficie : list
La superficie du bassin versant et la superficie moyenne du réservoir.
etat : dict
État du bassin versant et du réservoir à un pas de temps.
nb_pas_total : float
Nombre de pas des temps total.
s : dict
Sorties de simulation.
etats : dict
États du bassin versant et du réservoir pout tous les pas de temps.
deltas : dict
Composants du bilan massique.
Returns
-------
s : dict
Sorties de simulation.
etats : dict
États du bassin versants et du réservoir.
deltas : dict
Composants du bilan massique.
Notes
-----
projet : dict, Un dictionnaire contenant les clés suivantes :
- 'superficie' : liste des floats, la zone du projet. S'il ne contient qu'un seul élément,
un deuxième élément de valeur 0 est ajouté.
- 'param' : liste des float, Paramètres pour la simulation.
- 'mémoire' : int, taille de la mémoire pour la simulation.
- 'physio' : dict, les données physiographiques peuvent être vides.
- 'modules' : dict, les modules pour la simulation peuvent être vides. Les valeurs par défaut
sont définies si elles ne sont pas fournies.
- 'meteo' : dict, données météorologiques pour la simulation.
- 'dates' : liste des str, dates de simulation.
- 'nb_pas_par_jour' : entier, nombre de pas de temps par jour.
s : dict, un dictionnaire contenant les sorties de simulation avec les clés :
- 'Qtotal' : liste de float
- 'Qbase' : liste de float
- 'Qinter' : liste de float
- 'Qsurf' : liste de float
- 'Qreservoir' : liste de float
- 'Qglace' : liste de float
- 'ETP' : liste de float
- 'ETRtotal' : liste de float
- 'ETRsublim' : liste de float
- 'ETRPsurN' : liste de float
- 'ETRintercept' : liste de float
- 'ETRtranspir' : liste de float
- 'ETRreservoir' : liste de float
- 'ETRmhumide' : liste de float
- 'Qmh' : liste de float
etats : dict
Un dictionnaire contenant les états de la simulation à chaque pas de temps.
deltas : dict
Un dictionnaire contenant les composants du bilan massique avec les clés :
- 'total' : liste de float
- 'glace' : liste de float
- 'interception' : liste de float
- 'ruissellement' : liste de float
- 'vertical' : liste de float
- 'mhumide' : liste de float
- 'horizontal' : liste de float
"""
pas = 1
for i_pas in range(nb_pas_total):
# Construction du projet pour hsami_noyau
p = {}
if "hu_surface" in projet:
p["hu_surface"] = projet["hu_surface"]
if "hu_inter" in projet:
p["hu_inter"] = projet["hu_inter"]
p["date"] = projet["dates"][i_pas]
p["nb_pas_par_jour"] = projet["nb_pas_par_jour"]
p["superficie"] = superficie
p["memoire"] = projet["memoire"]
p["param"] = param
p["meteo"] = {
"bassin": projet["meteo"]["bassin"][i_pas],
"reservoir": projet["meteo"]["reservoir"][i_pas],
}
p["modules"] = modules
p["physio"] = copy(physio)
if "niveau" in physio.keys():
p["physio"]["niveau"] = physio["niveau"][i_pas]
p["pas"] = pas
# Simulation
s_sim, etat, delta = hsami2_noyau(p, etat)
# Sauvegarde des sorties
f = list(s_sim.keys())
for i_f in range(len(f)):
s[f[i_f]].append(s_sim[f[i_f]])
# Sauvegarde des états
f = list(etat.keys())
for i_f in range(len(f)):
if isinstance(etat[f[i_f]], np.ndarray):
if f[i_f] == "eeg":
etats[f[i_f]].append(np.nansum(etat[f[i_f]]).tolist())
else:
etats[f[i_f]].append(etat[f[i_f]].tolist())
else:
etats[f[i_f]].append(etat[f[i_f]])
# Sauvegarde du bilan de masse
f = list(delta.keys())
for i_f in range(len(f)):
deltas[f[i_f]].append(delta[f[i_f]])
# On avance d'un pas de temps
if pas == projet["nb_pas_par_jour"]:
pas = 1
else:
pas = pas + 1
return s, etats, deltas