DOI: 10.7910/dvn/jq4bcn
title: A Google Earth Engine implementation of the Floodwater Depth Estimation Tool (FwDET-GEE)

description: &lt;b&gt;A Google Earth Engine implementation of the Floodwater Depth Estimation Tool (FwDET)&lt;/b&gt;&lt;br&gt;&lt;br&gt;
This is a Google Earth Engine implementation of the Floodwater Depth Estimation Tool (FwDET) developed by the Surface Dynamics and Modeling Lab at the University of Alabama that calculates flood depth using a flood extent layer and a digital elevation model. This research is made possible by the CyberSeed Program at the University of Alabama. &lt;i&gt;Project name&lt;/i&gt;: WaterServ: A Cyberinfrastructure for Analysis, Visualization and Sharing of Hydrological Data.
&lt;br&gt;&lt;br&gt;
&lt;i&gt;Please see the associated publications:&lt;/i&gt;
&lt;br&gt;
&lt;b&gt;1&lt;/b&gt;. Peter, B.G., Cohen, S., Lucey, R., Munasinghe, D., Raney, A. and Brakenridge, G.R., 2020. Google Earth Engine Implementation of the Floodwater Depth Estimation Tool (FwDET-GEE) for rapid and large scale flood analysis. &lt;i&gt;IEEE Geoscience and Remote Sensing Letters&lt;/i&gt;, 19, pp.1-5.
&lt;br&gt;
&lt;a href="https://ieeexplore.ieee.org/abstract/document/9242297"&gt;https://ieeexplore.ieee.org/abstract/document/9242297&lt;/a&gt;
&lt;br&gt;
&lt;b&gt;2&lt;/b&gt;. Cohen, S., Peter, B.G., Haag, A., Munasinghe, D., Moragoda, N., Narayanan, A. and May, S., 2022. Sensitivity of remote sensing floodwater depth calculation to boundary filtering and digital elevation model selections. &lt;i&gt;Remote Sensing&lt;/i&gt;, 14(21), p.5313.
&lt;br&gt;
&lt;a href ="https://www.mdpi.com/2072-4292/14/21/5313&gt;https://www.mdpi.com/2072-4292/14/21/5313&gt;https://www.mdpi.com/2072-4292/14/21/5313&lt;/a&gt;
&lt;br&gt;&lt;br&gt;
GitHub Repository (ArcMap and QGIS implementations): &lt;a href = "https://github.com/csdms-contrib/fwdet"&gt;https://github.com/csdms-contrib/fwdet&lt;/a&gt;
&lt;br&gt;
&lt;b&gt;3&lt;/b&gt;. Cohen, S., A. Raney, D. Munasinghe, J.D. Loftis J, A. Molthan, J. Bell, L. Rogers, J. Galantowicz, G.R. Brakenridge7, A.J. Kettner, Y. Huang, Y. Tsang, (2019). The Floodwater Depth Estimation Tool (FwDET v2.0) for Improved Remote Sensing Analysis of Coastal Flooding. &lt;i&gt;Natural Hazards and Earth System Sciences&lt;/i&gt;, 19, 2053–2065. &lt;a href = "https://doi.org/10.5194/nhess-19-2053-2019"&gt;https://doi.org/10.5194/nhess-19-2053-2019&lt;/a&gt;
&lt;br&gt;
&lt;b&gt;4&lt;/b&gt;. Cohen, S., G. R. Brakenridge, A. Kettner, B. Bates, J. Nelson, R. McDonald, Y. Huang, D. Munasinghe, and J. Zhang (2018), Estimating Floodwater Depths from Flood Inundation Maps and Topography, &lt;i&gt;Journal of the American Water Resources Association&lt;/i&gt;, 54 (4), 847–858. &lt;a href = "https://doi.org/10.1111/1752-1688.12609"&gt;https://doi.org/10.1111/1752-1688.12609&lt;/a&gt;
&lt;br&gt;&lt;br&gt;
&lt;i&gt;Sample products and data availability:&lt;/i&gt;
&lt;br&gt;
&lt;a href = "https://sdml.ua.edu/models/fwdet/"&gt;https://sdml.ua.edu/models/fwdet/&lt;/a&gt;
&lt;br&gt;
&lt;a href = "https://sdml.ua.edu/michigan-flood-may-2020/"&gt;https://sdml.ua.edu/michigan-flood-may-2020/&lt;/a&gt;
&lt;br&gt;
&lt;a href = "https://cartoscience.users.earthengine.app/view/fwdet-gee-mi"&gt;https://cartoscience.users.earthengine.app/view/fwdet-gee-mi&lt;/a&gt;
&lt;br&gt;
&lt;a href = "https://alabama.app.box.com/s/31p8pdh6ngwqnbcgzlhyk2gkbsd2elq0"&gt;https://alabama.app.box.com/s/31p8pdh6ngwqnbcgzlhyk2gkbsd2elq0&lt;/a&gt;
&lt;br&gt;&lt;br&gt;
GEE implementation output: fwdet_gee_brazos.tif
&lt;br&gt;
ArcMap implementation output (see Cohen et al. 2019): fwdet_v2_brazos.tif
&lt;br&gt;
iRIC validation layer (see Nelson et al. 2010): iric_brazos_hydraulic_model_validation.tif 
&lt;br&gt;
Brazos River inundation polygon access in GEE: var brazos = ee.FeatureCollection('users/cartoscience/FwDET-GEE-Public/Brazos_River_Inundation_2016')
&lt;br&gt;&lt;br&gt;
Nelson, J.M., Shimizu, Y., Takebayashi, H. and McDonald, R.R., 2010. The international river interface cooperative: public domain software for river modeling. In 2nd Joint Federal Interagency Conference, Las Vegas, June (Vol. 27).
&lt;br&gt;&lt;br&gt;
&lt;i&gt;Google Earth Engine Code&lt;/i&gt;
&lt;pre&gt;
/* ----------------------------------------------------------------------------------------------------------------------
# FwDET-GEE calculates floodwater depth from a floodwater extent layer and a DEM
Authors: Brad G. Peter, Sagy Cohen, Ronan Lucey, Dinuke Munasinghe, Austin Raney
Emails: bpeter@ua.edu, sagy.cohen@ua.edu, ronan.m.lucey@nasa.gov, dsmunasinghe@crimson.ua.edu, aaraney@crimson.ua.edu
Organizations: BP, SC, DM, AR - University of Alabama; RL - University of Alabama in Huntsville
Last Modified: 10/08/2020

To cite this code use:
Peter, Brad; Cohen, Sagy; Lucey, Ronan; Munasinghe, Dinuke; Raney, Austin, 2020, "A Google Earth Engine implementation 
of the Floodwater Depth Estimation Tool (FwDET-GEE)", https://doi.org/10.7910/DVN/JQ4BCN, Harvard Dataverse, V2
-------------------------------------------------------------------------------------------------------------------------
This is a Google Earth Engine implementation of the Floodwater Depth Estimation Tool (FwDETv2.0) [1] developed by the 
Surface Dynamics and Modeling Lab at the University of Alabama that calculates flood depth using a flood extent layer 
and a digital elevation model. This research is made possible by the CyberSeed Program at the University of Alabama. 
Project name: WaterServ: A Cyberinfrastructure for Analysis, Visualization and Sharing of Hydrological Data. 
GitHub Repository (ArcMap and QGIS implementations): https://github.com/csdms-contrib/fwdet
-------------------------------------------------------------------------------------------------------------------------
How to run this code with your flood extent GEE asset:
User of this script will need to update path to flood extent (line 32 or 33) and select from the processing options. 
Available DEM options (1) are USGS/NED (U.S.) and USGS/SRTMGL1_003 (global). Other options include (2) running the elevation
outlier filtering algorithm, (3) adding water body data to the inundation extent, (4) add a water body data layer uploaded by 
the user rather than using the JRC global surface water data, (5) masking out regular water body data, (6) masking out 0 m 
depths, (7) choosing whether or not to export, (8) exporting additional data layers, and (9) setting an export file name. 
The simpleVis option (10) bypasses the time consuming processes and is meant for visualization only; set this option to false 
to complete the entire process and enable exporting. 
-------------------------------------------------------------------------------------------------------------------------

••••••••••••••••••••••••••••••••••••••••••• USER OPTIONS ••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••

Load flood extent layer | Flood extent layer must be uploaded to GEE first as an asset. If the flood extent is a 
shapefile, upload as a FeatureCollection; otherwise, if the flood extent layer is a raster, upload it as an image. 
A raster layer may be required if the flood extent is a highly complex geometry -------------------------------------- */

