smash.bayesian_optimize_control_info#

smash.bayesian_optimize_control_info(model, mapping='uniform', optimizer=None, optimize_options=None, cost_options=None)[source]#

Information on the bayesian optimization control vector of Model.

Parameters:
modelModel

Primary data structure of the hydrological model smash.

mappingstr, default ‘uniform’

Type of mapping. Should be one of

  • 'uniform'

  • 'distributed'

  • 'multi-linear'

  • 'multi-polynomial'

Hint

See the Mapping section

optimizerstr or None, default None

Name of optimizer. Should be one of

  • 'sbs' ('uniform' mapping only)

  • 'lbfgsb' ('uniform', 'distributed', 'multi-linear' or 'multi-polynomial' mapping only)

Note

If not given, a default optimizer will be set depending on the optimization mapping:

  • mapping = 'uniform'; optimizer = 'sbs'

  • mapping = 'distributed', 'multi-linear', or 'multi-polynomial'; optimizer = 'lbfgsb'

Hint

See the Optimization Algorithm section

optimize_optionsdict[str, Any] or None, default None

Dictionary containing optimization options for fine-tuning the optimization process. See default_bayesian_optimize_options to retrieve the default optimize options based on the mapping and optimizer.

parametersstr, list[str, …] or None, default None

Name of parameters to optimize. Should be one or a sequence of any key of:

>>> optimize_options = {
    "parameters": "cp",
}
>>> optimize_options = {
    "parameters": ["cp", "ct", "kexc", "llr"],
}

Note

If not given, all parameters in Model.rr_parameters, Model.serr_mu_parameters and Model.serr_sigma_parameters will be optimized.

boundsdict[str, tuple[float, float]] or None, default None

Bounds on optimized parameters. A dictionary where the keys represent parameter names, and the values are pairs of (min, max) values (i.e., a list or tuple) with min lower than max. The keys must be included in parameters.

>>> optimize_options = {
    "bounds": {
        "cp": (1, 2000),
        "ct": (1, 1000),
        "kexc": (-10, 5)
        "llr": (1, 1000)
    },
}
control_tfmstr or None, default None

Transformation method applied to the control vector. Only used with 'sbs' or 'lbfgsb' optimizer. Should be one of:

  • 'keep'

  • 'normalize'

  • 'sbs' ('sbs' optimizer only)

Note

If not given, a default control vector transformation will be set depending on the optimizer:

  • optimizer = 'sbs'; control_tfm = 'sbs'

  • optimizer = 'lbfgsb'; control_tfm = 'normalize'

descriptordict[str, list[str, …]] or None, default None

Descriptors linked to optimized parameters. A dictionary where the keys represent parameter names, and the values are list of descriptor names. The keys must be included in parameters.

>>> optimize_options = {
    "descriptor": {
        "cp": ["slope", "dd"],
        "ct": ["slope"],
        "kexc": ["slope", "dd"],
        "llr": ["dd"],
    },
}

Note

If not given, all descriptors will be used for each parameter. This option is only be used when mapping is 'multi-linear' or 'multi-polynomial'. In case of 'ann', all descriptors will be used.

termination_critdict[str, Any] or None, default None

Termination criteria. The elements are:

  • 'maxiter': The maximum number of iterations. Only used when optimizer is 'sbs' or 'lbfgsb'.

  • 'factr': An additional termination criterion based on cost values. Only used when optimizer is 'lbfgsb'.

  • 'pgtol': An additional termination criterion based on the projected gradient of the cost function. Only used when optimizer is 'lbfgsb'.

  • 'epochs': The number of training epochs for the neural network. Only used when mapping is 'ann'.

  • 'early_stopping': A positive number to stop training when the loss function does not decrease below the current optimal value for early_stopping consecutive epochs. When set to zero, early stopping is disabled, and the training continues for the full number of epochs. Only used when mapping is 'ann'.

>>> optimize_options = {
    "termination_crit": {
        "maxiter": 10,
        "factr": 1e6,
    },
}
>>> optimize_options = {
    "termination_crit": {
        "epochs": 200,
    },
}

Note

If not given, default values are set to each elements.

cost_optionsdict[str, Any] or None, default None

Dictionary containing computation cost options for simulated and observed responses. The elements are:

end_warmupstr, pandas.Timestamp or None, default None

The end of the warm-up period, which must be between the start time and the end time defined in Model.setup.

>>> cost_options = {
    "end_warmup": "1997-12-21",
}
>>> cost_options = {
    "end_warmup": pd.Timestamp("19971221"),
}

Note

If not given, it is set to be equal to the Model.setup start time.

gaugestr or list[str, …], default ‘dws’

