Fire Risk & Fuel Assessment with Python
Wildfire fuel and risk products carry consequences that few other forestry deliverables do: a fuel-model raster feeds an incident-command spread simulation, a hazard surface drives where a district spends its thinning budget, and a burn-severity map underwrites post-fire salvage and reforestation decisions. When those products are wrong — a canopy bulk density inflated by unfiltered noise returns, a hazard model trained on leaking spatial folds, a severity index computed from mismatched acquisition dates — the error does not announce itself. It propagates quietly into a spread run that misplaces a containment line, or a treatment prescription that funds the wrong stand. This section builds the end-to-end Python pipeline that turns three raw data streams — airborne LiDAR, Sentinel/Landsat optical imagery, and gridded fire-weather — into fuel, risk, severity, and behavior products that a fire analyst, a fuels planner, or an auditor can actually defend.
The work spans four ordered stages, each of which owns a focused workflow guide with the runnable code. This page stays at the orchestration level: it establishes the spatial-integrity preconditions every fire product depends on, walks the pipeline top to bottom, and links down into each stage. The vertical structure that fuel models are built from comes out of the Canopy Height Modeling & Terrain Extraction workflows, and the coordinate and datum discipline that keeps every layer registered to the same ground lives in Ecological GIS Data Foundations in Python.
Spatial-integrity prerequisites for fire products
Every fire product is a stack of layers that must describe the same ground at the same resolution, and the failures that matter most are the ones that never raise an exception. Before any fuel metric or hazard model is computed, four preconditions have to hold, and each is cheap to enforce and expensive to skip:
The remainder of this page assumes these gates are enforced at the front door, exactly as the Ecological GIS Data Foundations in Python framework prescribes. A fire pipeline that skips them produces outputs that look plausible in a map viewer and fail under scrutiny.
Stage 1: Fuel mapping from LiDAR and canopy structure
Fuel assessment begins with the physical structure of the vegetation, and airborne LiDAR is the only widely available data source that resolves the vertical arrangement of that fuel. The canopy fuel metrics that spread and crown-fire models require — canopy bulk density (CBD), canopy base height (CBH), canopy cover, and stand canopy fuel load — are all derived from the vertical distribution of returns above a normalized ground surface. Those returns must first pass through the same cleaning and normalization that every structural product depends on: outlier removal and ground classification from LiDAR Point Cloud Preprocessing, and a height-above-ground normalization that a Canopy Height Model Creation step both produces and validates.
Once returns are normalized, the fuel-mapping stage bins them into vertical layers, converts each layer’s return density into a foliage biomass estimate through an allometric relationship, and reduces the vertical biomass profile to the scalar metrics a fuel model needs. The full derivation — including how a vertical bulk-density profile becomes a single CBD value and how CBH is read off the profile at a bulk-density threshold — is the subject of Fuel Load Mapping from LiDAR. This orchestration page only fixes the contract: Stage 1 emits a stack of canopy fuel rasters, co-registered to the analysis grid, that classify each cell into a standard fuel model (for example one of the Scott & Burgan 40) and attach the continuous canopy variables that crown-fire initiation depends on.
The output of this stage is the single most leverage-heavy artifact in the whole pipeline. Every downstream model — hazard, severity interpretation, and behavior — reads the fuel layer, so an error here is an error everywhere.
Stage 2: Wildfire risk modeling
Risk is not fuel. A dense, continuous canopy is a hazard, but risk combines that hazard with the likelihood of ignition and the exposure of values at stake, and it is expressed as a spatial surface that a planner can rank. The modeling stage assembles predictor layers — the fuel metrics from Stage 1, topographic derivatives (slope, aspect, elevation), fire-weather summaries, and proximity variables such as distance to roads or the wildland-urban interface — and relates them to a response, whether that is historical ignition points or observed burn probability.
In Python this is a supervised-learning problem built on scikit-learn: predictors are stacked into an aligned array, a classifier or regressor is trained with spatially aware cross-validation, and the fitted model is applied back across the raster grid to produce a continuous hazard or probability surface. The stacking, model selection, and — critically — the spatially blocked validation that keeps an over-optimistic model from shipping are developed in Wildfire Risk Modeling in Python. Because fire-weather is the ignition- and spread-timing driver rather than a static structural trait, that guide also covers reducing a weather time series to the indices a model can consume, with the concrete recipe in Computing the Fire Weather Index in Python.
The predictor-stacking discipline here is the same one the species-modeling side of the site relies on, so the alignment, resampling, and collinearity concerns carry over directly from the broader raster-covariate workflow.
Stage 3: Burn-severity mapping
After a fire, the pipeline turns from prediction to measurement. Burn severity quantifies how much the fire changed the vegetation and soil, and the workhorse index is the differenced Normalized Burn Ratio (dNBR), computed from the near-infrared and shortwave-infrared bands of a pre-fire and a post-fire optical scene. The Normalized Burn Ratio for a single scene is
and severity is the difference between the pre-fire and post-fire values, , optionally offset-corrected and relativized to RdNBR to control for pre-fire vegetation density.
The band mathematics is simple; the discipline is in the inputs. Both scenes must be surface-reflectance products, cloud- and shadow-masked, and co-registered to the pixel — the same alignment rigor a Vegetation Index Calculation in Python step demands, because dNBR is structurally an index difference over time. The full masking, offset-correction, and classification workflow is built in Burn Severity Mapping with Python, with the end-to-end Sentinel-2 recipe in Calculating dNBR from Sentinel-2 in Python. Severity maps close the loop: they validate the fuel and hazard layers against what actually burned, and they seed the next planning cycle.
Stage 4: Fire behavior and rate-of-spread modeling
The final stage answers the operational question: given these fuels, this terrain, and this weather, how fast and how intensely would a fire move? The canonical surface-fire model is Rothermel’s, which combines a fuel model’s load, surface-area-to-volume ratio, and bed depth with fuel moisture, wind, and slope to predict a steady-state rate of spread. The head-fire rate of spread takes the form
where is the reaction intensity, the propagating flux ratio, and the wind and slope factors, the bulk density of the fuel bed, the effective heating number, and the heat of pre-ignition.
Driving this across a landscape means evaluating the model per cell against the fuel-model raster from Stage 1, slope and aspect from the terrain surface, and the wind and moisture fields from the weather stack, then optionally propagating a front. The full parameterization, the crown-fire transition logic that reads CBH and CBD from Stage 1, and the numerical implementation are developed in Fire Behavior and Rate-of-Spread Modeling, with the core Rothermel implementation in Modeling Rate of Spread with Rothermel in Python. This stage is where the whole pipeline pays off: it converts static fuel and risk layers into the dynamic behavior estimates that drive suppression tactics and evacuation timing.
Python library ecosystem
The fire pipeline rests on the same GDAL/PROJ/GEOS-backed stack the rest of the site uses, extended with the point-cloud and machine-learning tools the fuel and risk stages need. Pin both the Python wheels and their native binaries — the heavy lifting in point-cloud filtering and raster warping lives in the C layer.
| Package | Role in the fire pipeline | Version note |
|---|---|---|
PDAL |
Point-cloud pipelines: filtering, ground classification, height normalization | 2.6+; drives the Stage 1 return conditioning |
laspy |
Reading LAS/LAZ into NumPy for custom vertical-profile binning | 2.5+ with the lazrs or laszip backend |
rasterio |
Raster I/O, windowed reads, warping, masking for fuel and severity grids | 1.3+ for stable WarpedVRT |
numpy |
Array math for vertical profiles, band indices, and per-cell model evaluation | 1.24+ |
xarray / rioxarray |
Labelled, CRS-aware stacks for multi-band optical and multi-temporal weather | pair rioxarray with rasterio |
geopandas |
Ignition points, fire perimeters, WUI boundaries, zonal summaries | 0.14+ with pyogrio |
scikit-learn |
Hazard and burn-probability models with spatial cross-validation | 1.3+ |
A reproducible install pins the binaries alongside the wheels:
# conda-forge resolves GDAL/PROJ/GEOS and PDAL as one native stack
conda create -n fire-gis -c conda-forge \
python=3.11 pdal python-pdal laspy rasterio=1.3 \
numpy xarray rioxarray geopandas scikit-learn
conda activate fire-gis
Production pipeline principles
Fire products are decision instruments, so the engineering standard is higher than for exploratory analysis. Four principles keep the pipeline defensible.
- Reproducibility through pinning. Lock the versions of
PDAL,rasterio,scikit-learn, and the GDAL/PROJ binaries with acondalock file oruv. A silent change in a point-cloud filter default or a scikit-learn estimator can shift a fuel raster or a hazard surface between runs without any code change. - CRS and grid enforcement at every boundary. Reject layers with a null CRS at ingestion, assert the analysis CRS after every warp, and confirm one affine transform across the whole stack before any per-cell model evaluation. A one-cell misregistration between the fuel raster and the wind field silently biases every rate-of-spread value.
- Honest validation. Fire hazard and burn-probability models are trained on spatially autocorrelated data, so random k-fold cross-validation reports scores that will not survive deployment. Use spatially blocked validation and report the honest metric, not the flattering one.
- Provenance for every product. Record source scene IDs and acquisition dates, LiDAR survey and normalization parameters, the fuel-model lookup table used, model hyperparameters, and the resolved library and binary versions. When a fuel or severity map is questioned after an incident, provenance is the difference between a defensible answer and an irreproducible one.
Frequently Asked Questions
Do I need LiDAR to produce fuel maps, or can optical imagery alone work?
Optical imagery alone gives you canopy cover and greenness, but it cannot resolve the vertical structure — canopy base height and canopy bulk density — that crown-fire initiation and spread models require. LiDAR is what makes those vertical fuel metrics measurable rather than assumed. Where LiDAR is unavailable, fuel models are usually assigned from vegetation type and cover with far larger uncertainty, which is why the Fuel Load Mapping from LiDAR workflow treats a normalized point cloud as the primary input.
Why is spatial cross-validation emphasized for wildfire risk models?
Ignition points and burned areas are strongly spatially autocorrelated: nearby cells share fuels, weather, and terrain. Random k-fold splitting places training and test cells next to each other, so the model is effectively tested on data it has already seen, and the reported skill is inflated. Spatially blocked cross-validation holds out contiguous regions, giving a metric that reflects how the model performs on genuinely new ground. The mechanics are covered in Wildfire Risk Modeling in Python.
What is the difference between dNBR and RdNBR?
dNBR is the raw difference between pre-fire and post-fire Normalized Burn Ratio and is sensitive to how much vegetation existed before the fire — a sparse stand and a dense stand that both burn completely produce different dNBR values. RdNBR relativizes the change by the pre-fire NBR, which makes severity classes more comparable across vegetation types. Both are built in Burn Severity Mapping with Python.
Should this page contain the full implementation code for each stage?
No. This page orchestrates the fire pipeline and defines what each stage’s product must look like; the runnable implementations live in the focused workflow guides linked from each stage — fuel mapping, risk modeling, burn severity, and fire behavior — so the code is maintained in exactly one place and stays consistent across the site.
How do fuel metrics from the canopy workflows feed the fire models?
Canopy base height and canopy bulk density derived in Stage 1 are direct inputs to crown-fire transition logic in Stage 4, and canopy cover feeds both the fuel-model assignment and the risk predictors in Stage 2. Those metrics are only trustworthy if the underlying returns were cleaned and normalized first, which is why Stage 1 depends on LiDAR Point Cloud Preprocessing and Canopy Height Model Creation.
Related
- Fuel Load Mapping from LiDAR — derive canopy fuel metrics and assign standard fuel models
- Wildfire Risk Modeling in Python — combine hazard, ignition, and weather into a risk surface
- Burn Severity Mapping with Python — measure fire effects with dNBR and RdNBR
- Fire Behavior and Rate-of-Spread Modeling — drive Rothermel spread across the landscape
- Canopy Height Modeling & Terrain Extraction — the structural foundation fuel metrics are built on