var flood = ee.FeatureCollection('users/username/folder/flood_extent') // comment out this line if using an Image
// var flood = ee.Image('users/username/folder/flood_extent') // comment out this line if using a FeatureCollection

var waterExtent = ee.FeatureCollection('users/username/folder/water_extent') // *OPTIONAL* comment out this line if using an Image
// var waterExtent = ee.Image('users/username/folder/water_extent') // *OPTIONAL* comment out this line if using a FeatureCollection

// Processing options - refer to the directions above
/*1*/ var demSource = 'USGS/NED' // 'USGS/NED' or 'USGS/SRTMGL1_003'
/*2*/ var outlierTest = 'TRUE' // 'TRUE' (default) or 'FALSE'
/*3*/ var addWater = 'TRUE' // 'TRUE' (default) or 'FALSE'
/*4*/ var userWater = 'FALSE' // 'TRUE' or 'FALSE' (default)
/*5*/ var maskWater = 'FALSE' // 'TRUE' or 'FALSE' (default)
/*6*/ var maskZero = 'FALSE' // 'TRUE' or 'FALSE' (default)
/*7*/ var exportLayer = 'TRUE' // 'TRUE' (default) or 'FALSE'
/*8*/ var exportAll = 'FALSE' // 'TRUE' or 'FALSE' (default)
/*9*/ var outputName = 'FwDET_GEE' // text string for naming export file
/*10*/ var simpleVis = 'FALSE' // 'TRUE' or 'FALSE' (default)