Type of gauge to be computed. There are two ways to specify it:

  • An alias among 'all' (all gauge codes) or 'dws' (most downstream gauge code(s))

  • A gauge code or any sequence of gauge codes. The gauge code(s) given must belong to the gauge codes defined in the Model.mesh

>>> cost_options = {
    "gauge": "dws",
}
>>> cost_options = {
    "gauge": "V3524010",
}
>>> cost_options = {
    "gauge": ["V3524010", "V3515010"],
}
control_priordict[str, list[str, list[float]]] or None, default None

Prior applied to the control vector. A dictionary containing the type of prior to link to control vector. The keys are any control parameter name (i.e. 'cp0', 'cp1-1', 'cp-slope-a', etc.), see bayesian_optimize_control_info to retrieve control parameters names. The values are list of length 2 containing distribution information (i.e. distribution name and parameters). Below, the set of available distributions and the associated number of parameters:

  • 'FlatPrior', [] (0)

  • 'Uniform', [lower_bound, higher_bound] (2)

  • 'Gaussian', [mean, standard_deviation] (2)

  • 'Exponential', [threshold, scale] (2)

  • 'LogNormal', [mean_log, standard_deviation_log] (2)

  • 'Triangle', [peak, lower_bound, higher_bound] (3)

>>> cost_options = {
    control_prior: {
        "cp0": ["Gaussian", [200, 100]],
        "kexc0": ["Gaussian", [0, 5]],
    }
}

Note

If not given, 'FlatPrior' is applied to each control vector parameter (i.e. equivalent to no prior).

Hint

See a more detailed explanation on the available distributions in Bayesian Estimation section.

Returns:
control_infodict[str, Any]

A dictionary containing optimize control information of Model. The elements are:

  • nint

    The size of the control vector.

  • nbknumpy.ndarray

    An array of shape (4,) containing the number of elements by kind (Model.rr_parameters, Model.rr_initial_states, Model.serr_mu_parameters, Model.serr_sigma_parameters) of the control vector (sum(nbk) = n).

  • xnumpy.ndarray

    An array of shape (n,) containing the initial values of the control vector (it can be transformed).

  • lnumpy.ndarray

    An array of shape (n,) containing the lower bounds of the control vector (it can be transformed).

  • unumpy.ndarray

    An array of shape (n,) containing the upper bounds of the control vector (it can be transformed).

  • nbdnumpy.ndarray

    An array of shape (n,) containing the type of bounds of the control vector. The values are:

    • 0: unbounded

    • 1: only lower bound

    • 2: both lower and upper bounds

    • 3: only upper bound

  • namenumpy.ndarray

    An array of shape (n,) containing the names of the control vector. The naming convention is:

    • <key>0: Spatially uniform parameter or multi-linear/polynomial intercept where <key> is the name of any rainfall-runoff parameters or initial_states ('cp0', 'llr0', 'ht0', etc).

    • <key><row>-<col>: Spatially distributed parameter where <key> is the name of any rainfall-runoff parameters or initial_states and <row>, <col>, the corresponding position in the spatial domain ('cp1-1', 'llr20-2', 'ht3-12', etc). It’s one based indexing.

    • <key>-<desc>-<kind>: Multi-linear/polynomial descriptor linked parameter where <key> is the name of any rainfall-runoff parameters or initial_states, <desc> the corresponding descriptor and <kind>, the kind of parameter (coefficient or exposant) ('cp-slope-a', 'llr-slope-b', 'ht-dd-a').

    • <key>-<code>: Structural error parameter where <key> is the name of any structural error mu or sigma parameters and <code>, the corresponding gauge ('sg0-V3524010', 'sg1-V3524010', etc)

  • x_bkgnumpy.ndarray

    An array of shape (n,) containing the background values of the control vector.

  • l_bkgnumpy.ndarray

    An array of shape (n,) containing the background lower bounds of the control vector.

  • u_bkgnumpy.ndarray

    An array of shape (n,) containing the background upper bounds of the control vector.

Examples

>>> from smash.factory import load_dataset
>>> setup, mesh = load_dataset("cance")
>>> model = smash.Model(setup, mesh)

Default optimize control vector information

