Fully-distributed optimization using a uniform first guess#

To get started, open a Python interface:

python3

Imports#

In [1]: import smash

In [2]: import matplotlib.pyplot as plt

In [3]: import numpy as np

Model object creation#

To perform the calibrations, you need to create a smash.Model object. For this case, we will use the Lez dataset.

Load the setup and mesh dictionaries using the smash.load_dataset() method and create the smash.Model object.

In [4]: setup, mesh = smash.load_dataset("Lez")

In [5]: model = smash.Model(setup, mesh)

Spatially uniform optimization#

To find the uniform first guess, we can perform a spatially-uniform calibration using global optimization algorithms. Here’s an example how we can do it with the \(\mathrm{SBS}\) algorithm:

In [6]: model_su = model.optimize(mapping="uniform", algorithm="sbs", options={"maxiter": 2});

Once the optimization is complete. We can visualize the simulated discharge:

In [7]: qo = model_su.input_data.qobs[0,:].copy()

In [8]: qo = np.where(qo<0, np.nan, qo)  # to deal with missing data

In [9]: plt.plot(qo, label="Observed discharge");

In [10]: plt.plot(model_su.output.qsim[0,:], label="Simulated discharge");

In [11]: plt.grid(alpha=.7, ls="--");

In [12]: plt.xlabel("Time step");

In [13]: plt.ylabel("Discharge $(m^3/s)$");

In [14]: plt.title(model_su.mesh.code[0]);

In [15]: plt.legend();
../../../_images/user_guide.in_depth.optimize.fully_distributed.qsim_su.png

The cost function value \(J\):

In [16]: model_su.output.cost
Out[16]: 0.17609025537967682

And the spatially uniform first guess:

In [17]: ind = tuple(model_su.mesh.gauge_pos[0,:])

In [18]: ind
Out[18]: (26, 12)

In [19]: (
   ....:  model_su.parameters.cp[ind],
   ....:  model_su.parameters.cft[ind],
   ....:  model_su.parameters.exc[ind],
   ....:  model_su.parameters.lr[ind],
   ....: )
   ....: 
Out[19]: (55.60748, 139.0187, 1.6593012, 431.59668)

Hint

You may want to refer to the Bayesian estimation section for information on how to improve the first guess using a Bayesian estimation approach.

Spatially distributed optimization#

Next, using the first guess provided by a global calibration, which had stored the optimized parameters in the previous step, we perform a spatially distributed calibration using the \(\mathrm{L}\text{-}\mathrm{BFGS}\text{-}\mathrm{B}\) algorithm:

In [20]: model_sd = model_su.optimize(
   ....:         mapping="distributed",
   ....:         algorithm="l-bfgs-b",
   ....:         options={"maxiter": 30}
   ....:     )
   ....: 

We can once again visualize, the simulated discharges (su: spatially uniform, sd: spatially distributed):

In [21]: qo = model_sd.input_data.qobs[0,:].copy()

In [22]: qo = np.where(qo<0, np.nan, qo)  # to deal with missing data

In [23]: plt.plot(qo, label="Observed discharge");

In [24]: plt.plot(model_su.output.qsim[0,:], label="Simulated discharge - su");

In [25]: plt.plot(model_sd.output.qsim[0,:], label="Simulated discharge - sd");

In [26]: plt.grid(alpha=.7, ls="--");

In [27]: plt.xlabel("Time step");

In [28]: plt.ylabel("Discharge $(m^3/s)$");

In [29]: plt.title(model_sd.mesh.code[0]);

In [30]: plt.legend();
../../../_images/user_guide.in_depth.optimize.fully_distributed.qsim_sd.png

The cost value:

In [31]: model_sd.output.cost
Out[31]: 0.13125108182430267

And finally, the distributed model parameters in this case:

In [32]: ma = (model_sd.mesh.active_cell == 0)

In [33]: ma_cp = np.where(ma, np.nan, model_sd.parameters.cp)

In [34]: ma_cft = np.where(ma, np.nan, model_sd.parameters.cft)

In [35]: ma_lr = np.where(ma, np.nan, model_sd.parameters.lr)

In [36]: ma_exc = np.where(ma, np.nan, model_sd.parameters.exc)

In [37]: f, ax = plt.subplots(2, 2)

In [38]: map_cp = ax[0,0].imshow(ma_cp);

In [39]: f.colorbar(map_cp, ax=ax[0,0], label="cp (mm)");

In [40]: map_cft = ax[0,1].imshow(ma_cft);

In [41]: f.colorbar(map_cft, ax=ax[0,1], label="cft (mm)");

In [42]: map_lr = ax[1,0].imshow(ma_lr);

In [43]: f.colorbar(map_lr, ax=ax[1,0], label="lr (min)");

In [44]: map_exc = ax[1,1].imshow(ma_exc);

In [45]: f.colorbar(map_exc, ax=ax[1,1], label="exc (mm/d)");
../../../_images/user_guide.in_depth.optimize.fully_distributed.theta.png