Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Bedload Exercise

Run this notebook in your web browser: Open in marimo

The link opens bedload-exercise.py as an interactive marimo notebook that runs entirely in your web browser, without installing anything. Like the Jupyter notebook, the marimo notebook is the original French version of this page.

  1. Wait a moment until Python has loaded in the browser (this takes longer only at the first start).

  2. Click the yellow run button (▶︎, bottom right) to run all cells.

  3. Edit and re-run any code cell to experiment: marimo automatically updates all cells that depend on it.

  4. Your edits remain in the browser tab only. To keep them, save the notebook through the menu (☰, top right) > Export… > Python.

Structure of the Exercise

partwho does the work
Isetup: load the script and the datagiven: run the cells
IIdata: grain sizes, roughness coefficients kstk_{st}, threshold τ∗,cr\tau_{*,cr}you: complete two lists
IIIequations: roughness ratio k′k' and critical roughness kst,crk_{st,cr}you: complete two lines of code
IVresults: MPM bedload calculation, Shields diagram, active cross-sectionsgiven: run and interpret

Programming experience is not required. Run a cell with Shift + Enter. The spots to complete are marked with the comment # >>> À COMPLÉTER (to complete): replace each text ">>> COMPLETER" (quotes included) with your value or equation. In the code, decimal numbers are written with a point (0.047, not 0,047).


Part I: Setup

The following cell loads the script fun/charriage.py under the short name ch and displays the data from data/hecras-arbogne.csv. On Google Colab, it first downloads these two files. This cell carries no course content.

import os, sys, urllib.request
if "google.colab" in sys.modules:  # uniquement sur Google Colab : télécharge le script et les données
    for f in ("fun/charriage.py", "data/hecras-arbogne.csv"):
        os.makedirs(os.path.dirname(f), exist_ok=True)
        urllib.request.urlretrieve(
            f"https://raw.githubusercontent.com/hydro-informatics/jupyter-python-course/main/{f}", f)

from fun import charriage as ch   # fun/charriage.py, lit data/hecras-arbogne.csv
ch.lire_hecras()

For each cross-section (from upstream to downstream), the table shows the station, the discharge, the bed and water surface elevations, the energy slope JeJ_e, the hydraulic radius RhR_h and the water depth hh. The slope JeJ_e drops from 0.0042 upstream to 0.0007 downstream: this is where the gravel risks being deposited.


Part II: Data

Task 1: Grain Size and Roughness

Two grain size distributions describe the Arbogne (line-count analysis after Fehr, March 2014):

  • “Sable (fin)” (sand, fine) to estimate the supply from upstream;

  • “Gravier (complet)” (gravel, complete) to characterize the bed in place.

Four characteristic diameters are sufficient for the exercise:

grain size distributiondmd_m [mm]d84d_{84} [mm]d90d_{90} [mm]
“Sable (fin)”0.23not needednot needed
“Gravier (complet)”8.8813.5623.06
  • dmd_m of the sand represents the fine supply passing through;

  • dmd_m of the gravel represents the gravel in transit;

  • d84d_{84} of the gravel represents the bed in place (armor layer);

  • d90d_{90} of the gravel sets the grain roughness krk_r (Meyer-Peter & Müller 1948).

Enter these values, in millimeters, in the list melanges. The order matters: first the sand, then the gravel (the last mixture in the list represents the bed).

Then enter in the list k_st the two Strickler coefficients kstk_{st} [m1/3^{1/3}/s] to be compared, from the smoothest to the roughest:

  1. without vegetation: the flow stays in the gravel bed (reference state);

  2. with vegetation: the flood overtops into the densely vegetated floodplain.

The list may contain further values: every kstk_{st} added becomes an additional roughness case.

# >>> À COMPLÉTER : diamètres caractéristiques en mm
#             nom                   d_m               d_84              d_90
melanges = [["Sable (fin)",         ">>> COMPLETER"],
            ["Gravier (complet)",   ">>> COMPLETER",  ">>> COMPLETER",  ">>> COMPLETER"]]

# >>> À COMPLÉTER : coefficients de Strickler k_st [m^(1/3)/s], sans végétation en premier
k_st = [">>> COMPLETER", ">>> COMPLETER"]

Threshold of Motion τ∗,cr\tau_{*,cr}

MPM was calibrated with a critical Shields parameter of τ∗,cr\tau_{*,cr} = 0.047, the value used throughout the exercise. The list tau_cr nevertheless accepts several values, for example to test how sensitive the result is to the threshold (see the homework). To do so, delete the # in front of the second line: every figure then shows all values of the list.

