# Modélisation
## Proposition de structure
### Simulation
#### Modèle hydrologique
Un modèle (hydrologique) a des paramètres:
```python=
model = model_factory(x)
```
Typiquement, `model_factory` peut être une classe `GR4J`, et les paramètres `X1`, `X2`, `X3`, `X4`:
```python=
gr4j = GR4J([x1, x2, x3, x4])
```
Un modèle produit des sorties en fonction d'entrées:
```python=
outputs = model.run(inputs)
```
En hydrologie, les entrées sont typiquement des séries temporelles de précipitation `P` et d'évapotransporation `E`, et la sortie une série temporelle de débit `Qsim`.
```python=
q_sim = gr4j.run([p, e])
```
### Évaluation
Évaluer un modèle consiste à comparer les simulations du modèle à des références (observations), et à calculer un résultat agrégé traduisant la performance du modèle.
```python=
performance = criteria_function(outputs, observations)
```
Typiquement, on compare la série temporelle de débit simulée `q_sim` à une série mesurée `q_obs`.
Pour cela on utilise une fonction de critère, par exemple `NSE`.
```python=
performance = nse(q_sim, q_obs)
```
### Calibration
La calibration consiste à trouver les paramètres du modèle qui simulent le mieux les observations. Typiquement, on itère sur des valeurs de paramètres pour minimiser un critère, en utilisant un algorithme. Ces algorithmes ont souvent besoin de valeurs de paramètres initiales.
```python=
x = calibration_algorithm( # e.g. Calibration_Michel, Downhill_Simplex...
function_to_optimize,
initial_parameters
)
```
L'algorithme de calibration executera la fonction à optimiser avec une suite de valeurs de paramètres:
```python=
result = function_to_optimize(x)
```
Et essaiera de trouver la plus petite valeur de `result`. La valeur de `x` correspondante donne les paramètres calibrés.
```python=
function_to_optimize = calibration_function_factory(
model_factory, # GR4J
observations, # [p, e, q_obs]
criteria_function, # nse
)
```
## Le cas d'airGR
### Procédure de calibration
D'après la vignette [Get Started with airGR](https://cran.r-project.org/web/packages/airGR/vignettes/V01_get_started.html), la procédure de calibration est la suivante:
1. Le modèle (ici `RunModel_GR4J`) est d'emblée lié aux données d'entrées. Pourquoi? Et pourquoi a-t-il besoin des dates? Il devrait en être indépendant.
```r=
InputsModel <- CreateInputsModel(
FUN_MOD = RunModel_GR4J,
DatesR = BasinObs$DatesR,
Precip = BasinObs$P,
PotEvap = BasinObs$E
)
```
2. On sélectionne un sous-ensemble des données d'entrées. Pourquoi avoir lié le modèle à des données qui ne sont pas celles sur lesquelles il sera exécuté? Maintenant `Ind_Run` doit être passé à plusieurs endroits.
```r=
Ind_Run <- seq(
which(format(BasinObs$DatesR, format = "%Y-%m-%d") == "1990-01-01"),
which(format(BasinObs$DatesR, format = "%Y-%m-%d") == "1999-12-31")
)
```
3. On crée des options pour l'exécution du modèle, dans lesquelles on passe à nouveau le modèle `RunModel_GR4J`, déjà présent dans `InputsModel`. Pourquoi?
```r=
RunOptions <- CreateRunOptions(
FUN_MOD = RunModel_GR4J,
InputsModel = InputsModel,
IndPeriod_Run = Ind_Run,
IniStates = NULL,
IniResLevels = NULL,
IndPeriod_WarmUp = NULL
)
```
4. La sélection du sous-ensemble des observations `Ind_Run` est à nouveau passée à la fonction critère, alors qu'on aurait pu sélectionner ce sous-ensemble une fois pour toutes si le modèle n'avait pas été lié aux données à l'étape 1.
```r=
InputsCrit <- CreateInputsCrit(
FUN_CRIT = ErrorCrit_NSE,
InputsModel = InputsModel,
RunOptions = RunOptions,
VarObs = "Q",
Obs = BasinObs$Qmm[Ind_Run]
)
```
5. Dans les options de l'algorithme de calibration, on trouve l'algorithme de calibration lui-même (`Calibration_Michel`).
```r=
CalibOptions <- CreateCalibOptions(
FUN_MOD = RunModel_GR4J,
FUN_CALIB = Calibration_Michel
)
```
6. Puis on appelle l'algorithme de calibration avec lui-même en option?
```r=
OutputsCalib <- Calibration_Michel(
InputsModel = InputsModel,
RunOptions = RunOptions,
InputsCrit = InputsCrit,
CalibOptions = CalibOptions,
FUN_MOD = RunModel_GR4J
)
```
### Critique
Selon moi, les incohérences de cette procédure illustrent le manque de structure des objects manipulés, conduisant à du code entremêlé difficile à maintenir.
Les modèles hydrologiques codés en Fortran sont de simples fonctions, appelées avec toutes les entrées en paramètre "à plat":
```fortran=
SUBROUTINE frun_gr4j(
LInputs,
InputsPrecip,
InputsPE,
NParam,
Param,
&NStates,
StateStart,
NOutputs,
IndOutputs,
&Outputs,
StateEnd
)
```
Pourtant la programmation orientée objet est supportée depuis Fortran 90, et améliorée en Fortran 2003. Les modèles hydrologiques pourraient mettre à profiter l'utilisation de classes (`module` en Fortran), qui doivent être instanciées avec les paramètres du modèle. L'instance du modèle possède des variables d'état (hauteur des réservoirs), et une méthode pour calculer la simulation du débit en fonction de séries temporelles de pluie et d'ETP. Mais ces séries temporelles ne doivent pas faire partie de l'état du modèle.