Sediment Component Tutorial¶
This tutorial introduces the Sediment component in rompy-xbeach, which controls sediment transport, morphological evolution, bed composition, and related processes in XBeach.
What You'll Learn¶
- How to configure the Sediment component
- Sediment transport formulations and calibration
- Morphological acceleration (morfac)
- Bed composition and grain sizes
- Avalanching and slope effects
- Quasi-3D sediment transport
- Validation and constraints
Prerequisites¶
- Basic familiarity with XBeach concepts
- Completed the Physics Tutorial
- rompy-xbeach installed (
pip install rompy-xbeach)
1. Introduction¶
The Sediment component groups all sediment-related parameters:
| Sub-component | Purpose |
|---|---|
sedtrans |
Transport formulations, wave effects, bed slope effects |
morphology |
Morfac, time windows, avalanching slopes |
bed_composition |
Grain sizes (D50, D90), density, porosity, layers |
numerics |
Transport numerical parameters |
q3d |
Quasi-3D vertical structure |
groundwater |
Groundwater flow (if gwflow enabled) |
Relationship with Physics¶
The Sediment component handles what happens to the bed, while Physics handles hydrodynamics. They work together:
- Physics computes waves and currents
- Sediment uses those to compute transport and bed change
- Bed change feeds back to Physics (updated bathymetry)
from rompy_xbeach.components.sediment import Sediment
def print_params(lines, filename="params.txt"):
"""Special printing to simulate a params.txt file content"""
max_content_width = max(len(line) for line in lines) if lines else 0
max_width = max(len(filename), max_content_width)
box_width = max_width + 2
print("┌" + "─" * box_width + "┐")
print("│ " + filename.ljust(max_width) + " │")
print("├" + "─" * box_width + "┤")
for line in lines:
print("│ " + line.ljust(max_width) + " │")
print("└" + "─" * box_width + "┘")
def show_params(obj, destdir=None):
"""Helper to display parameters that would be written to params.txt."""
params = obj.get(destdir=destdir)
content = []
if not params:
content.append("")
else:
for key, value in params.items():
content.append(f"{key} = {value}")
print_params(content)
def print_warning(text):
"""Print text with warning-style highlighting."""
print(f"\033[48;5;224m\033[30m {text} \033[0m")
# Create Sediment with all defaults
sediment = Sediment()
show_params(sediment)
┌────────────┐ │ params.txt │ ├────────────┤ │ │ └────────────┘
An empty Sediment() produces no output - XBeach will use its defaults.
XBeach Default Behavior¶
| Parameter | Default | Meaning |
|---|---|---|
sedtrans |
0 (off) | Sediment transport disabled |
morphology |
0 (off) | Morphology disabled |
form |
vanthiel_vanrijn | Transport formulation |
morfac |
1.0 | No morphological acceleration |
D50 |
0.0002 m | Median grain size (fine sand) |
Note: Unlike Physics where many processes are on by default, sediment transport and morphology are off by default. You must explicitly enable them.
3. Enabling Sediment Transport¶
To enable sediment transport, set sedtrans=True or provide a SedimentTransport object.
3.1 Simple Enable¶
# Enable sediment transport with defaults
sediment_on = Sediment(sedtrans=True)
show_params(sediment_on)
┌──────────────┐ │ params.txt │ ├──────────────┤ │ sedtrans = 1 │ └──────────────┘
3.2 Transport Formulations¶
XBeach supports several sediment transport formulations:
| Formulation | Description | Best For |
|---|---|---|
vanthiel_vanrijn |
Van Thiel de Vries & Van Rijn | Dune erosion (default) |
soulsby_vanrijn |
Soulsby & Van Rijn (1997) | General coastal |
vanrijn1993 |
Van Rijn (1993) | Detailed studies |
from rompy_xbeach.components.sediment.transport import SedimentTransport
# Van Thiel de Vries formulation (default, optimized for dune erosion)
sediment_vanthiel = Sediment(
sedtrans=SedimentTransport(
form="vanthiel_vanrijn",
)
)
show_params(sediment_vanthiel)
┌─────────────────────────┐ │ params.txt │ ├─────────────────────────┤ │ sedtrans = 1 │ │ form = vanthiel_vanrijn │ └─────────────────────────┘
# Soulsby-Van Rijn formulation
sediment_soulsby = Sediment(
sedtrans=SedimentTransport(
form="soulsby_vanrijn",
)
)
show_params(sediment_soulsby)
┌────────────────────────┐ │ params.txt │ ├────────────────────────┤ │ sedtrans = 1 │ │ form = soulsby_vanrijn │ └────────────────────────┘
3.3 Wave Asymmetry and Skewness¶
Wave-induced transport is controlled by facua (or separately facAs and facSk).
These parameters control onshore transport due to wave nonlinearity.
# Calibrate wave-induced transport
sediment_waves = Sediment(
sedtrans=SedimentTransport(
facua=0.15, # Combined asymmetry/skewness factor (default: 0.1)
)
)
show_params(sediment_waves)
┌──────────────┐ │ params.txt │ ├──────────────┤ │ sedtrans = 1 │ │ facua = 0.15 │ └──────────────┘
# Or set asymmetry and skewness separately
sediment_waves_sep = Sediment(
sedtrans=SedimentTransport(
facAs=0.2, # Asymmetry factor (default: 0.2)
facSk=0.15, # Skewness factor (default: 0.15)
)
)
show_params(sediment_waves_sep)
┌──────────────┐ │ params.txt │ ├──────────────┤ │ sedtrans = 1 │ │ facAs = 0.2 │ │ facSk = 0.15 │ └──────────────┘
3.4 Bed Slope Effects¶
Bed slope affects both the magnitude and direction of transport:
sediment_slope = Sediment(
sedtrans=SedimentTransport(
bdslpeffmag="roelvink_total", # Magnitude modification (default)
bdslpeffdir="talmon", # Direction modification
facsl=1.6, # Slope effect factor
reposeangle=30.0, # Angle of repose (degrees)
)
)
show_params(sediment_slope)
┌──────────────────────────────┐ │ params.txt │ ├──────────────────────────────┤ │ sedtrans = 1 │ │ bdslpeffdir = talmon │ │ bdslpeffmag = roelvink_total │ │ facsl = 1.6 │ │ reposeangle = 30.0 │ └──────────────────────────────┘
3.5 Stirring Mechanisms¶
Control what processes stir up sediment:
sediment_stirring = Sediment(
sedtrans=SedimentTransport(
sws=True, # Short wave stirring (default: on)
lws=True, # Long wave stirring (default: on)
turb="wave_averaged", # Turbulence model (default)
)
)
show_params(sediment_stirring)
┌──────────────────────┐ │ params.txt │ ├──────────────────────┤ │ sedtrans = 1 │ │ lws = 1 │ │ sws = 1 │ │ turb = wave_averaged │ └──────────────────────┘
4.1 Enabling Morphology¶
from rompy_xbeach.components.sediment.morphology import Morphology
# Enable morphology with defaults
sediment_morph = Sediment(
morphology=True
)
show_params(sediment_morph)
┌────────────────┐ │ params.txt │ ├────────────────┤ │ morphology = 1 │ └────────────────┘
4.2 Morphological Acceleration (morfac)¶
The morfac parameter accelerates morphological change relative to hydrodynamics.
This allows simulating slow processes (hours/days) with shorter hydrodynamic runs.
Example: morfac=10 means 1 hour of waves produces 10 hours of bed change.
sediment_morfac = Sediment(
morphology=Morphology(
morfac=10.0, # 10x acceleration
morstart=0.0, # Start morphology at t=0
morstop=36000.0, # Stop at t=36000s (10 hours morphological time)
)
)
show_params(sediment_morfac)
┌───────────────────┐ │ params.txt │ ├───────────────────┤ │ morphology = 1 │ │ morfac = 10.0 │ │ morstart = 0.0 │ │ morstop = 36000.0 │ └───────────────────┘
4.3 Avalanching¶
Avalanching occurs when slopes exceed critical values. Different slopes apply above and below water:
sediment_aval = Sediment(
morphology=Morphology(
dryslp=1.0, # Critical slope above water (default: 1.0, ~45°)
wetslp=0.3, # Critical slope below water (default: 0.3, ~17°)
hswitch=0.1, # Depth to switch between dry/wet slopes (m)
dzmax=0.05, # Max bed change per timestep (m/s/m)
)
)
show_params(sediment_aval)
┌────────────────┐ │ params.txt │ ├────────────────┤ │ morphology = 1 │ │ dryslp = 1.0 │ │ dzmax = 0.05 │ │ hswitch = 0.1 │ │ wetslp = 0.3 │ └────────────────┘
4.4 Non-Erodible Structures¶
Define hard structures that limit erosion:
sediment_struct = Sediment(
morphology=Morphology(
struct=True, # Enable non-erodible layer
# ne_layer would point to a file defining layer thickness
)
)
show_params(sediment_struct)
┌────────────────┐ │ params.txt │ ├────────────────┤ │ morphology = 1 │ │ struct = 1 │ └────────────────┘
5. Bed Composition¶
Bed composition defines sediment properties - critical for transport calculations.
5.1 Grain Sizes¶
The most important parameters are D50 (median) and D90 (90th percentile):
from rompy_xbeach.components.sediment.composition import BedComposition
# Fine sand (typical beach)
sediment_sand = Sediment(
bed_composition=BedComposition(
D50=0.0002, # 0.2 mm median grain size
D90=0.0003, # 0.3 mm 90th percentile
)
)
show_params(sediment_sand)
┌──────────────┐ │ params.txt │ ├──────────────┤ │ D50 = 0.0002 │ │ D90 = 0.0003 │ └──────────────┘
# Coarse sand / gravel (XBeach-G applications)
sediment_gravel = Sediment(
bed_composition=BedComposition(
D50=0.01, # 10 mm median grain size
D90=0.015, # 15 mm 90th percentile
)
)
show_params(sediment_gravel)
┌─────────────┐ │ params.txt │ ├─────────────┤ │ D50 = 0.01 │ │ D90 = 0.015 │ └─────────────┘
5.2 Sediment Properties¶
sediment_props = Sediment(
bed_composition=BedComposition(
D50=0.0002,
D90=0.0003,
rhos=2650.0, # Sediment density (kg/m³, quartz default)
por=0.4, # Porosity (void fraction)
)
)
show_params(sediment_props)
┌───────────────┐ │ params.txt │ ├───────────────┤ │ D50 = 0.0002 │ │ D90 = 0.0003 │ │ rhos = 2650.0 │ │ por = 0.4 │ └───────────────┘
5.3 Bed Layering¶
XBeach divides the bed into layers for tracking sediment:
sediment_layers = Sediment(
bed_composition=BedComposition(
D50=[0.0002],
D90=[0.0003],
nd=3, # Number of layers (default: 3)
dzg1=0.1, # Top layer thickness (m)
dzg2=0.1, # Middle layer thickness (m)
dzg3=0.1, # Bottom layer thickness (m)
)
)
show_params(sediment_layers)
┌──────────────┐ │ params.txt │ ├──────────────┤ │ nd = 3 │ │ D50 = 0.0002 │ │ D90 = 0.0003 │ │ dzg1 = 0.1 │ │ dzg2 = 0.1 │ │ dzg3 = 0.1 │ └──────────────┘
5.4 Multiple Sediment Classes¶
For graded sediments, use multiple grain size classes:
sediment_graded = Sediment(
bed_composition=BedComposition(
ngd=2, # 2 sediment classes
D50=[0.0001, 0.0004], # Fine and coarse fractions
D90=[0.00015, 0.0006], # Corresponding D90 values
)
)
show_params(sediment_graded)
┌──────────────────────┐ │ params.txt │ ├──────────────────────┤ │ ngd = 2 │ │ D50 = 0.0001 0.0004 │ │ D90 = 0.00015 0.0006 │ └──────────────────────┘
from rompy_xbeach.components.sediment.transport import TransportNumerics
sediment_numerics = Sediment(
numerics=TransportNumerics(
cmax=0.1, # Maximum concentration (default: 0.1)
thetanum=1.0, # Upwind (1.0) vs central (0.5) scheme
)
)
show_params(sediment_numerics)
┌────────────────┐ │ params.txt │ ├────────────────┤ │ cmax = 0.1 │ │ thetanum = 1.0 │ └────────────────┘
from rompy_xbeach.components.sediment.transport import Quasi3D
sediment_q3d = Sediment(
q3d=Quasi3D(
kmax=100, # Number of vertical layers (default: 100)
sigfac=1.3, # Layer distribution factor
)
)
show_params(sediment_q3d)
┌──────────────┐ │ params.txt │ ├──────────────┤ │ q3d = 1 │ │ kmax = 100 │ │ sigfac = 1.3 │ └──────────────┘
8.1 Grain Size Validation¶
D90 must be greater than D50:
from pydantic import ValidationError
try:
invalid_grains = BedComposition(
D50=[0.0003], # D50 larger than D90!
D90=[0.0002],
)
except ValidationError as e:
print_warning(f"{e.errors()[0]['msg']}")
print("\n(Validation error caught)\n")
Value error, D90[0] (0.0002) must be greater than D50[0] (0.0003)
(Validation error caught)
8.2 Sediment Class Consistency¶
When using multiple classes, all lists must have the same length:
try:
invalid_classes = BedComposition(
ngd=2,
D50=[0.0002], # Only 1 value, but ngd=2!
D90=[0.0003],
)
except ValidationError as e:
print_warning(f"{e.errors()[0]['msg']}")
print("\n(Validation error caught)\n")
Value error, D50 must have 2 values (one per sediment class), but got 1 values. Set ngd=1 or adjust D50.
(Validation error caught)
8.3 Cross-Parameter Warnings¶
Some parameter combinations generate warnings:
import logging
logging.basicConfig(level=logging.WARNING)
# Bore-averaged turbulence with ruessink_vanrijn waveform
sediment_warning = Sediment(
sedtrans=SedimentTransport(
turb="bore_averaged",
waveform="ruessink_vanrijn", # Incompatible combination
)
)
print("\n(A warning was logged above)")
2026-01-10 16:51:36 [WARNING] rompy_xbeach.components.sediment.transport: ! Bore-averaged turbulence (turb='bore_averaged') cannot be combined with the Ruessink et al. (2012) wave form (waveform='ruessink_vanrijn'). The Ruessink formulation does not determine an exact wave shape, which is required to calculate the bore interval for bore-averaged turbulence. Consider using waveform='vanthiel' or turb='wave_averaged' instead. 2026-01-10 16:51:36 [WARNING] rompy_xbeach.components.sediment.transport: ! Bore-averaged turbulence (turb='bore_averaged') cannot be combined with the Ruessink et al. (2012) wave form (waveform='ruessink_vanrijn'). The Ruessink formulation does not determine an exact wave shape, which is required to calculate the bore interval for bore-averaged turbulence. Consider using waveform='vanthiel' or turb='wave_averaged' instead.
(A warning was logged above)
# Storm impact simulation with morphology
sediment_storm = Sediment(
# Sediment transport
sedtrans=SedimentTransport(
form="vanthiel_vanrijn",
facua=0.15,
bdslpeffmag="roelvink_total",
sws=True,
lws=True,
turb="wave_averaged",
),
# Morphology with acceleration
morphology=Morphology(
morfac=10.0,
morstart=0.0,
morstop=36000.0,
dryslp=1.0,
wetslp=0.3,
),
# Bed composition (fine sand)
bed_composition=BedComposition(
D50=[0.0002],
D90=[0.0003],
rhos=2650.0,
por=0.4,
),
# Numerics
numerics=TransportNumerics(
cmax=0.1,
),
)
show_params(sediment_storm)
┌──────────────────────────────┐ │ params.txt │ ├──────────────────────────────┤ │ sedtrans = 1 │ │ bdslpeffmag = roelvink_total │ │ facua = 0.15 │ │ form = vanthiel_vanrijn │ │ lws = 1 │ │ sws = 1 │ │ turb = wave_averaged │ │ morphology = 1 │ │ dryslp = 1.0 │ │ morfac = 10.0 │ │ morstart = 0.0 │ │ morstop = 36000.0 │ │ wetslp = 0.3 │ │ D50 = 0.0002 │ │ D90 = 0.0003 │ │ rhos = 2650.0 │ │ por = 0.4 │ │ cmax = 0.1 │ └──────────────────────────────┘
config_example = """
from rompy_xbeach import Config
from rompy_xbeach.components.physics import Physics
from rompy_xbeach.components.sediment import Sediment
from rompy_xbeach.components.sediment.transport import SedimentTransport
from rompy_xbeach.components.sediment.morphology import Morphology
from rompy_xbeach.components.output import Output
config = Config(
project="storm_erosion",
grid=grid,
bathy=bathy,
# Physics (hydrodynamics)
physics=Physics(
wavemodel=Surfbeat(),
flow=True,
),
# Sediment (transport and morphology)
sediment=Sediment(
sedtrans=SedimentTransport(form="vanthiel_vanrijn"),
morphology=Morphology(morfac=10.0),
),
# Output
output=Output(
outputformat="netcdf",
tintg=3600,
),
)
config.generate(destdir="./model_run")
"""
print("Config integration example:")
print(config_example)
Config integration example:
from rompy_xbeach import Config
from rompy_xbeach.components.physics import Physics
from rompy_xbeach.components.sediment import Sediment
from rompy_xbeach.components.sediment.transport import SedimentTransport
from rompy_xbeach.components.sediment.morphology import Morphology
from rompy_xbeach.components.output import Output
config = Config(
project="storm_erosion",
grid=grid,
bathy=bathy,
# Physics (hydrodynamics)
physics=Physics(
wavemodel=Surfbeat(),
flow=True,
),
# Sediment (transport and morphology)
sediment=Sediment(
sedtrans=SedimentTransport(form="vanthiel_vanrijn"),
morphology=Morphology(morfac=10.0),
),
# Output
output=Output(
outputformat="netcdf",
tintg=3600,
),
)
config.generate(destdir="./model_run")
Summary¶
Key Takeaways¶
Sediment transport and morphology are OFF by default - you must enable them
Transport formulation choice matters:
vanthiel_vanrijn: Dune erosion (default)soulsby_vanrijn: General coastal
Morfac accelerates morphology - use wisely:
morfac=1: Real-time (slow)morfac=10-100: Typical for storm simulations
Grain size is critical:
- Fine sand: D50 ~ 0.0002 m
- Gravel: D50 ~ 0.01 m
Validation catches errors early - trust the error messages
Typical Morfac Values¶
| Application | Morfac | Duration |
|---|---|---|
| Detailed erosion | 1 | Hours |
| Storm events | 5-10 | Hours to days |
| Seasonal | 20-50 | Weeks to months |
| Long-term | 50-200 | Months to years |
Next Steps¶
- See the Physics Tutorial for hydrodynamics
- See the Output Tutorial for output configuration
- See the Full Example for a complete workflow