Learning Objectives¶
By the end of this chapter you will be able to:
- Explain why
dissluccimplements both continuous and discrete allocation in one package, on one raster substrate - Choose between continuous and discrete allocation for a given research question
- Describe the Demand/Potential/Allocation loop every LUCC model in the ecosystem shares
- Know how each allocation style validates itself against its TerraME/LUCCME predecessor, and run it yourself via script or CLI
# Standard imports — add chapter-specific imports below
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
Every model since Chapter 23 has been a paradigm demonstration — Predator-Prey, Game of Life, a handful of agents. This chapter is the first full domain application: land use and cover change, the process that originally motivated LUCCME at INPE/CCST, and the process DisSModel's own migration story (Chapter 32) keeps returning to as its central example.
What disslucc Is¶
disslucc implements spatially explicit land-use and cover change modeling on top of dissmodel, raster-only, covering two allocation philosophies LUCCME itself historically supported — not as two packages, but as two components within one:
| Approach | Style | Unit of allocation | Potential | Allocation |
|---|---|---|---|---|
| Continuous | LUCCME-like | area/percentage per cell | PotentialLinearRegression |
AllocationClueLike |
| Discrete | CLUE-S-like | one land use per cell | PotentialDLogisticRegression |
AllocationDClueSLike |
Both import from the same disslucc package and depend on dissmodel as an ordinary package dependency, following the same additive philosophy Chapter 33 describes for every satellite package in the ecosystem — neither modifies the core. There are two entry points into the same underlying components: a script-first path (build the models directly in Python — no TOML, no provenance tracking, the fastest way to experiment) and an Executor path (disslucc.executors, wraps the same math in ModelExecutor/ExperimentRecord for automatic provenance, and is what gets registered in dissmodel-configs to run on dissmodel-platform). Both produce identical results; which one you reach for depends on whether you need the provenance record.
Theory: Demand, Potential, Allocation¶
Every LUCC model in this chapter, continuous or discrete, runs the identical three-part loop each time step — the same structure LUCCME itself established:
- Demand ("how much?") — the area changing class this step. It can come from a historical trend, a constructed scenario, an economic model, or simply a precomputed table read from a CSV.
- Potential ("where?") — a suitability map built from driving-factor layers: distance to roads, distance to ports, protected-area status, soil fertility. This is a regression problem — predicting suitability from spatial covariates — with those covariates typically prepared upstream by
disscube's derivation pipeline (Chapter 30). - Allocation — spatially distributing the demanded change according to the potential map, by rank ordering, competition, or another strategy.
Is a land-change model a cellular automaton? By Chapter 24's own six-element definition — grid, neighborhood, finite states, transition rules, initial state, discrete time — yes, formally. The difference from dissmodel-ca's models is one of emphasis and disciplinary origin (economic geography, not physics), not underlying mechanism.
Continuous Allocation¶
PotentialLinearRegression + AllocationClueLike answer "how much does this cell's land use change" — the right choice whenever a cell can legitimately hold more than one land use at once (a partially-deforested cell, a partially-urbanized one). Potential is one linear regression per land-use type, each with its own intercept and driving-factor coefficients (RegressionSpec); allocation distributes demand across cells according to that potential map, subject to per-class minimum/maximum bounds (AllocationSpec).
Script-first — no ModelExecutor, no TOML, the fastest way to run this:
from dissmodel.core import Environment
from disslucc import DemandInline, PotentialLinearRegression, AllocationClueLike
from disslucc.schemas import RegressionSpec, AllocationSpec
env = Environment(end_time=7)
demand = DemandInline(values=demand_matrix, land_use_types=LAND_USE_TYPES)
potential = PotentialLinearRegression(
backend=backend,
demand=demand,
land_use_types=LAND_USE_TYPES,
potential_data=[[
RegressionSpec(const=-0.2, betas={"slope": 0.4}), # forest
RegressionSpec(const=0.4, betas={"dist_road": -0.1, "slope": -0.5}), # agriculture
RegressionSpec(const=0.3, betas={"dist_road": -0.6, "slope": -0.3}), # urban
]],
)
allocation = AllocationClueLike(
backend=backend, demand=demand, potential=potential,
land_use_types=LAND_USE_TYPES,
static={"forest": 0, "agriculture": -1, "urban": -1},
complementar_lu="forest", cell_area=1.0, max_difference=5.0,
allocation_data=[AllocationSpec(static=0), AllocationSpec(static=-1), AllocationSpec(static=-1)],
)
env.run()
Validated against real TerraME/LUCCME output, not synthetic data: Lab1 (Amazon deforestation, csAC region, 6,574 cells, 6 steps) reproduces the reference at MAE = 0.0036 (RMSE 0.0062, max error 0.027), well within the 0.01 tolerance the original benchmark used to call something "equivalent to TerraME". The Pontius & Millones decomposition attributes 90% of that residual to quantity disagreement and 10% to allocation disagreement — the spatial pattern matches almost perfectly; the small gap is in total allocated quantity, not position. The residual itself traces to the original LuccME script's own convergence tolerance (maxDifference = 1643 against a 2014 demand of 21,607 — a 7.6% band the reference itself doesn't close). Runs at 44.0 ms/step.
Discrete Allocation¶
PotentialDLogisticRegression + AllocationDClueSLike answer a different question: "which single land use dominates this cell" — a CLUE-S-style allocation, right whenever ground-truth is itself categorical (a classified land-cover map, not a fractional-cover raster). Potential comes from a logistic regression predicting which class a cell most likely belongs to, not how much of a fractional quantity it holds (LogisticRegressionSpec, adding an elasticity term over the continuous case); allocation runs through a competition-based CLUE-S loop governed by a transition matrix ([region][from][to], which pairs are even reachable).
The Executor path is what registers with dissmodel-configs/dissmodel-platform, and — as of dissmodel 0.6.4 — also runs locally via its CLI, configuration in a TOML file rather than inline Python:
[model]
land_use_types = ["f", "d", "o"]
transition_matrix = [[[1, 1, 0], [0, 1, 0], [0, 0, 1]]] # irreversible deforestation
[model.parameters]
n_steps = 6
[[model.potential_data]]
lu = "f"
const = -2.34187976925989
elasticity = 0.0
[model.potential_data.betas]
dist_br = 3.10319957497883
python -m disslucc.executors.discrete run \
--toml examples/dissmodel-configs/lucc_discrete.toml \
--input data/input/cs_moju.zip \
--param demand_csv=data/input/demand_moju.csv \
--output outputs/result.tif
Validated against real TerraME/LUCCME output: Lab15 (deforestation, Moju region, 5,914 cells, 6 steps) reaches exact cell-for-cell agreement — zero quantity disagreement, zero allocation disagreement (Pontius & Millones decomposition), 100% accuracy, F1 = 1.0. Runs at 10.3 ms/step.
Discriminance caveat, inherited from the original benchmark and still true here: the Lab15 scenario is nearly non-discriminative — a trivial static ranking by (prob_d - prob_f), with no CLUE-S, no iteration, no time steps, already reproduces the same cell-by-cell output. So this result confirms the logistic regression coefficients were transcribed correctly; it does not by itself prove the CLUE-S allocation algorithm (iteration/convergence via factor_iteration) is faithful in a scenario where competition between classes actually matters. A shipped discriminance test makes this explicit rather than letting the strong headline number stand unqualified; a dynamic-covariate scenario that would actually exercise the competition logic is planned.
Choosing Between Continuous and Discrete¶
Both components implement the identical Demand/Potential/Allocation loop with different algorithms at each step — the decision between them is about your data, not architecture:
| Continuous | Discrete | |
|---|---|---|
| Potential | linear regression | logistic regression |
| Allocation | CLUE-like, per-class bounds | competition-based CLUE-S |
| Validation | MAE/RMSE tolerance vs. reference | exact cell-level parity vs. reference |
| Speed (validated benchmark) | 44.0 ms/step | 10.3 ms/step |
The fastest way to decide: look at your calibration and validation data first. If it's expressed as a class label per cell, discrete allocation is what can be checked against it exactly. If it's expressed as an area or percentage per cell, continuous allocation is the only one that represents it without lossy discretization forced on it first.
Calibration, Validation, and Goodness-of-Fit¶
The MAE/RMSE/parity checks above are engineering validation — confirming a Python port matches a TerraME reference run. That's a different question from scientific validation: fitting a model to real-world observed data by splitting a timeline into a calibration period (used to fit parameters) and a held-out validation period, checked only after fitting.
A cell-by-cell comparison between a simulated map and an observed one is often too strict a bar even for scientific validation — two reasonable model runs can disagree pixel-for-pixel while still being "equally good" at the pattern level. A multiscale comparison — checking agreement in successively larger windows (3×3, then 5×5, then 9×9, and so on) — is the standard alternative: two maps might show weak agreement at the finest resolution but strong agreement once compared at a coarser one, which is real, usable information a strict pixel match would have discarded entirely.
Exercises¶
- Match the component to the question. For each research question, name which allocation style fits and why: (a) "how does the percentage of forest cover in each cell change over the next 20 years," (b) "which cells convert from forest to pasture by 2030."
- Why two different regressions?
PotentialLinearRegressionandPotentialDLogisticRegressionboth take driving-factor coefficients (betas) per land-use type. From the class names alone, explain why one needs a linear regression and the other a logistic one — what is each one actually trying to predict? - Tolerance vs. exact parity. Explain, in your own words, why a tolerance-based check makes sense for the continuous allocation's validation but not for the discrete one's.
- Multiscale comparison, by hand. Sketch, conceptually, how you'd compute a 3×3-window agreement score between two categorical land-use grids of the same shape — what would you compare within each window, and how would you turn that into a single agreement number for the whole grid?
# Your code here
Summary¶
Key concepts introduced¶
disslucc: one raster-only package implementing both continuous and discrete LUCC allocation, sharing the identical Demand/Potential/Allocation loop LUCCME originally established- Continuous: fractional, per-cell land-use change, validated by MAE/RMSE tolerance against a real TerraME/LUCCME reference (MAE 0.0036, 44.0 ms/step)
- Discrete: categorical, one-class-per-cell allocation, validated by exact cell-level parity — the strongest equivalence claim in the ecosystem, possible because the output is categorical (10.3 ms/step) — with a discriminance test making explicit that this validates coefficient transcription, not full allocation-algorithm fidelity
- Two entry points into the same components: script-first (fastest to experiment) and
ModelExecutor-based (automatic provenance, TOML registration, CLI) - Choosing between allocation styles by looking at your own calibration/validation data's type first, not by architectural preference
- Engineering validation (matching a TerraME reference) versus scientific validation (calibration/validation split against real-world data), and multiscale comparison as an alternative to an overly strict pixel-for-pixel match
Chapter 27 stays in domain-application territory but moves from land far inland to the coastline itself — a coupled flood and mangrove-migration model, run on both substrates and validated two different ways at once.
Further Reading¶
- Verburg, P. H. et al. (2002). "Modeling the spatial dynamics of regional land use: the CLUE-S model." Environmental Management, 30(3), 391-405
- Verburg, P. H. et al. (2006). "Downscaling of land use change scenarios to assess the dynamics of European landscapes." Agriculture, Ecosystems & Environment, 114(1), 39-56
- Costanza, R. (1989). "Model goodness of fit: a multiple resolution procedure." Ecological Modelling, 47(3-4), 199-215 — the multiscale comparison method this chapter's validation section draws on
- Pontius Jr., R. G. & Millones, M. (2011). "Death to Kappa: birth of quantity disagreement and allocation disagreement for accuracy assessment." International Journal of Remote Sensing, 32(15), 4407-4429 — the decomposition
dissluccuses in place of Cohen's kappa - LuccME documentation (INPE): http://www.dpi.inpe.br/luccme/
dissluccon GitHub: https://github.com/DisSModel/disslucc