tau_cr = [0.047]
# tau_cr = [0.030, 0.040, 0.047, 0.056, 0.070]   # variante, pas utilisée dans l'exercice

Part III: Equations

Task 2: Roughness Ratio k′k'

MPM does not compare the entire dimensionless bed shear stress τ∗\tau_* with the threshold, but only the share that acts on the grains. Part of the energy is dissipated by bedforms, vegetation and banks. The roughness ratio k′k' corrects τ∗\tau_* accordingly:

Φ=8 (k′ τ∗−τ∗,cr)3/2withτ∗=Rh Je(s−1) d\Phi = 8\,\left(k'\,\tau_* - \tau_{*,cr}\right)^{3/2} \qquad \text{with} \qquad \tau_* = \frac{R_h\,J_e}{(s-1)\,d}
  k′=(kstkr)3/2≤1  wherekr=26d901/6\boxed{\;k' = \left(\frac{k_{st}}{k_r}\right)^{3/2} \le 1\;} \qquad \text{where} \qquad k_r = \frac{26}{d_{90}^{1/6}}
  • kstk_{st}: total Strickler coefficient of the reach (the list k_st from Task 1);

  • krk_r: grain Strickler coefficient of a plane bed, calculated by charriage.py with d90d_{90} of the gravel in meters.

Complete the marked line. In Python, a power is written **: for example, a3/2a^{3/2} is written a ** (3 / 2).

def rapport_rugosite(k_st, k_r):
    # >>> À COMPLÉTER : k' = (k_st / k_r)^(3/2)
    return ">>> COMPLETER"

Task 3: Critical Roughness kst,crk_{st,cr}

The more vegetation slows down the flow, the lower kstk_{st}, and with it the effective shear stress k′ τ∗k'\,\tau_*. A cross-section stops transporting when k′ τ∗=τ∗,crk'\,\tau_* = \tau_{*,cr}. Substituting k′k' with its definition and solving for kstk_{st} yields the critical roughness of each cross-section:

  kst,cr=kr(τ∗,crτ∗)2/3  \boxed{\;k_{st,cr} = k_r \left(\frac{\tau_{*,cr}}{\tau_*}\right)^{2/3}\;}

A cross-section transports as long as kst>kst,crk_{st} > k_{st,cr}. This equation makes it possible to plot the number of active cross-sections as roughness increases (last figure). Complete the marked line.

def k_st_critique(tau, k_r, tau_cr):
    # >>> À COMPLÉTER : k_st,cr = k_r * (tau_cr / tau)^(2/3)
    return ">>> COMPLETER"

Check

Run this cell after each task. [OK] means that the value matches the lecture, [XX] that it is wrong, and [ ] that it has not been completed yet. Correct the value, then re-run the cell of the task and this one.

ch.verifier(melanges, k_st, rapport_rugosite, k_st_critique)

Part IV: Results

MPM Calculation for the 16 Cross-Sections

charriage.py combines your data and applies MPM to every cross-section: each roughness case of the list k_st is calculated for both grain classes.

grainwhat it representsroughness cases
gravel, dmd_mthe gravel in transitwithout and with vegetation
sand, dmd_mthe fine supply from upstreamwithout and with vegetation
gravel, d84d_{84}the armored bed in placewithout vegetation only

For each combination, the table summarizes the roughness ratio k′k', the number of cross-sections that still transport (Φ>0\Phi > 0), as well as the largest Φ\Phi and the largest bedload transport rate qbq_b [kg/(s⋅\cdotm)] of the reach.

resultats = ch.calculer(melanges, k_st, tau_cr, rapport_rugosite)
ch.resume(resultats)

Shields Diagram

The diagram compares the two roughness cases, without vegetation (flow in the channel) and with vegetation (flood overtopping into the floodplain), for both grain classes, gravel and sand. Every point is a cross-section. The vertical axis is the effective shear stress on the grains k′ τ∗k'\,\tau_*, the one that MPM compares with τ∗,cr\tau_{*,cr}. Below the critical Shields curve, there is no bedload transport.

  • color: roughness case (blue without vegetation, red with vegetation);

  • symbol: grain class (circle: gravel; triangle: sand);

  • size: Φ\Phi, one decade per class (the largest Φ\Phi gives the largest marker).

ch.diagramme_shields(resultats)

Active Cross-Sections as Roughness Increases

The following figure lowers kstk_{st} step by step (from left to right, vegetation increases) and counts, for the gravel, the cross-sections where kst>kst,crk_{st} > k_{st,cr}. The vertical lines are your values from the list k_st. The total extinction is the kstk_{st} below which no cross-section transports anymore.

ch.profils_actifs(melanges, k_st, tau_cr, k_st_critique)