2

I am using an available code on Google Earth Engine that takes wildfire polygons that have a Year and UniqueFireID in the attributes and created fire severity rasters ('dnbr', 'dnbr_w_offset','rbr', 'rbr_w_offset','rdnbr', 'rdnbr_w_offset')

The code can be found here https://code.earthengine.google.com/c76157be827be2f24570df50cca427e9

I've been running most of the polygons through with no problems but some large batches come up with:

Error: Collection.first: Error in map(ID=00000000000000000032): Image.constant: Parameter 'value' is required.

and I have also encountered another:

Error: Collection.first: Error in map(ID=0000000000000000000b): Image.select: Pattern 'preNBR' did not match any bands.

I'm assuming the second Error is that it can't find a good enough image for preNBR and then can't make the rest of the sets because preNBR is the starting point but I have no idea how to troubleshoot the first error.

I have only made one small change to the original code in that I am only calling the code to create the 'rdnbr_w_offset' instead of 'dnbr', 'dnbr_w_offset','rbr', 'rbr_w_offset','rdnbr', 'rdnbr_w_offset'

I am pretty new to Earth Engine and have minimal coding/scripting experience with R and Python.

// Script to develop and export 6 fire severity metrics (see list below) for each of 18 fires across the western US. 
//    Polygon-based fire perimeters were created by the Monitoring Trends in Burn Severity (MTBS) program (www.mtbs.gov). 
//    Script by Morgan Voss and Than Robinson - University of Montana
//    with revisions by Lisa Holsinger - U.S. Forest Service Rocky Mountain Research Station
//    May 2018 
//    For updates or questions on this code, please can contact:  
//        Lisa Holsinger, [email protected]
//        Sean Parks, [email protected]
//
// Fire Severity metrics created include:
//    dNBR:        delta normalized burn ratio
//    RdNBR:       relativezed delta normalized burn ratio
//    RBR:         relativized burn ratio
//    dNBRoffset:  dNBR with an offset to account for inter-annual differences in phenology between pre- and post-fire imagery.
//    RdNBRoffset: RdNBR with offset (as above)
//    RBRoffset:   RBR with offset (as above)

////////////////////// IMPORTANT - PLEASE READ BELOW ////////////////////////////////
// 1) When 'Run' Button is hit, it may take a few minutes to populate tasks 
//    and the browser may become unresponsive. In this case, the browser 
//    will bring up an option to 'Wait' while list of tasks are completed, 
//    which should be confirmed.
//
// 2) Create a folder called 'fires' in Google Drive before running exports,
//    otherwise, an error 'More than one folder with specified name [fires] found'
//    may occur.
/////////////////////////////////////////////////////////////////////////////////////


//--------------------       INPUTS       ------------------------------//
// import shapefile with fire polygons as a feature collection - these must have the following standard attributes  
//    as distributed by MTBS:  Fire_ID and Year
//    Note, we use Fire_ID as unique identifier rather than 'Fire_Name' attribute which has duplicate names for different fires
var fires = ee.FeatureCollection("users/mtd25/fires/1996");
//var fires_all = ee.FeatureCollection("users/mtd25/fires/SW_Fires_lessthan1000acres_1984_2019");
//print(fires)
//var fires = fires_all.filter(ee.Filter.eq('Year', 1986));
//print(fires)
//Map.addLayer(fires, )

// specify fire severity metrics to create
var bandList = ['rdnbr_w_offset'];
//var bandList = ['dnbr', 'dnbr_w_offset','rbr', 'rbr_w_offset','rdnbr', 'rdnbr_w_offset'];
// Enter beginning and end days for imagery season as julian dates
var startday = 91;
var endday   = 181;

//  visualize fire perimeters
Map.setCenter(-115,41.5, 5);
Map.addLayer(fires, {color: 'Red'}, "Fire perimeters");

//--------------------    END OF INPUTS   ----------------------------//


