Author: Solvi Rognvaldsson, Rafael Daniel Vias, Birgir Hrafnkelsson and Axel Orn Jansson

# Introduction

#### Solvi Rognvaldsson, Rafael Daniel Vias, Birgir Hrafnkelsson and Axel Orn Jansson

A discharge rating curve is a model that describes the relationship between water elevation and discharge in a river. The rating curve is estimated from paired observations of water elevation and discharge and it is used to predict discharge for a given water elevation. This is the main practical usage of rating curves, as water elevation is substantially easier to directly observe than discharge. This R package implements four different discharge rating curve models using a Bayesian hierarchical modeling framework:

- `plm0()` - Power-law model with constant log-error variance.

- `plm()` - Power-law model with stage-dependent log-error variance.

- `gplm0()` - Generalized power-law model with constant log-error variance.

- `gplm()` - Generalized power-law model with stage-dependent log-error variance.

For further details about the different models, see Hrafnkelsson et al. (2022). For an brief overview of the underlying theory, see our Background vignette.

The models differ in their complexity, `gplm` being the most flexible and complex model. We will focus on the use of `gplm` throughout this introduction vignette and explore the different ways to fit the `gplm` and visualize its output. However, the API of the functions for the other three models are almost identical so this vignette also helps users to run those models.

    > library(bdrc)
    > set.seed(1) #set seed for reproducibility

We will use a dataset from a stream gauging station in Sweden, called Krokfors, that comes with the package:

    > data(krokfors)
    > head(krokfors)
    #>          W          Q
    #> 1 9.478000 10.8211700
    #> 2 8.698000  1.5010000
    #> 3 9.009000  3.3190000
    #> 4 8.097000  0.1595700
    #> 5 9.104000  4.5462500
    #> 6 8.133774  0.2121178

## Fitting a discharge rating curve

Fitting a discharge rating curve with `bdrc` is straightforward. Only two input arguments are mandatory: `formula` and `data`. The `formula` should of the form `y ~ x`, where `y` is the discharge in cubic meters per second (m³/s), and `x` is the water elevation (stage) in meters (m). It is crucial that the data is in the correct units! The `data` argument must be a `data.frame` including `x` and `y` as column names. In our case, the Krokfors data has the discharge and water elevation measurements stored in columns named `Q` and `W`, respectively. We are ready to fit a discharge rating curve using the `gplm` function:

    > gplm.fit <- gplm(Q ~ W, data = krokfors, parallel = TRUE, num_cores = 2)
    #> Progress:
    #> Initializing Metropolis MCMC algorithm...
    #> Multiprocess sampling (4 chains in 2 jobs) ...
    #>
    #> MCMC sampling completed!
    #>
    #> Diagnostics:
    #> Acceptance rate: 25.88%.
    #> ✔ All chains have mixed well (Rhat < 1.1).
    #> ✔ Effective sample sizes sufficient (eff_n_samples > 400).

The function prints out a summary of the fitting process and key MCMC diagnostics. These include the acceptance rate, chain mixing (assessed via the Gelman-Rubin statistic, \(\hat{R}\)), and effective sample sizes. The checkmarks indicate that the algorithm has met important criteria for reliability. However, sometimes you may encounter warnings. For example:

    #> ⚠ Warning: Some chains are not mixing well. Parameters with Rhat > 1.1:
    #>   - sigma_eta: Rhat = 1.281

This warning suggests that certain parameters (in this case, sigma_eta) haven’t mixed well across chains, which could affect the reliability of the results. In such cases, the function provides advice:

    #> ℹ Try re-running the model after inspecting the trace plots, convergence diagnostics plots, and reviewing the data for potential issues.

This output helps you assess whether the discharge rating curve has been fitted successfully and reliably using the specified data. The function can be made to run silently by setting `verbose=FALSE`.

Note that `parallel=TRUE` is the default setting, utilizing all available cores on the machine. You can adjust the number of cores with the `num_cores` argument if needed.