// ••••••••••••••••••••••••••••••••• NO USER INPUT BEYOND THIS POINT ••••••••••••••••••••••••••••••••••••••••••••••••••••

// Create buffer around flood area to use for clipping other layers
var area = flood.geometry().bounds().buffer(1000).bounds()

// Load DEM and grab projection info
var dem = ee.Image(demSource).select('elevation').clip(area) // [2,3]
var projection = dem.projection()
var resolution = projection.nominalScale().getInfo()

// Load global surface water layer
var jrc = ee.Image('JRC/GSW1_1/GlobalSurfaceWater').select('occurrence').clip(area) // [4]
var water_image = jrc

// User uploaded flood extent layer
// Identify if a raster or vector layer is being used and proceed with appropriate process
if ( flood.name() == 'FeatureCollection' ) {
 var addProperty = function(feature) {
 return feature.set('val',0);
 };
 var flood_image = flood.map(addProperty).reduceToImage(['val'],ee.Reducer.first())
 .rename('flood')
} else {
 var flood_image = flood.multiply(0)
}

// Optional user uploaded water extent layer
if ( userWater == 'TRUE' ) {
 // Identify if a raster or vector layer is being used and proceed with appropriate process
 if ( waterExtent.name() == 'FeatureCollection' ) {
 var addProperty = function(feature) {
 return feature.set('val',0);
 };
 var water_image = waterExtent.map(addProperty).reduceToImage(['val'],ee.Reducer.first())
 .rename('flood')
 } else {
 var water_image = waterExtent.multiply(0)
 }
}

// Add water bodies to flood extent if 'TRUE' is selected
if ( addWater == 'TRUE' ) {
 var w = water_image.reproject(projection)
 var waterFill = flood_image.mask().where(w.gt(0),1)
 flood_image = waterFill.updateMask(waterFill.eq(1)).multiply(0)
}

// Change processing options if 'TRUE' is selected
if ( simpleVis == 'FALSE' ) {
 flood_image = flood_image.reproject(projection)
} else {
 outlierTest = 'FALSE'
 exportLayer = 'FALSE'
}

// Run the outlier filtering process if 'TRUE' is selected
if ( outlierTest == 'TRUE' ) {
 // Outlier detection and filling on complete DEM using the modified z-score and a median filter [5]
 var kernel = ee.Kernel.fixed(3,3,[[1,1,1],[1,1,1],[1,1,1]])
 var kernel_weighted = ee.Kernel.fixed(3,3,[[1,1,1],[1,0,1],[1,1,1]])
 var median = dem.focal_median({kernel:kernel}).reproject(projection)
 var median_weighted = dem.focal_median({kernel:kernel_weighted}).reproject(projection)
 var diff = dem.subtract(median)
 var mzscore = diff.multiply(0.6745).divide(diff.abs().focal_median({kernel:kernel}).reproject(projection))
 var fillDEM = dem.where(mzscore.gt(3.5),median_weighted) 
 
 // Outlier detection and filling on the flood extent border pixels
 var expand = flood_image.focal_max({kernel: ee.Kernel.square({
 radius: projection.nominalScale(), 
 units: 'meters'
 })}).reproject(projection)
 var demMask = fillDEM.updateMask(flood_image.mask().eq(0))
 var boundary = demMask.add(expand)
 var medianBoundary = boundary.focal_median({kernel:kernel}).reproject(projection)
 var medianWeightedBoundary = boundary.focal_median({kernel:kernel_weighted}).reproject(projection)
 var diffBoundary = boundary.subtract(medianBoundary)
 var mzscoreBoundary = diffBoundary.multiply(0.6745).divide(diffBoundary.abs().focal_median({kernel:kernel}).reproject(projection))
 var fill = fillDEM.where(mzscoreBoundary.gt(3.5),medianWeightedBoundary) 
} else {
 var fill = dem
}