//--------------------     PROCESSING     ----------------------------//
//-------- Initialize variables for fire perimeters  -----------------//
// create two lists: one with fire names and the other with fire IDs 
var fireID    = ee.List(fires.aggregate_array('Fire_ID')).getInfo();
print(fireID)
var nFires = fireID.length;

//------------------- Image Processing for Fires Begins Here -------------//
// Landsat 5, 7, and 8 Surface Reflectance Tier 1 collections
var ls8SR = ee.ImageCollection('LANDSAT/LC08/C01/T1_SR'),
    ls7SR = ee.ImageCollection('LANDSAT/LE07/C01/T1_SR'),
    ls5SR = ee.ImageCollection('LANDSAT/LT05/C01/T1_SR'),
    ls4SR = ee.ImageCollection('LANDSAT/LT04/C01/T1_SR');

/////////////////////////////////
// FUNCTIONS TO CREATE NBR
/////////////////////////////////

// Returns vegetation indices for LS8
var ls8_Indices = function(lsImage){
  var nbr = lsImage.normalizedDifference(['B5', 'B7']).toFloat();
  var qa = lsImage.select(['pixel_qa']);
  return nbr.addBands([qa])
          .select([0,1], ['nbr', 'pixel_qa'])
          .copyProperties(lsImage, ['system:time_start']);
  };
  
// Returns vegetation indices for LS4, LS5 and LS7
var ls4_7_Indices = function(lsImage){
  var nbr = lsImage.normalizedDifference(['B4', 'B7']).toFloat();
  var qa = lsImage.select(['pixel_qa']);
  return nbr.addBands([qa])
          .select([0,1], ['nbr', 'pixel_qa'])
          .copyProperties(lsImage, ['system:time_start']);
  };

// Mask Landsat surface reflectance images
// Creates a mask for clear pixels 
var lsCfmask = function(lsImg){
  var quality =lsImg.select(['pixel_qa']);
  var clear = quality.bitwiseAnd(8).eq(0) // cloud shadow
                .and(quality.bitwiseAnd(32).eq(0) // cloud
                .and(quality.bitwiseAnd(4).eq(0) // water
                .and(quality.bitwiseAnd(16).eq(0)))); // snow
  return lsImg.updateMask(clear).select([0])                                    
            .copyProperties(lsImg, ['system:time_start']);
};

// Map functions across Landsat Collections
var ls8 = ls8SR.map(ls8_Indices)
                .map(lsCfmask);
var ls7 = ls7SR.map(ls4_7_Indices)
                .map(lsCfmask); 
var ls5 = ls5SR.map(ls4_7_Indices)
                .map(lsCfmask); 
var ls4 = ls4SR.map(ls4_7_Indices)
                .map(lsCfmask); 
                
// Merge Landsat Collections
var lsCol = ee.ImageCollection(ls8.merge(ls7).merge(ls5).merge(ls4));