The `gplm` function returns an object of class gplm which we can summarize and visualize using familiar functions such as

    > summary(gplm.fit)
    #>
    #> Formula:
    #>  Q ~ W
    #> Latent parameters:
    #>   lower-2.5% median-50% upper-97.5%
    #> a 1.47       1.94       2.23
    #> b 1.82       1.84       1.85
    #>
    #> Hyperparameters:
    #>            lower-2.5% median-50% upper-97.5%
    #> c           7.70549    7.8090     7.86
    #> sigma_beta  0.42979    0.7151     1.28
    #> phi_beta    0.56969    1.1876     2.86
    #> sigma_eta   0.00351    0.0914     0.49
    #> eta_1      -4.90126   -4.2535    -3.57
    #> eta_2      -4.77897   -4.2237    -3.54
    #> eta_3      -4.80833   -4.2543    -3.61
    #> eta_4      -4.98458   -4.3049    -3.62
    #> eta_5      -5.18542   -4.3142    -3.60
    #> eta_6      -5.26113   -4.3087    -3.54
    #>
    #> WAIC: -27.96081

and

    > plot(gplm.fit)

In the next section, we will dive deeper into visualizing the gplm object.

## Visualizing posterior distributions of different parameters

The `bdrc` package provides several tools to visualize the results from model objects which can give insight into the physical properties of the river at hand. For instance, the hyperparameter \(c\) corresponds to the water elevation of zero discharge. To visualize the posterior of \(c\), we can write

    > plot(gplm.fit, type = 'histogram', param = 'c')

Technically, instead of inferring \(c\) directly, \(h_{min}-c\) is inferred, where \(h_{min}\) is the lowest water elevation value in the data. Since the parameter \(h_{min}-c\) is strictly positive, a transformation \(\zeta=log(h_{min}-c)\) is used for the Bayesian inference so that it has support on the real line. To plot the transformed posterior we write

    > plot(gplm.fit, type = 'histogram', param = 'c', transformed = TRUE)

The `param` argument can also be a vector containing multiple parameter names. For example, to visualize the posterior distributions of the parameters \(a\) and \(c\), we can write

    > plot(gplm.fit, type = 'histogram', param = c('a', 'c'))

There is a shorthand to visualize the hyperparameters all at once

    > plot(gplm.fit, type = 'histogram', param = 'hyperparameters')

Similarly, writing `"latent_parameters"` plots the latent parameters in one plot. To plot the hyperparameters transformed on the same scale as in the Bayesian inference, we write

    > plot(gplm.fit, type = 'histogram', param = 'hyperparameters', transformed = TRUE)

Finally, we can visualize the components of the model that are allowed (depending on the model) to vary with water elevation, that is, the power-law exponent, \(f(h)\), and the standard deviation of the error terms at the response level, \(\sigma_{\varepsilon}(h)\). Both `gplm0` and `gplm` generalize the power-law exponent by modeling it as a sum of a constant term, \(b\), and Gaussian process, \(\beta(h)\), namely \(f(h)=b+\beta(h)\), where \(\beta(h)\) is assumed to be twice differentiable with mean zero. On the other hand, `plm` and `plm0` both model the power-law exponent as a constant by setting \(\beta(h)=0\), which gives \(f(h)=b\). We can plot the inferred power-law exponent with

    > plot(gplm.fit, type = 'f')

Both `plm` and `gplm` model the standard deviation of the error terms at the response level, \(\sigma_{\varepsilon}(h)\), as a function of water elevation, using B-splines basis functions, while `plm0` and `gplm0` model the standard deviation as a constant. We can plot the inferred standard deviation by writing

    > plot(gplm.fit, type = 'sigma_eps')

To get a visual summary of your model, the `"panel"` option in the plot type is useful:

    > plot(gplm.fit, type = 'panel', transformed = TRUE)

## Assessing model fit and convergence

The package has several functions for convergence diagnostics of a `bdrc` model, most notably the residual plot, trace plots, autocorrelation plots, and Gelman-Rubin diagnostic plots. The log-residuals can be plotted with

    > plot(gplm.fit, type = 'residuals')

