A Python re-implementation of the BR-MANGUE coastal flood and mangrove migration model (Bezerra et al., 2013), built on top of DisSModel and compared against the original TerraME version.
This repository was created with a modest, specific goal: to replicate the BR-MANGUE model originally written in TerraME/Lua (LambdaGeo/brmangue-terrame) using the DisSModel framework, so that the two implementations can be compared side by side.
Two coupled processes are modelled, following Bezerra et al. (2013):
- Flood Dynamics β sea-level rise propagation and terrain elevation adjustments.
- Mangrove Migration β ecosystem response to rising sea levels, soil transitions, and sediment accretion.
As an additional experiment, the model is implemented on two spatial substrates offered by DisSModel, which lets us also compare how they behave and what each costs in computing time:
- Raster (
brmangue.models.raster) β NumPy/RasterBackend, vectorized. This is the implementation we use as the reference for the comparison with TerraME. - Vector (
brmangue.models.vector) β GeoDataFrame/libpysal, cell-by-cell over real polygon geometry. It is written to follow the same rules as the raster version, and a benchmark executor checks how closely the two agree.
β οΈ Status: this is work in progress. The comparison with TerraME covers two reference scenarios, a baseline and a flooding one (see Testing & Validation); the model still needs to be validated against more scenarios before it should be relied upon for scientific conclusions.
# Raster simulation (NumPy-based)
python examples/main_raster.py run \
--input examples/data/input/synthetic_grid_60x60_tiff.zip \
--output examples/data/output/saida.tiff \
--param interactive=true \
--param end_time=20
# Vector simulation (GeoDataFrame-based)
python examples/main_vector.py run \
--input examples/data/input/synthetic_grid_60x60_shp.zip \
--output examples/data/output/saida.gpkg \
--param end_time=20
# Load calibrated parameters from TOML (works for both substrates)
python examples/main_raster.py run \
--input examples/data/input/synthetic_grid_60x60_tiff.zip \
--toml examples/model.toml
# Vector vs Raster comparison (agreement and runtime)
python examples/main_benchmark.py run \
--input examples/data/input/synthetic_grid_60x60_shp.zip \
--param end_time=10 \
--param sea_level_rise_rate=0.011 \
--param tolerance=0.05
# Validate executor data contract without running
python examples/main_raster.py validate \
--input examples/data/input/synthetic_grid_60x60_tiff.zip
# Prepare raster from vector
python examples/prepare_raster.py data/input.shp --output data/input.tif
# Compare against TerraME golden CSVs
python src/brmangue/executors/validation_executor.py run \
--input examples/data/input/elevacao_pol.zip \
--param golden_dir=tests/fixtures/golden \
--param end_time=19 \
--param sea_level_rise_rate=0.05 \
--param tide_height=6.0 \
--param checkpoints=[1,5,10,15,20]# Submit job
curl -X POST http://localhost:8000/submit_job \
-H "X-API-Key: <your-api-key>" \
-H "Content-Type: application/json" \
-d '{
"model_name": "brmangue_raster",
"input_dataset": "s3://dissmodel-inputs/ilha_maranhao_epsg31983.tif",
"parameters": {"end_time": 88, "sea_level_rise_rate": 0.011}
}'Sea-level rise propagates across the landscape using a push-based neighbourhood algorithm that we tried to keep faithful to the original TerraME implementation (Bezerra et al., 2013).
Ecosystem transitions driven by tidal influence and flooding thresholds, including soil migration and optional sediment accretion (Alongi, 2008).
Both processes exist in raster and vector form, using the same equations, thresholds, parameter names, and update ordering.
This package and the TerraME adaptation
(brmangue-terrame) use the same
English names, so the two codes can be read side by side. Python uses
snake_case, Lua camelCase. The data keep their Portuguese names: bands and
columns uso, solo, alt, and the class codes below.
The attribute names are written in one place only, brmangue.common.constants;
the rest of the code uses the constants (in Lua, the attribute_names table plays
the same role):
LAND_USE = "uso" # Lua: attribute_names.land_use
SOIL = "solo" # Lua: attribute_names.soil
ALTITUDE = "alt" # Lua: attribute_names.altitude
past(LAND_USE) # "uso_past", start-of-step snapshot (TerraME cell.past)If the data are renamed, change these three lines. Files whose attributes have other
names can also be mapped at run time, without code changes, with column_map
(vector) or band_map (GeoTIFF).
| Concept | Python (this package) | Lua (brmangue-terrame) |
|---|---|---|
| sea-level rise per step (m) | sea_level_rise_rate |
seaLevelRiseRate |
| tide height (m) | tide_height |
tideHeight |
| vertical accretion on/off | accretion_enabled |
(applyAccretion call, commented out) |
| sea level at step t | sea_level |
seaLevel |
| tidal influence zone | influence_zone |
influenceZone |
| flux / lower neighbours | flux, lower_neighbors |
flux, lowerNeighbors |
| land-use / soil / altitude attribute | land_use_attr, soil_attr, altitude_attr |
landUseAttr, soilAttr, altitudeAttr |
| models | FloodModel, MangroveModel |
Flood (models/flood.lua), Mangrove (models/mangrove.lua) |
| flooded uses / flooding rules | FLOODED_USES, FLOODING_RULES |
isSeaOrFlooded, applyFlooding |
| Code | Land use (uso) |
Original name |
|---|---|---|
| 1 | MANGROVE |
Mangue |
| 2 | TERRESTRIAL_VEGETATION |
VegetaΓ§Γ£o terrestre |
| 3 | SEA |
Mar |
| 4 | ANTHROPIZED_AREA |
Γrea antropizada |
| 5 | BARE_SOIL |
Solo descoberto |
| 6 | FLOODED_SOIL |
Solo inundado |
| 7 | FLOODED_ANTHROPIZED_AREA |
Γrea antropizada inundada |
| 8 | MIGRATED_MANGROVE |
Mangue migrado |
| 9 | FLOODED_MANGROVE |
Mangue inundado |
| 10 | FLOODED_TERRESTRIAL_VEGETATION |
VegetaΓ§Γ£o terrestre inundada |
| Code | Soil (solo) β Python / Lua |
Original name |
|---|---|---|
| 0 | SOIL_RIVER_CHANNEL / soil_classes.RIVER_CHANNEL |
Canal fluvial |
| 1 | SOIL_RIVERBED / soil_classes.RIVERBED (no transition rule) |
Leito de rio |
| 2 | SOIL_PODZOLIC / soil_classes.PODZOLIC (no transition rule) |
PodzΓ³lico |
| 3 | SOIL_MANGROVE / soil_classes.MANGROVE (mangrove mud) |
Mangue |
| 4 | SOIL_OTHER / soil_classes.OTHER |
Outros |
| 9 | SOIL_MIGRATED_MANGROVE / soil_classes.MIGRATED_MANGROVE |
Mangue migrado |
Before 0.5.0 these names were in Portuguese (taxa_elevacao, altura_mare,
acrecao_ativa, MANGUE_MIGRADO, SOLO_MANGUEβ¦). The executors reject the old
parameter names with a message that gives the new one; see CHANGELOG.md.
The project follows the DisSModel ModelExecutor pattern β each executor separates
science from infrastructure.
| name | Substrate | Input β Output | Description |
|---|---|---|---|
brmangue_raster |
RasterBackend / NumPy | Shapefile / GeoTIFF β GeoTIFF | Raster simulation, used as the reference for comparison with TerraME |
brmangue_vector |
GeoDataFrame / libpysal | Shapefile / ZIP β GeoPackage | Cell-by-cell vector simulation over real polygon geometry |
brmangue_benchmark |
raster + vector | Shapefile / ZIP β scatter.png + report.md | Runs both substrates on the same input and reports match %/MAE/RMSE per band, plus runtime |
validation |
RasterBackend | Shapefile / ZIP β scatter.png + report.md | Compares raster output against TerraME golden CSVs at configurable checkpoints |
# Vector simulation over real geometry (GeoDataFrame / libpysal)
python examples/main_vector.py run \
--input examples/data/input/synthetic_grid_60x60_shp.zip \
--output examples/data/output/saida.gpkg \
--param end_time=88 \
--param sea_level_rise_rate=0.5 \
--param tide_height=6.0
# With column remapping (source uses non-canonical names)
python examples/main_vector.py run \
--input examples/data/input/synthetic_grid_60x60_shp.zip \
--column-map uso=land_use alt=elevation solo=soil# Runs both Vector and Raster models on the same input; reports match per band
python examples/main_benchmark.py run \
--input examples/data/input/synthetic_grid_60x60_shp.zip \
--param end_time=10 \
--param sea_level_rise_rate=0.011 \
--param tide_height=6.0 \
--param tolerance=0.05
# Output artifacts written to outputs/experiments/<id>/benchmark/
# scatter.png β per-band Vector vs Raster scatter plots
# report.md β runtime (ms/step) and accuracy tableOn synthetic_grid_60x60_shp.zip with the parameters above (3,600 cells, 10 steps)
the two substrates agree on every cell of uso and solo, and alt agrees with
MAE 0.0011 and a maximum error of 0.024 m; tests/test_synthetic_benchmark.py
checks this. The runtime columns depend on the machine.
The runtime figures in report.md are what we use to compare the efficiency of
the raster and vector substrates. They depend on the machine and the input, so
we recommend running the benchmark on your own data rather than taking any
single number as general.
# From source
git clone https://github.com/DisSModel/brmangue-dissmodel.git
cd brmangue-dissmodel
pip install -e .brmangue-dissmodel/
βββ src/
β βββ brmangue/
β βββ __init__.py
β βββ common/
β β βββ constants.py # TIFF_BANDS, CRS, USE_COLORS, ...
β β βββ utils.py # default_output_uri helper
β βββ executors/ # ModelExecutor implementations
β β βββ __init__.py # imports executors β auto-registration
β β βββ raster_executor.py # Raster simulation
β β βββ vector_executor.py # Vector simulation over real geometry
β β βββ benchmark_executor.py # Vector vs raster comparison
β β βββ validation_executor.py # Comparison against TerraME golden CSVs
β βββ models/
β βββ raster/ # NumPy-based models
β β βββ flood_model.py
β β βββ mangrove_model.py
β βββ vector/ # GeoDataFrame-based models
β βββ flood_model.py
β βββ mangrove_model.py
βββ tests/
β βββ fixtures/golden/ # TerraME reference CSVs (step_01..step_20)
β βββ test_transition_rules.py
β βββ test_model_invariants.py
βββ examples/
β βββ main_raster.py # BrmangueRasterExecutor via CLI
β βββ main_vector.py # BrmangueVectorExecutor via CLI
β βββ main_benchmark.py # BrmangueBenchmarkExecutor via CLI
β βββ prepare_raster.py # Vector to GeoTIFF converter
β βββ model.toml # Simulation parameters
β βββ data/
βββ pyproject.toml
Two test modules cover basic model correctness without external data:
tests/test_transition_rules.pyβ analytical tests on 3Γ3 synthetic grids with hand-calculated expected values (flood propagation, mangrove soil/use migration, altitude blocking).tests/test_model_invariants.pyβ structural invariants on a 5Γ5 real grid (flooded cells monotonically non-decreasing,SOIL_MIGRATED_MANGROVEnever reverts, masked cells never change, etc.).
pytest tests/ -vValidationExecutor (src/brmangue/executors/validation_executor.py,
name="validation") runs the raster model and compares its output step-by-step
against reference CSVs generated by the original TerraME/Lua model
(Bezerra et al., 2013), located in tests/fixtures/golden/step_NN.csv
(currently step_01 β¦ step_20).
Metrics reported per band (uso, solo, alt) at each checkpoint:
match %, MAE, RMSE, max_err.
The golden CSVs are indexed on state, not on number of executions:
step_01.csv is the initial state, before the model has run once (verified:
zero cells differ from the input shapefile). Simulation step N therefore maps
to step_{N+1}.csv, applied via GOLDEN_STEP_OFFSET in the executor.
With 20 golden files, the highest comparable simulation step is 19.
| Step | uso |
solo |
alt (1 mm tol) |
alt MAE |
|---|---|---|---|---|
| 1 | 100.0% | 100.0% | 100.0% | 0.00000 |
| 5 | 100.0% | 100.0% | 99.6% | 0.00002 |
| 10 | 100.0% | 100.0% | 98.6% | 0.00017 |
| 19 | 100.0% | 100.0% | 97.4% | 0.00038 |
In this scenario, the categorical bands (uso, solo) agree with TerraME cell
for cell at every checkpoint. Only alt diverges slightly (maximum absolute
error 0.10 m after 19 steps, against elevations of 1β58 m). The residual is
floating-point tie-breaking, not a rule difference: the flux rule compares
accumulated elevations with <=, and ~57% of neighbour pairs hold exactly
equal elevations, so a ~1e-16 difference in summation order (TerraME visits
cells sequentially, NumPy adds neighbour contributions per direction) flips an
occasional comparison. Fed the exact TerraME state (17 significant digits), the
elevation rule reproduces the next TerraME step to 1e-14 at most steps.
Same dataset, with the laboratory parameters of lab1.lua, where flooding does
occur (TerraME flood golden regenerated with TerraME 2.0.1; 2,469 flooded cells
at step 11). Python vs TerraME:
| Step | uso |
solo |
alt (1 mm tol) |
alt MAE |
|---|---|---|---|---|
| 1 | 100.0% | 100.0% | 100.0% | 0.00000 |
| 3 | 100.0% | 100.0% | 98.8% | 0.00063 |
| 5 | 100.0% | 100.0% | 97.8% | 0.00200 |
| 10 | 100.0% | 100.0% | 94.9% | 0.00708 |
| 11 | 99.99% | 100.0% | 94.4% | 0.00801 |
solo is exact at every step and uso differs in <0.05% of cells (4 cells at
step 11, frontier cells whose flooding flips on the same elevation ties); the
maximum alt error at step 11 is 1.01 m. The golden files for this scenario are
in tests/fixtures/golden_flood/ (only the steps the checkpoints need) and
tests/test_flood_validation.py checks the comparison; to regenerate them, run
make golden TAXA=0.5 FINAL=11 OUT=golden_flood in
brmangue-terrame. Because the
flooding threshold is discontinuous, the tie noise grows with the number of
steps; this scenario should be read as "same dynamics, not bit-identical".
These results should be read with care, because the model has been validated on two scenarios so far, and the baseline one is a limited test:
- At
sea_level_rise_rate=0.05the flood component never triggers a land-use transition: the lowest cell adjacent to a source sits at 1.0 m and the sea only reaches 1.0 m at step 20, by which point flux diffusion has raised it further. The golden CSVs show TerraME behaving the same way (zero newly flooded cells across all 20 steps), so the two implementations agree β but this scenario leaves the flood component essentially unexercised, and the agreement above mostly reflects the mangrove migration component. - The original laboratory script (
lab1.lua) usesTAXA_ELEVACAO_MAR = 0.5withFINAL_TIME = 11, under which flooding does occur (2,469 cells by step 11 in TerraME). The "Flood scenario" table above compares that run step by step with TerraME, andtests/test_model_invariants.py::test_flood_model_floods_with_laboratory_parameterschecks that flooding happens under those parameters. - The vector/raster comparison and the runtime measurements have likewise been run on a limited set of inputs.
Next steps are to validate the model against additional scenarios β especially ones in which flooding actually occurs β and to extend the raster/vector comparison to more datasets. Feedback, issues and suggestions are very welcome.
# See Quick Start above for the full CLI invocation:
python src/brmangue/executors/validation_executor.py run \
--input examples/data/input/elevacao_pol.zip \
--param golden_dir=tests/fixtures/golden \
--param end_time=19 \
--param 'checkpoints=[1,5,10,19]'Bezerra, D. da S., Amaral, S., & Kampel, M. (2013). Impactos da ElevaΓ§Γ£o do NΓvel MΓ©dio do Mar sobre o Ecossistema Manguezal: A ContribuiΓ§Γ£o do Sensoriamento Remoto e Modelos Computacionais. CiΓͺncia e Natura, 35(2), 152β162. https://doi.org/10.5902/2179460X12569
Original TerraME implementation: LambdaGeo/brmangue-terrame
This port builds on the reference implementation and design ideas of Felipe Martins Sousa (UFMA), co-author of the BR-MANGUE application to the Baixada Maranhense (Bezerra et al., 2025, https://doi.org/10.5772/intechopen.1012210).
Developed by the LambdaGeo research group.