>>> control_info = smash.bayesian_optimize_control_info(model)
>>> control_info
{
    'l': array([-1.3815511e+01, -1.3815511e+01, -4.6052704e+00, -1.3815511e+01, 1.0000000e-06, 1.0000000e-06],
         dtype=float32),
    'l_bkg': array([ 1.e-06,  1.e-06, -5.e+01,  1.e-06,  1.e-06,  1.e-06], dtype=float32),
    'n': 6,
    'name': array(['cp0', 'ct0', 'kexc0', 'llr0', 'sg0-V3524010', 'sg1-V3524010'], dtype='<U12'),
    'nbd': array([2, 2, 2, 2, 2, 2], dtype=int32),
    'nbk': array([4, 0, 0, 2], dtype=int32),
    'u': array([   6.9077554,    6.9077554,    4.6052704,    6.9077554, 1000.       ,   10.       ],
         dtype=float32),
    'u_bkg': array([1000., 1000.,   50., 1000., 1000.,   10.], dtype=float32),
    'x': array([5.2983174, 6.214608 , 0.       , 1.609438 , 1.       , 0.2      ], dtype=float32),
    'x_bkg': array([2.e+02, 5.e+02, 0.e+00, 5.e+00, 1.e+00, 2.e-01], dtype=float32),
}

This gives a direct indication of what the optimizer takes as input, depending on the optimization configuration set up. 4 rainfall-runoff parameters are uniformly optimized ('cp0', 'ct0', 'kexc0' and 'llr0') and 2 structural error sigma parameters at gauge 'V3524010' ('sg0-V3524010', 'sg1-V3524010') Each parameter has a lower and upper bound (2 in nbd) and a transformation was applied to the control (x relative to x_bkg)

With a customize optimize configuration. Here, choosing a multi-linear mapping and optimizing only 2 rainfall-runoff parameters cp, kexc with different descriptors and 2 structural error sigma parameters sg0 and sg1.

>>> control_info = smash.bayesian_optimize_control_info(
        model,
        mapping="multi-linear",
        optimize_options={
            "parameters": ["cp", "kexc", "sg0", "sg1"],
            "descriptor": {"kexc": ["dd"]},
        },
    )
>>> control_info
{
    'l': array([-99., -99., -99., -99., -99.,   0.,   0.], dtype=float32),
    'l_bkg': array([-9.9e+01, -9.9e+01, -9.9e+01, -9.9e+01, -9.9e+01,  1.0e-06, 1.0e-06], dtype=float32),
    'n': 7,
    'name': array(['cp0', 'cp-slope-a', 'cp-dd-a', 'kexc0', 'kexc-dd-a', 'sg0-V3524010', 'sg1-V3524010'],
            dtype='<U12'),
    'nbd': array([0, 0, 0, 0, 0, 2, 2], dtype=int32),
    'nbk': array([5, 0, 0, 2], dtype=int32),
    'u': array([-99., -99., -99., -99., -99.,   1.,   1.], dtype=float32),
    'u_bkg': array([ -99.,  -99.,  -99.,  -99.,  -99., 1000.,   10.], dtype=float32),
    'x': array([-1.3862944e+00,  0.0000000e+00,  0.0000000e+00,  0.0000000e+00, 0.0000000e+00,  9.9999900e-04,
         1.9999903e-02], dtype=float32),
    'x_bkg': array([-1.3862944,  0.       ,  0.       ,  0.       ,  0.       , 1.       ,  0.2      ],
             dtype=float32),
}

7 parameters are optimized which are the intercepts ('cp0' and 'kexc0') and the coefficients ('cp-slope-a', 'cp-dd-a' and 'kexc-dd-a') of the regression between the descriptors (slope and dd) and the rainfall-runoff parameters (cp and kexc) and the 2 structural error sigma parameters ('sg0' and 'sg1') associated to the gauge 'V3524010'.

Retrieving information from the control vector is particularly useful for defining priors on the parameters. During a bayesian optimization, it is possible to define these priors in the cost_options argument within the 'control_prior' key. The problem is that we don’t know the control vector in advance until we’ve filled in all the optimization options. This is why we can define all the optimization options in the bayesian_optimize_control_info method, retrieve the names of the parameters that make up the control vector and then call the optimization function, assigning the priors we want to.

Assign Gaussian priors to the two rainfall-runoff parameters 'cp0' and 'kexc0' and perform a spatially uniform optimization

>>> model.bayesian_optimize(
        cost_options={
            "control_prior": {"cp0": ["Gaussian", [200, 100]], "kexc0": ["Gaussian", [0, 5]]}
        },
    )
</> Bayesian Optimize
    At iterate      0    nfg =     1    J =     80.526947    ddx = 0.64
    At iterate      1    nfg =    68    J =      3.029253    ddx = 0.64
    At iterate      2    nfg =   135    J =      2.764919    ddx = 0.32
    At iterate      3    nfg =   203    J =      2.760564    ddx = 0.04
    At iterate      4    nfg =   271    J =      2.755039    ddx = 0.02
    At iterate      5    nfg =   344    J =      2.754198    ddx = 0.01
    CONVERGENCE: DDX < 0.01