The log-residuals are calculated by subtracting the posterior estimate (median) of the log-discharge, \(log(\hat{Q})\), from the observed log-discharge, \(log(Q)\). Additionally, the plot includes the 95% predictive intervals of \(\log(Q)\) (- -) and 95% credible intervals for the expected value of \(\log(Q)\) (—), the latter reflecting the rating curve uncertainty.

    > plot(gplm.fit, type = 'trace', param = 'c', transformed = TRUE)

To plot a trace plot for all the transformed hyperparameters, we write

    > plot(gplm.fit, type = 'trace', param = 'hyperparameters', transformed = TRUE)

To assess the mixing and convergence of the MCMC chains for each parameter, you can visualize the Gelman-Rubin statistic, \(\hat{R}\), as presented by Gelman and Rubin (1992) with:

    > plot(gplm.fit, type = 'r_hat')

And finally, autocorrelation of parameters can be assessed with

    > plot(gplm.fit, type = 'autocorrelation')

## Customizing the models

There are ways to further customize the `gplm` function. In some instances, the parameter of zero discharge, \(c\), is known, and you might want to fix the model parameter to the known value. In addition, you might want to extrapolate the rating curve to higher water elevation values by adjusting the maximum water elevation. Assume 7.65 m is the known value of \(c\) and you want to calculate the rating curve for water elevation values up to 10 m, then your function call would look like this

    > gplm.fit.known_c <- gplm(Q ~ W, krokfors, c_param = 7.65, h_max = 10, parallel = FALSE)

## Prediction for an equally spaced grid of water elevations

To get rating curve predictions for an equally spaced grid of water elevation values, you can use the predict function. Note that only values in the range from \(c\) and h_max are accepted, as that is the range in which the Bayesian inference was performed

    > h_grid <- seq(8, 8.2, by = 0.01)
    > rating_curve_h_grid <- predict(gplm.fit, newdata = h_grid)
    > print(rating_curve_h_grid)
    #>       h      lower     median     upper
    #> 1  8.00 0.06142757 0.08245384 0.1107656
    #> 2  8.01 0.06729304 0.09011654 0.1208716
    #> 3  8.02 0.07393166 0.09850101 0.1318898
    #> 4  8.03 0.08057029 0.10688548 0.1429080
    #> 5  8.04 0.08726188 0.11544316 0.1541234
    #> 6  8.05 0.09424804 0.12496416 0.1664356
    #> 7  8.06 0.10123421 0.13448515 0.1787478
    #> 8  8.07 0.10843035 0.14412947 0.1910722
    #> 9  8.08 0.11634481 0.15419564 0.2034387
    #> 10 8.09 0.12425927 0.16426182 0.2158051
    #> 11 8.10 0.13242403 0.17466315 0.2288102
    #> 12 8.11 0.14117283 0.18584652 0.2433055
    #> 13 8.12 0.14992163 0.19702989 0.2578007
    #> 14 8.13 0.15867043 0.20821326 0.2722960
    #> 15 8.14 0.16797515 0.21990869 0.2873889
    #> 16 8.15 0.17761685 0.23191452 0.3028441
    #> 17 8.16 0.18725856 0.24392034 0.3182993
    #> 18 8.17 0.19689344 0.25679685 0.3348738
    #> 19 8.18 0.20652808 0.26970311 0.3514867
    #> 20 8.19 0.21630683 0.28286887 0.3683904
    #> 21 8.20 0.22640436 0.29660873 0.3859374

## References

Gelman, A., & Rubin, D. B. (1992). Inference from iterative simulation using multiple sequences, Statistical Science, 7(4), 457–472. doi: https://doi.org/10.1214/ss/1177011136

Hrafnkelsson, B., Sigurdarson, H., Rögnvaldsson, S., Jansson, A. Ö., Vias, R. D., and Gardarsson, S. M. (2022). Generalization of the power-law rating curve using hydrodynamic theory and Bayesian hierarchical modeling, Environmetrics, 33(2):e2711. doi: https://doi.org/10.1002/env.2711