// ------------------ Create and Export Fire Severity Imagery for each fire -----------------//
var indices = ee.ImageCollection(fires.map(function(ft){
  // use 'Fire_ID' as unique identifier
  var fName = ft.get("Fire_ID");

  // select fire
  var fire = ft;
  var fireBounds = ft.geometry().bounds();
  
  // create pre- and post-fire NBR imagery
  var fireYear = ee.Date.parse('YYYY', fire.get('Year'));
  var preFireYear = fireYear.advance(-1, 'year');
  var postFireYear = fireYear.advance(1, 'year');
  var preFireIndices = lsCol.filterBounds(fireBounds)
                          .filterDate(preFireYear, fireYear)
                          .filter(ee.Filter.dayOfYear(startday, endday))
                          .mean()
                          .rename('preNBR');
 
  var postFireIndices = lsCol.filterBounds(fireBounds)
                          .filterDate(postFireYear, fireYear.advance(2, 'year'))
                          .filter(ee.Filter.dayOfYear(startday, endday))
                          .mean()
                          .rename('postNBR');
                          
  var fireIndices = preFireIndices.addBands(postFireIndices);
  
  // create fire severity indices    
  // calculate dNBR  
  var burnIndices = fireIndices.expression(
              "(b('preNBR') - b('postNBR')) * 1000")
              .rename('dnbr').toFloat().addBands(fireIndices);

  // calculate dNBR with Offset developed from 180-m ring outside the fire perimeter
  var ring   = fire.buffer(180).difference(fire);
  var burnIndices2 = ee.Image.constant(ee.Number(burnIndices.select('dnbr').reduceRegion({
      reducer: ee.Reducer.mean(),
      geometry: ring.geometry(),
      scale: 30,
      maxPixels: 1e9
    }).get('dnbr'))).rename('offset').toFloat().addBands(burnIndices); 

  var burnIndices3 = burnIndices2.expression(
            "b('dnbr') - b('offset')").
            rename('dnbr_w_offset').toFloat().addBands(burnIndices2);

  // calculate RBR  
  var burnIndices4 = burnIndices3.expression(
            "b('dnbr') / (b('preNBR') + 1.001)")
            .rename('rbr').toFloat().addBands(burnIndices3);
  
  // calculate RBR with offset
  var burnIndices5 = burnIndices4.expression(
            "b('dnbr_w_offset') / (b('preNBR') + 1.001)")
            .rename('rbr_w_offset').toFloat().addBands(burnIndices4);

  // calculate RdNBR
  var burnIndices6 = burnIndices5.expression(
    "(b('preNBR') < 0.001) ? 0.001" + 
      ": b('preNBR')")
      .sqrt().rename('preNBR2').toFloat().addBands(burnIndices5);

  var burnIndices7 = burnIndices6.expression(
    "(b('dnbr') / sqrt(b('preNBR2')))")
    .rename('rdnbr').toFloat().addBands(burnIndices6);

  // calculate RdNBR with offset
  var burnIndices8 = burnIndices7.expression(
            "b('dnbr_w_offset') / sqrt(b('preNBR2'))")
            .rename('rdnbr_w_offset').toFloat().addBands(burnIndices7);

  burnIndices8 = burnIndices8.select(bandList);
  return burnIndices8.set({
                        'fireID' : ft.get('Fire_ID'),
                        'fireName' : ft.get('Fire_Name'),
                        'fireYear' : ft.get('Year')
  }); 
}));

// // Export fire indices for each fire  
var nBands = bandList.length;

for (var j = 0; j < nFires; j++){
  var id   = fireID[j];
  var Name = id;
  var fireExport = ee.Image(indices.filterMetadata('fireID', 'equals', id).first());
  var fireBounds = ee.Feature(fires.filterMetadata('Fire_ID', 'equals', id).first()).geometry().bounds();

  for (var i = 0; i < nBands; i++) {
    var bandExport = bandList[i];  
    var exportImg = fireExport.select(bandExport);
    Export.image.toDrive({
      image: exportImg,
      description: Name + '_' + bandExport,
      fileNamePrefix: Name + '_' + bandExport,
      maxPixels: 1e13,
      scale: 30,
      crs: "EPSG:4326",
      folder: 'fires',      
      region: fireBounds
  }); 
}}

1 Answer 1

2

Image.constant: Parameter 'value' is required.

This error happens when it gets null (equivalent to an omitted parameter) instead of a proper value. In situations like this, that usually happens because there is no data, such as because you called .get('x') on a feature or dictionary that doesn't have a property/key named 'x'.

The obvious candidate is your

ee.Image.constant(ee.Number(....get('dnbr')))

To debug this problem, modify your map that constructs indices to return features whose properties are things like the list of band names in burnIndices and the properties of the dictionary returned by reduceRegion (instead of trying to compute the desired image), print the resulting collection, and see which bands you're getting. If you need more help, first reduce your script to a simpler form that still produces the error (even if it does not calculate anything scientifically meaningful).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.