// cumulativeCost floodwater surface elevation model (adaptation of the cost allocation method from FwDETv2.0)
var mod = fill.updateMask(flood_image.mask().eq(0))
var source = mod.mask()
var val = 10000
var push = 5000
var cost0 = ee.Image(val).where(source,0).cumulativeCost(source,push)
var cost1 = ee.Image(val).where(source,1).cumulativeCost(source,push)
var cost2 = mod.unmask(val).cumulativeCost(source,push)
var costFill = cost2.subtract(cost0).divide(cost1.subtract(cost0))
var costSurface = mod.unmask(0).add(costFill)
// Interpolation method courtesy of Matt Hancher (Earth Engine Co-Founder) posted to the GEE developer forums
// https://groups.google.com/forum/#!forum/google-earth-engine-developers

// Kernel size for low-pass filter
var boxcar = ee.Kernel.square({
 radius: 3, units: 'pixels', normalize: true
});

// Floodwater depth calculation and smoothing using a low-pass filter
var costDepth = costSurface.subtract(fill)
 .rename('FwDET_GEE')
 .convolve(boxcar)
 .reproject(projection)
 .updateMask(flood_image.eq(0))
 
var costDepthFilter = costDepth.where(costDepth.lt(0),0)

// Mask out regular water bodies if 'TRUE' is selected
if ( maskWater === 'TRUE' ) {
 var w = jrc.reproject(projection)
 costDepthFilter = costDepthFilter.updateMask(w.mask().eq(0))
}

// Mask out zero values if 'TRUE' is selected
if ( maskZero === 'TRUE' ) {
 costDepthFilter = costDepthFilter.updateMask(costDepthFilter.neq(0))
}

// Add flood depth to console
Map.clear() 
Map.setOptions('HYBRID')
Map.centerObject(flood)

// Add message to user
var message = ui.Panel({
 layout: ui.Panel.Layout.flow('vertical'),
 style: {position: 'bottom-left', border: '1px solid gray', padding: '2px'}
})

message.widgets().set(0,ui.Label('Check tasks tab for export'));
Map.add(message);

// Change options for visualization sample
if ( simpleVis == 'TRUE' ) {
 var histOptions = {
 title: 'Depth (m)',
 fontSize: 11,
 legend: {position: 'none'},
 series: {0: {color: '7100AA'}}
 };
 var histogram = ui.Chart.image.histogram({
 image: costDepthFilter.updateMask(costDepthFilter.neq(0)),
 region: area, 
 scale: resolution*10
 }).setOptions(histOptions)
 Map.addLayer(costDepthFilter,{},'FwDET GEE',true)
 message.widgets().set(0,ui.Label("set simpleVis to 'FALSE' to export layers"))
 message.widgets().set(1,histogram)
} else {
 Map.addLayer(flood_image,{},'flood extent',true)
 Map.addLayer(costDepthFilter,{},'FwDET GEE',false)
}

// Export function
var exportFunc = function(i,n) {
 return Export.image.toDrive({
 image: i,
 description: outputName+n,
 fileNamePrefix: outputName+n,
 maxPixels: 1e13,
 scale: resolution,
 region: area
 })
}

// Export output if 'TRUE' is selected
if ( exportLayer === 'TRUE' ) {
 exportFunc(costDepthFilter, '_FwDET')
 
 // Export all layers if 'TRUE' is selected
 if ( exportAll == 'TRUE' ) {
 exportFunc(costSurface, '_costSurface')
 exportFunc(dem, '_dem')
 exportFunc(fill, '_demFill')
 }
}
 
/* ----------------------------------------------------------------------------------------------------------------------
// Citations
// [1] Cohen, S., A. Raney, D. Munasinghe, J.D. Loftis J, A. Molthan, J. Bell, L. Rogers, J. Galantowicz, 
// G.R. Brakenridge7, A.J. Kettner, Y. Huang, Y. Tsang, (2019). The Floodwater Depth Estimation Tool (FwDET v2.0) 
// for Improved Remote Sensing Analysis of Coastal Flooding. Natural Hazards and Earth System Sciences, 19, 2053–2065. 
// https://doi.org/10.5194/nhess-19-2053-2019
// [2] Gesch, D., Oimoen, M., Greenlee, S., Nelson, C., Steuck, M. and Tyler, D., 2002. The national elevation dataset. 
// Photogrammetric engineering and remote sensing, 68(1), pp.5-32.
// [3] Farr, T.G., Rosen, P.A., Caro, E., Crippen, R., Duren, R., Hensley, S., Kobrick, M., Paller, M., Rodriguez, E., 
// Roth, L. and Seal, D., 2007. The shuttle radar topography mission. Reviews of geophysics, 45(2).
// [4] Pekel, J.F., Cottam, A., Gorelick, N. and Belward, A.S., 2016. High-resolution mapping of global surface 
// water and its long-term changes. Nature, 540(7633), pp.418-422.
// [5] Iglewicz, B. and Hoaglin, D.C., 1993. How to detect and handle outliers (Vol. 16). Asq Press.
---------------------------------------------------------------------------------------------------------------------- */
&lt;/pre&gt;