Terrapin (or TerraPIN) stands for "Terraces Put Into Numerics". It generates the terraces — both strath and fill — that a river leaves as it incises, aggrades, and planes laterally across its valley.
STARTED 09 SEPTEMBER 2013 (written by ADW)
TerraPIN models a river-valley cross-section as material polygons (Shapely/GEOS) and expresses the physics as polygon algebra: incision and lateral planation remove material, aggradation and talus add it, and eroded and deposited volumes are polygon areas — so mass is conserved by construction rather than by bookkeeping.
It is a driver-agnostic geometry and mass-balance engine. You tell it what
happened — "incise to z", "plane to channel width w", "aggrade to level" —
and it reports back the updated geometry, the mass balance (eroded and deposited
volumes, sediment out), and the emergent valley width. It does not decide
rates, erosion laws, or channel migration; those live in whatever drives it (for
example GRLP for vertical change, a separate
lateral-migration model, or a test).
Each material body is a deposit that carries the age of its formation;
each stranded surface carries the age of its abandonment. A terrace is an
abandoned surface, so its age is the age of abandonment — and the deposit it is
cut on keeps its own, separate deposition age. Terrapin.terraces() reads the
benches straight from the live geometry and returns both, so a cut–fill–recut
history is legible as strath and fill terraces annotated with when they formed
and when the river left them behind.
from shapely.geometry import box
from terrapin import Terrapin
tp = Terrapin()
tp.set_bodies({"bedrock": box(-140.0, -80.0, 0.0, -6.0),
"alluvium": box(-140.0, -6.0, 0.0, 0.0)})
tp.set_repose_angles({"bedrock": 75.0, "alluvium": 32.0, "colluvium": 20.0})
tp.set_channel_elevation(0.0)
tp.incise(-8.0, age=5.0) # cut down; strand the land surface
tp.plane_laterally(95.0) # plane a strath (its age is set when abandoned)
tp.set_channel_width(0.0)
tp.aggrade(-3.0, age=22.0) # a valley fill
tp.incise(-20.0, age=33.0) # re-incise; strand the fill top
for t in tp.terraces():
print(t["kind"], "at z =", t["z"],
"| terrace age (abandoned) =", t["age"],
"| deposit age =", t["deposit_age"])The symmetric Terrapin above holds the channel at a fixed position. The
standard model — StandardTerrapin — instead resolves the channel's
position on the valley floor, so the valley evolves asymmetrically. Alongside
incise and aggrade it adds:
migrate(x)— the channel planes laterally to a new position, undercutting the wall it advances into and (at transport capacity) leaving a channel belt.avulse(x)— a discontinuous hop that abandons the old channel in place, preserving its belt to be buried by later aggradation.retreat(side, dx)— a hillslope process: an abandoned wall retreats parallel and sheds talus at its base. This is the river-absent counterpart to the channel's work — the interplay a migrating channel unlocks.
All the channel motions are special cases of one primitive, sweep(x1, z1): a
level move is migrate, a vertical move is incise/aggrade, and a diagonal
move — lateral planation while incising — leaves a sloped strath, the classic
strath-terrace-forming process.
Every body carries a porosity, so sediment_out is a solid volume (the
load a river actually carries; area_out is the bulk), and
compute_valley_width() returns the emergent wall-to-wall width. Those two, plus a
BMI wrapper (terrapin.bmi.BmiStandardTerrapin, pip install terrapin-valley[bmi]), make the standard model ready to couple one cross-section
per node to a long-profile model such as
GRLP.
TerraPIN is a small pure-Python package; install it from source (pip install -e . or by putting the repository on your PYTHONPATH). The geometry engine
requires Python 3, NumPy 2, Shapely (GEOS), and SciPy;
Matplotlib is used for plotting. A dedicated environment keeps these
consistent — for example:
conda create -n terrapin numpy shapely scipy matplotlib pytest
conda run -n terrapin python -m pytestdocs/architecture.md— the model: polygon algebra, the driver-agnostic engine, the one-wall unit, symmetric vs. the standard model, and terrace/provenance tracking.examples/— worked cross-sections, insymmetric/(e.g.terrace_tracking.py— terraces read back and labelled by age) andstandard/:standard_terraces.py(migration, avulsion, channel belts, terraces),talus_slope_retreat.py(the hillslope talus mechanism), andtalus_valley.py(fluvial abandonment then hillslope retreat).- AlluvStrat — ADW's earlier raster model of alluvial stratigraphy in strike-section.
If you use TerraPIN, please cite it: GitHub builds a ready-made citation from
CITATION.cff (the "Cite this repository" button), and every
release is archived on Zenodo with a DOI.