Continuous Spatial Library for Land Use Change Modeling — A Python implementation of continuous LUCC modeling components (LUCCME-like), built on top of DissModel
DisSLUCC-Continuous is a Python library that implements spatially explicit components for continuous Land Use and Cover Change (LUCC) modeling. It is directly inspired by the LUCCME framework and the TerraME environment, originally developed by the Earth System Science Center (CCST/INPE, Brazil).
DisSLUCC-Continuous focus on continuous land use change (area/percentage per cell), equivalent to the LUCCME core components.
| Original Ecosystem (INPE/CCST) | LambdaGeo Ecosystem | Role |
|---|---|---|
| TerraME | dissmodel |
Generic framework for dynamic spatial modeling |
| LUCCME | DisSLUCC-Continuous |
Domain-specific environment for continuous LUCC modeling |
| TerraLib | geopandas/shapely |
Geographic data handling |
| FillCell | dissluc.io |
Cellular space preparation utilities |
┌─────────────────────────────────────┐ ┌─────────────────────────────────────┐
│ Original Stack (INPE/CCST) │ │ LambdaGeo Stack │
│ ┌───────────┐ ┌───────────┐ │ │ ┌───────────┐ ┌───────────┐ │
│ │ TerraME │→ │ LUCCME │ │ → │ │ DissModel │→ │ DisSLUCC │ │
│ │(framework)│ │(LUCC dom.)│ │ │ │(framework)│ │(continuous) │
│ └───────────┘ └───────────┘ │ │ └───────────┘ └───────────┘ │
└─────────────────────────────────────┘ └─────────────────────────────────────┘
> ℹ️ **Note**: Both the Python package name and repository name are **DisSLUCC-Continuous** (`dissluc` for imports).
---
## 🚀 Quick Start
DisSLUCC supports two usage modes that share the same model code — **CLI local** for development and exploration, **Platform API** for reproducible production runs.
### CLI local (development)
```bash
# Vector substrate
python lab1_vector.py run \
--input data/input/csAC.zip \
--param interactive=True
# Raster substrate
python lab1_raster.py run \
--input data/input/csAC.zip \
--output data/output/result.tif \
--param interactive=True \
--param n_steps=7
# Load parameters from TOML (calibrated coefficients)
python lab1_raster.py run \
--input data/input/csAC.zip \
--toml examples/model.toml
# Validate executor data contract without running
python lab1_raster.py validate --input data/input/csAC.zip
# Run the Benchmark suite (Vector vs Raster vs TerraME/LUCCME comparison)
python -m dissluc.infra.executors.lucc_benchmark_executor run \
--input examples/data/input/csAC.zip \
--output ./benchmark/ \
--param demand_csv=examples/data/input/examples_demand_lab1.csv \
--param terrame_reference=benchmark/data/LUCCME_Lab1_2014.zip \
--param n_steps=6 \
--param tolerance=0.01
# Show resolved parameters
python lab1_raster.py show --toml examples/model.toml
# Submit job
curl -X POST http://localhost:8000/submit_job \
-H "X-API-Key: chave-sergio" \
-H "Content-Type: application/json" \
-d '{
"model_name": "lucc_raster",
"input_dataset": "s3://dissmodel-inputs/csAC.zip",
"parameters": {"n_steps": 7}
}'
# Check status
curl -H "X-API-Key: chave-sergio" \
http://localhost:8000/job/<experiment_id>
# Reproduce exact experiment
curl -X POST http://localhost:8000/experiments/<id>/reproduce \
-H "X-API-Key: chave-sergio"DisSLUCC implements the three-pillar LUCC modeling philosophy described by Verburg et al. (2006):
Computes the magnitude of land-use change to allocate at each time step.
from dissluc import DemandPreComputedValues, load_demand_csv
demand = DemandPreComputedValues(
annual_demand = load_demand_csv("demand.csv", ["f", "d", "outros"]),
land_use_types = ["f", "d", "outros"],
)Estimates the suitability of each cell to change, based on spatial driving factors.
from dissluc import PotentialLinearRegression, RegressionSpec
potential = PotentialLinearRegression(
gdf = gdf,
land_use_types = ["f", "d", "outros"],
land_use_no_data = "outros",
potential_data = [[
RegressionSpec(const=0.7392, betas={
"assentamen": -0.2193, "uc_us": 0.1754,
"dist_riobr": 2.388e-7, "fertilidad": -0.1313,
}),
RegressionSpec(const=0.267, betas={
"rodovias": -9.922e-7, "assentamen": 0.2294,
}),
RegressionSpec(const=0.0), # "outros" — no betas
]],
)Available algorithms:
| Discrete | Continuous |
|---|---|
PotentialDLogisticRegression |
PotentialLinearRegression ✅ |
PotentialDNeighSimpleRule |
PotentialCSpatialLagRegression |
PotentialDSampleBased |
PotentialCSampleBased |
Spatially distributes changes based on demand and cell-level potential.
from dissluc import AllocationClueLike, AllocationSpec
AllocationClueLike(
gdf = gdf,
demand = demand,
potential = potential,
land_use_types = ["f", "d", "outros"],
static = {"f": -1, "d": -1, "outros": 1},
complementar_lu = "f",
cell_area = 25.0, # km²
allocation_data = [[
AllocationSpec(static=-1, min_value=0, max_value=1, min_change=0, max_change=1),
AllocationSpec(static=-1, min_value=0, max_value=1, min_change=0, max_change=1),
AllocationSpec(static=1, min_value=0, max_value=1, min_change=0, max_change=1),
]],
)Available algorithms:
| Discrete | Continuous |
|---|---|
AllocationDClueSLike |
AllocationClueLike ✅ |
AllocationDSimpleOrdering |
AllocationClueLikeSaturation |
DisSLUCC follows the DissModel ModelExecutor pattern — each executor separates science from infrastructure. The same model runs locally via CLI or on the platform via API without changing a single line.
Science Layer (Model / Salabim)
PotentialLinearRegression, AllocationClueLike, DemandPreComputedValues
→ only knows math, geometry and time
Infrastructure Layer (ModelExecutor)
LUCCRasterExecutor, LUCCVectorExecutor, LUCCBenchmarkExecutor
→ only knows URIs, MinIO, column_map, parameters
| name | Substrate | Input → Output | Description |
|---|---|---|---|
lucc_raster |
RasterBackend / NumPy | Shapefile → GeoTIFF | Production raster simulation |
lucc_vector |
GeoDataFrame | Shapefile → GeoPackage | Production vector simulation |
lucc_benchmark |
Both | Shapefile → MD + PNG | Vector vs Raster vs TerraME comparison |
The LUCCBenchmarkExecutor is a meta-executor that runs vector and raster substrates in a single pass and compares both against a TerraME/LUCCME reference result. It generates a Markdown report and scatter plots — the primary tool for validating numerical equivalence before publishing results.
python -m dissluc.infra.executors.lucc_benchmark_executor run \
--input examples/data/input/csAC.zip \
--output ./benchmark/ \
--param demand_csv=examples/data/input/examples_demand_lab1.csv \
--param terrame_reference=benchmark/data/LUCCME_Lab1_2014.zip \
--param n_steps=6 \
--param tolerance=0.01Output:
benchmark/
report.md ← runtime comparison + accuracy metrics (match %, MAE, RMSE) per substrate and band
scatter.png ← scatter plots: Vector vs Raster vs TerraME for each land-use band
# my_lucc_executor.py
from dissmodel.executor import ExperimentRecord, ModelExecutor
from dissmodel.executor.cli import run_cli
from dissmodel.io import load_dataset, save_dataset
class MyLUCCExecutor(ModelExecutor):
name = "my_lucc"
def load(self, record: ExperimentRecord):
gdf, checksum = load_dataset(record.source.uri)
record.source.checksum = checksum
if record.column_map:
gdf = gdf.rename(columns={v: k for k, v in record.column_map.items()})
return gdf
def run(self, record: ExperimentRecord):
from dissmodel.core import Environment
from dissluc import DemandPreComputedValues, load_demand_csv
from dissluc.vector.potential.linear import PotentialLinearRegression
from dissluc.vector.allocation.clue import AllocationClueLike
params = record.parameters
gdf = self.load(record)
env = Environment(end_time=params.get("n_steps", 7) - 1)
demand = DemandPreComputedValues(...)
potential = PotentialLinearRegression(gdf=gdf, ...)
AllocationClueLike(gdf=gdf, ...)
env.run()
return gdf
def save(self, result, record: ExperimentRecord) -> ExperimentRecord:
uri = record.output_path or "output.gpkg"
checksum = save_dataset(result, uri)
record.output_path = uri
record.output_sha256 = checksum
record.status = "completed"
return record
if __name__ == "__main__":
run_cli(MyLUCCExecutor)Parameters and regression coefficients are stored in a TOML file, separate from code. In the platform, this lives in dissmodel-configs and is version-controlled by the LambdaGeo group.
# examples/model.toml
[model.parameters]
resolution = 5000.0
n_steps = 7
demand_csv = "data/examples_demand_lab1.csv"
land_use_types = ["f", "d", "outros"]
land_use_no_data = "outros"
complementar_lu = "f"
cell_area = 25.0
[model.driver_columns]
cols = ["assentamen", "uc_us", "uc_pi", "ti", "dist_riobr", "fertilidad", "rodovias"]
[model.static]
f = -1
d = -1
outros = 1
[[model.potential]]
lu = "f"
const = 0.7392
[model.potential.betas]
assentamen = -0.2193
uc_us = 0.1754
uc_pi = 0.09708
ti = 0.1207
dist_riobr = 0.0000002388
fertilidad = -0.1313
[[model.potential]]
lu = "d"
const = 0.267
[model.potential.betas]
rodovias = -0.0000009922
assentamen = 0.2294
uc_us = -0.09867
dist_riobr = -0.0000003216
fertilidad = 0.1281
[[model.potential]]
lu = "outros"
const = 0.0
[[model.allocation]]
lu = "f"
static = -1
min_value = 0
max_value = 1
min_change = 0
max_change = 1
[[model.allocation]]
lu = "d"
static = -1
min_value = 0
max_value = 1
min_change = 0
max_change = 1
[[model.allocation]]
lu = "outros"
static = 1
min_value = 0
max_value = 1
min_change = 0
max_change = 1# Via pip
pip install disslucc-continuous
# From source
git clone https://github.com/LambdaGeo/DisSLUCC.git
cd DisSLUCC
pip install -e .Dependencies: dissmodel, geopandas, shapely, pandas, numpy, rasterio, matplotlib
DisSLUCC-Continuous/
├── src/dissluc/
│ ├── __init__.py # Main facade (exports models and schemas)
│ ├── components/ # Science Layer (Models)
│ │ ├── demand/
│ │ ├── potential/
│ │ │ ├── raster/
│ │ │ └── vector/
│ │ └── allocation/
│ │ ├── raster/
│ │ └── vector/
│ ├── infra/ # Infrastructure Layer (Executors)
│ │ └── executors/
│ │ ├── clue_like_raster_executor.py
│ │ ├── clue_like_vector_executor.py
│ │ └── lucc_benchmark_executor.py
│ └── common/ # Common Layer (Schemas and Protocols)
│ ├── schemas.py # RegressionSpec, AllocationSpec
│ └── protocols.py # Component interfaces
├── examples/
│ ├── lab1_raster.py
│ ├── lab1_vector.py
│ └── ...
├── benchmark/
└── ...
- Modularity — Demand, Potential, and Allocation are interchangeable components.
- Transparency — Regression coefficients and allocation rules are explicit in TOML, version-controlled.
- Reproducibility — Each experiment records model commit, input checksum, and resolved spec via
ExperimentRecord. - Two substrates — Same algorithms available for vector (GeoDataFrame) and raster (RasterBackend/NumPy).
- Executor pattern — Science layer never knows about files or cloud; infrastructure layer never calculates spatial equations.
- Benchmark-first validation —
lucc_benchmarkvalidates numerical equivalence between substrates and against TerraME/LUCCME reference results before any production use.
- LUCCME: Carneiro et al. (2013). Environmental Modelling & Software, 46, 104–117. http://luccme.ccst.inpe.br
- TerraME: http://www.terrame.org
- Demand–Potential–Allocation framework: Verburg et al. (2004, 2006)
- Validation metric: Multi-resolution similarity (Costanza, 1989)
⚠️ Disclaimer: DisSLUCC is not an official fork or extension of LUCCME/TerraME. It is an independent Python implementation that preserves the original philosophy and algorithms, adapted to the DissModel architecture.
- Fork the repository and create a feature branch
- Implement changes and add tests
- Submit a Pull Request with a clear description
To register a new model in the platform, open a PR in dissmodel-configs with a TOML spec pointing to your package.
Distributed under the GPL-3.0 License. Developed by the LambdaGeo research group.
Built with ❤️ for the open-source environmental modeling community. 🌱🔬