Lab 30 - Wildfire Analysis

Objective: Map burn severity using the Normalized Burn Ratio (NBR) and delta NBR (dNBR) from pre- and post-fire Landsat imagery.

What You'll Learn

  • Calculate NBR from Landsat NIR and SWIR bands
  • Compute dNBR (delta NBR) from pre- and post-fire imagery
  • Classify burn severity using USGS thresholds
  • Summarize burned area by severity class within fire perimeters
  • Export burn severity maps and statistics

Why This Matters

Burn severity mapping supports wildfire management:

  • Recovery planning: High-severity areas need different restoration strategies
  • Erosion risk: Burned areas are vulnerable to debris flows and floods
  • Carbon accounting: Fires release stored carbon to the atmosphere
  • Insurance/damage assessment: Quantify impacts for recovery funding

Before You Start

  • Prerequisites: Understand spectral indices and image differencing.
  • Estimated time: 75 minutes
  • Materials: Earth Engine account and a known fire event with perimeter data.

Key Terms

NBR (Normalized Burn Ratio)
A spectral index using NIR and SWIR bands that is sensitive to vegetation moisture and burn severity: (NIR - SWIR2) / (NIR + SWIR2)
dNBR (delta NBR)
The difference between pre-fire and post-fire NBR. Positive values indicate burn severity.
Burn Severity
The degree to which fire has altered an ecosystem, from unburned to high severity.
MTBS
Monitoring Trends in Burn Severity - a USGS/USFS program providing burn severity data for the US.

USGS Burn Severity Thresholds

Class dNBR Range Description
0 < 0.1 Unburned/Low regrowth
1 0.1 - 0.27 Low severity
2 0.27 - 0.44 Moderate-low severity
3 0.44 - 0.66 Moderate-high severity
4 > 0.66 High severity

Step 1: Define AOI and Date Ranges

Set up your study area and pre/post fire dates:

// AOI and dates (adjust for your fire)
var aoi = ee.Geometry.Rectangle([-118.2, 34.1, -117.5, 34.4]);
Map.centerObject(aoi, 10);

// Pre-fire: before ignition
var preStart = '2020-07-01';
var preEnd   = '2020-08-31';

// Post-fire: after containment, before vegetation recovery
var postStart = '2020-10-01';
var postEnd   = '2020-11-30';

Step 2: Calculate NBR

Create a function to mask clouds and calculate NBR:

// Mask clouds and shadows using QA_PIXEL
function maskL2(img) {
    var qa = img.select('QA_PIXEL');
    var cloud = qa.bitwiseAnd(1 << 3).neq(0);
    var shadow = qa.bitwiseAnd(1 << 4).neq(0);
    var mask = cloud.or(shadow).not();
    return img.updateMask(mask);
}

// Calculate NBR from Landsat
function prep(img){
    var sr = maskL2(img);
    var nir = sr.select('SR_B5').multiply(0.0000275).add(-0.2);
    var sw2 = sr.select('SR_B7').multiply(0.0000275).add(-0.2);
    var nbr = nir.subtract(sw2).divide(nir.add(sw2)).rename('NBR');
    return nbr.copyProperties(img, img.propertyNames());
}

// Load Landsat 8 and create pre/post NBR composites
var L = ee.ImageCollection('LANDSAT/LC08/C02/T1_L2').filterBounds(aoi);
var pre  = L.filterDate(preStart, preEnd).map(prep).median().clip(aoi);
var post = L.filterDate(postStart, postEnd).map(prep).median().clip(aoi);

Map.addLayer(pre, {min:-1, max:1, palette:['#1a9850','#ffffbf','#d73027']}, 'NBR pre');
Map.addLayer(post,{min:-1, max:1, palette:['#1a9850','#ffffbf','#d73027']}, 'NBR post');

Step 3: Calculate dNBR and Classify Severity

// Calculate delta NBR
var dnbr = pre.subtract(post).rename('dNBR');
Map.addLayer(dnbr, {min:-0.2, max:1, palette:['#2c7bb6','#ffff8c','#d7191c']}, 'dNBR');

// Classify burn severity using USGS thresholds
var sev = dnbr.expression(
  'b(0) <= 0.1 ? 0 : ' +
  'b(0) <= 0.27 ? 1 : ' +
  'b(0) <= 0.44 ? 2 : ' +
  'b(0) <= 0.66 ? 3 : 4'
).rename('severity');

Map.addLayer(sev, {
    min: 0, max: 4, 
    palette: ['#1a9641','#ffffbf','#fdae61','#d7191c','#a50026']
}, 'Severity classes');

Step 4: Summarize Area by Severity Class

// Fire perimeter (replace with actual perimeter if available)
var perimeter = aoi; // Use actual fire perimeter FeatureCollection

// Calculate area (hectares) by severity class
var areaImg = ee.Image.pixelArea().divide(10000).addBands(sev);
var byClass = areaImg.reduceRegion({
  reducer: ee.Reducer.sum().group({groupField: 1, groupName: 'severity'}),
  geometry: perimeter, 
  scale: 30, 
  maxPixels: 1e9
});

print('Area (ha) by severity class', byClass);

Step 5: Export Results

// Convert grouped dictionary to FeatureCollection for CSV export
var groups = ee.List(byClass.get('groups'));
var table = ee.FeatureCollection(groups.map(function(g){
    g = ee.Dictionary(g);
    return ee.Feature(null, {
        severity: g.get('severity'),
        area_ha: g.get('sum')
    });
}));

// Export table as CSV
Export.table.toDrive({
    collection: table,
    description: 'burn_severity_area_by_class',
    fileFormat: 'CSV'
});

// Export dNBR as GeoTIFF
Export.image.toDrive({
    image: dnbr,
    description: 'dnbr_geotiff',
    region: aoi,
    scale: 30,
    maxPixels: 1e13
});

Check Your Understanding

  1. Why do we use SWIR bands in the NBR calculation?
  2. What would a negative dNBR value indicate?
  3. Why is timing of post-fire imagery important?
  4. How might topography affect burn severity patterns?

Troubleshooting

Problem: Pre-fire NBR shows burn scars

Solution: Check your pre-fire dates - they may overlap with an earlier fire. Adjust date range.

Problem: High dNBR values appear in water bodies

Solution: Add a water mask using the JRC Global Surface Water dataset.

Problem: Clouds in post-fire composite

Solution: Extend the date range or use a different cloud masking approach.

Pro Tips

  • Use MTBS data: Compare your results to official MTBS burn severity maps
  • Consider RdNBR: Relativized dNBR normalizes by pre-fire NBR for more consistent results
  • Multiple fires: Use fire perimeter datasets (NIFC, CalFire) for specific events
  • Time series: Track post-fire vegetation recovery over multiple years

?? Lab Submission

Subject: Lab 30 - Wildfire Analysis - [Your Name]

Submit:

  • Map layers: NBR pre/post, dNBR, and severity classes
  • Table: area (hectares) by severity class within fire perimeter
  • Short discussion: Note any unburned/low-severity islands and likely drivers
  • EE script URL and exported CSV