2

I have modified code from Google Earth Engine - counts days of the longest dry period in a time period to look at the longest consecutive number of days without rain in an image collection.

I am now trying to modify this analysis. I have a set of prescribed fire records (FeatureCollection) and I am trying to calculate the number of consecutive days without rain prior to the day of the fire for each record.

Below is my current working script, which is set to just calculate the longest consecutive number days without rain in the entire time series, relative to the start and end of the image collection.

// REFERENCE
// Center the map to an area of interest (ex. Tall Timbers)
Map.setCenter(-84.20875, 30.6565, 12)

// REFORMAT DATES FOR ALL POINTS IN THE SHAPEFILE
var BurnPermits = BurnPermits.map(function (feature) {
  return feature.set('system:time_start', ee.Date(feature.get('DATE')))
})
// FILTER TO 2020 FOR TESTING
var Permits2020 = BurnPermits.filterDate('2020-01-01','2020-12-30')

// PRINT 2020 PERMITS TO CONSOLE
print(Permits2020)

// FILTER GRIDMET DATA TO DESIRED SPATIAL AND TEMPORAL EXTENTS
var GRIDMET = GRIDMET.select('pr').filterBounds(TT).filterDate('2020-01-01','2020-12-30')

// THIS FUNCTION ADDS A BAND FOR COUNTING NO RAIN DAYS
var addBands = function(image) {
  return image.addBands(ee.Image.constant(0).uint8().rename('counter'));
};

// APPLY THE FUNCTION TO THE GRIDMET IMAGE COLLECTION
var GRIDMET = GRIDMET.map(addBands)
print(GRIDMET)

// SET A PRECIPITATION THRESHOLD (mm)
var PR_BIN = 1; 

function PrecipFreeInterval(img, list){
  // get previous image
  var prev = ee.Image(ee.List(list).get(-1));
  // find areas less than FIRE_BIN threshold (gt==0, lt==1)
  var PrecipFree = img.select('pr').lt(PR_BIN);
  // add previous day counter to today's counter
  var accum = prev.select('counter').add(PrecipFree).rename('counter');
  // create a result image for iteration
  // PrecipFree < thresh will equall the accumulation of counters
  // otherwise it will equal zero
  var out = img.select('pr').addBands(
        img.select('counter').where(PrecipFree.eq(1),accum)
      ).uint8();
  return ee.List(list).add(out);
}

// CREATE FIRST IMAGE FOR ITERATION
var first = ee.List([ee.Image(GRIDMET.first())]);

// APPLY DRY SPELL ITERATION FUNCTION
var LPFI = ee.ImageCollection.fromImages(
    GRIDMET.iterate(PrecipFreeInterval,first)
).max(); // GET THE MAX VALUE

// DISPLAY RESULTS
Map.addLayer(LPFI.select('counter').clip(TT), {},'Longest Precipitation Free Interval');

Functionally, I am trying to write a function that iterates over each feature in the collection, finds the start date of the feature, and then counts back until rain has been detected (in the GRIDMET product) and records the consecutive days without rain for that feature.

Would anyone be able to steer me in the right direction here? I know that the function has to iterate over features instead of images, I am just not sure the best way to accomplish this task.

Link to full script

1 Answer 1

4

Iterate() is almost never the right tool to reach for in Earth Engine. In this case you can get the number of days by converting the time series to an array and doing some simple array masking to mask off values after your date of interest and then finding the maximum array index with any precipitation.

// FILTER GRIDMET DATA TO DESIRED SPATIAL AND TEMPORAL EXTENTS
var collection = GRIDMET
    .filterBounds(TT)
    .filterDate('2020-01-01','2020-12-30')
    .select('pr')
    .map(function(img) {
      // Add a date band to each image.
      return img.addBands(img.metadata("system:time_start").rename("date"))
    })
var precipitation = collection.toArray()
var PR_BIN = 1; 

var getDryRunlength = function(f) {
  var target = f.get("system:time_start")
  
  // Get the time-series of precipitation and dates as an array and split into two.
  var pr = precipitation.reduceRegion(ee.Reducer.first(), f.geometry(), 1).get('array')
  var precip = ee.Array(pr).slice(1, 0, 1).gte(PR_BIN).project([0])
  var dates = ee.Array(pr).slice(1, 1, 2).project([0])
  
  // Mask off values after the feature's date
  var mask = dates.lt(target)
  precip = precip.mask(mask)

  // Find the index and date of the last day of precip.
  var size = precip.length().get([0])
  var index = ee.Array(ee.List.sequence(0, size.subtract(1)))
  var lastIndex = index.multiply(precip).reduce(ee.Reducer.max(), [0]).get([0])
  var lastDate = ee.Date(dates.get([lastIndex]))
  var daysDifference = ee.Date(target).difference(lastDate, 'day')
  return f.set('daysSinceLastPrecip', daysDifference)
}

print(Permits2020.map(getDryRunlength).aggregate_array('daysSinceLastPrecip'))

https://code.earthengine.google.com/a92cabc121f051448c174e92303bed88

See this blog post for more about runs: https://medium.com/google-earth/runs-with-arrays-400de937510a

2
  • I need to export this analysis and I am working with a very large FeatureCollection (hundreds of thousands of records). Is there anything I can do to avoid memory issues and/or reduce the time to export this data? @NoelGorelick Jun 9, 2021 at 14:16
  • This approach shouldn't run into any memory issues since each ReduceRegion will essentially run independently, but it could take a while to export a table with >>100k points. I'd start by seeing how long it takes to export ~5000 point and based on that figure out if it's worth breaking up into multiple pieces. Jun 10, 2021 at 15:05

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.