def derive_HAND(dem, ldd, accuThreshold, rivers=None, basin=None, up_area=None): """ Function derives Height-Above-Nearest-Drain. See http://www.sciencedirect.com/science/article/pii/S003442570800120X Input: dem -- pcraster object float32, elevation data ldd -- pcraster object direction, local drain directions accuThreshold -- upstream amount of cells as threshold for river delineation rivers=None -- you can provide a rivers layer here. Pixels that are identified as river should have a value > 0, other pixels a value of zero. basin=None -- set a boolean pcraster map where areas with True are estimated using the nearest drain in ldd distance and areas with False by means of the nearest friction distance. Friction distance estimated using the upstream area as weight (i.e. drains with a bigger upstream area have a lower friction) the spreadzone operator is used in this case. up_area=None -- provide the upstream area (if not assigned a guesstimate is prepared, assuming the LDD covers a full catchment area) Output: hand -- pcraster bject float32, height, normalised to nearest stream dist -- distance to nearest stream measured in cell lengths according to D8 directions """ if rivers is None: # prepare stream from a strahler threshold stream = pcr.ifthenelse( pcr.accuflux(ldd, 1) >= accuThreshold, pcr.boolean(1), pcr.boolean(0)) else: # convert stream network to boolean stream = pcr.boolean(pcr.cover(rivers, 0)) # determine height in river (in DEM*100 unit as ordinal) height_river = pcr.ifthenelse(stream, pcr.ordinal(dem * 100), 0) if basin is None: up_elevation = pcr.scalar(pcr.subcatchment(ldd, height_river)) else: # use basin to allocate areas outside basin to the nearest stream. Nearest is weighted by upstream area if up_area is None: up_area = pcr.accuflux(ldd, 1) up_area = pcr.ifthen(stream, up_area) # mask areas outside streams friction = 1. / pcr.scalar( pcr.spreadzone(pcr.cover(pcr.ordinal(up_area), 0), 0, 0)) # if basin, use nearest river within subcatchment, if outside basin, use weighted-nearest river up_elevation = pcr.ifthenelse( basin, pcr.scalar(pcr.subcatchment(ldd, height_river)), pcr.scalar(pcr.spreadzone(height_river, 0, friction))) # replace areas outside of basin by a spread zone calculation. hand = pcr.max(pcr.scalar(pcr.ordinal(dem * 100)) - up_elevation, 0) / 100 # convert back to float in DEM units # hand = (pcr.scalar(pcr.ordinal(dem*100))-up_elevation)/100 # convert back to float in DEM units dist = pcr.ldddist(ldd, stream, 1) # compute horizontal distance estimate return hand, dist
def derive_HAND(dem, ldd, accuThreshold, rivers=None, basin=None, up_area=None, neg_HAND=None): """ Function derives Height-Above-Nearest-Drain. See http://www.sciencedirect.com/science/article/pii/S003442570800120X Input: dem -- pcraster object float32, elevation data ldd -- pcraster object direction, local drain directions accuThreshold -- upstream amount of cells as threshold for river delineation rivers=None -- you can provide a rivers layer here. Pixels that are identified as river should have a value > 0, other pixels a value of zero. basin=None -- set a boolean pcraster map where areas with True are estimated using the nearest drain in ldd distance and areas with False by means of the nearest friction distance. Friction distance estimated using the upstream area as weight (i.e. drains with a bigger upstream area have a lower friction) the spreadzone operator is used in this case. up_area=None -- provide the upstream area (if not assigned a guesstimate is prepared, assuming the LDD covers a full catchment area) neg_HAND=None -- if set to 1, HAND maps can have negative values when elevation outside of stream is lower than stream (for example when there are natural embankments) Output: hand -- pcraster bject float32, height, normalised to nearest stream dist -- distance to nearest stream measured in cell lengths according to D8 directions """ if rivers is None: # prepare stream from a strahler threshold stream = pcr.ifthenelse(pcr.accuflux(ldd, 1) >= accuThreshold, pcr.boolean(1), pcr.boolean(0)) else: # convert stream network to boolean stream = pcr.boolean(pcr.cover(rivers, 0)) # determine height in river (in DEM*100 unit as ordinal) height_river = pcr.ifthenelse(stream, pcr.ordinal(dem*100), 0) if basin is None: up_elevation = pcr.scalar(pcr.subcatchment(ldd, height_river)) else: # use basin to allocate areas outside basin to the nearest stream. Nearest is weighted by upstream area if up_area is None: up_area = pcr.accuflux(ldd, 1) up_area = pcr.ifthen(stream, up_area) # mask areas outside streams friction = 1./pcr.scalar(pcr.spreadzone(pcr.cover(pcr.ordinal(up_area), 0), 0, 0)) # if basin, use nearest river within subcatchment, if outside basin, use weighted-nearest river up_elevation = pcr.ifthenelse(basin, pcr.scalar(pcr.subcatchment(ldd, height_river)), pcr.scalar(pcr.spreadzone(height_river, 0, friction))) # replace areas outside of basin by a spread zone calculation. # make negative HANDS also possible if neg_HAND == 1: hand = (pcr.scalar(pcr.ordinal(dem*100))-up_elevation)/100 # convert back to float in DEM units else: hand = pcr.max(pcr.scalar(pcr.ordinal(dem*100))-up_elevation, 0)/100 # convert back to float in DEM units dist = pcr.ldddist(ldd, stream, 1) # compute horizontal distance estimate return hand, dist
def derive_HAND(dem, ldd, accuThreshold, rivers=None, basin=None): """ Function derives Height-Above-Nearest-Drain. See http://www.sciencedirect.com/science/article/pii/S003442570800120X Input: dem -- pcraster object float32, elevation data ldd -- pcraster object direction, local drain directions accuThreshold -- upstream amount of cells as threshold for river delineation rivers=None -- you can provide a rivers layer here. Pixels that are identified as river should have a value > 0, other pixels a value of zero. basin=None -- set a boolean pcraster map where areas with True are estimated using the nearest drain in ldd distance and areas with False by means of the nearest friction distance. Friction distance estimated using the upstream area as weight (i.e. drains with a bigger upstream area have a lower friction) the spreadzone operator is used in this case. Output: hand -- pcraster bject float32, height, normalised to nearest stream dist -- distance to nearest stream measured in cell lengths according to D8 directions """ if rivers is None: stream = pcr.ifthenelse( pcr.accuflux(ldd, 1) >= accuThreshold, pcr.boolean(1), pcr.boolean(0) ) else: stream = pcr.boolean(pcr.cover(rivers, 0)) height_river = pcr.ifthenelse(stream, pcr.ordinal(dem * 100), 0) if basin is None: up_elevation = pcr.scalar(pcr.subcatchment(ldd, height_river)) else: drainage_surf = pcr.ifthen(rivers, pcr.accuflux(ldd, 1)) weight = 1.0 / pcr.scalar( pcr.spreadzone(pcr.cover(pcr.ordinal(drainage_surf), 0), 0, 0) ) up_elevation = pcr.ifthenelse( basin, pcr.scalar(pcr.subcatchment(ldd, height_river)), pcr.scalar(pcr.spreadzone(height_river, 0, weight)), ) # replace areas outside of basin by a spread zone calculation. hand = pcr.max(pcr.scalar(pcr.ordinal(dem * 100)) - up_elevation, 0) / 100 dist = pcr.ldddist(ldd, stream, 1) return hand, dist
def generate_hydro_datasets(path, output_dir, step): print(path) file_name = os.path.splitext(os.path.basename(path))[0] map_path = output_dir + '/' + file_name + '.map' path_prefix = map_path[:-14] if step == 'ldd': cmd = u'gdal_translate -a_nodata -9999 -of PCRaster -ot Float32 ' + path + ' ' + map_path print(cmd) subprocess.call(cmd, shell=True) # slope = pcr.slope(dem) # pcr.report(slope, path_prefix + '_slope.map') # pcr.setglobaloption("lddin") if step == 'ldd': dem = pcr.readmap(map_path) print("Computing LDD ...") # enable pit filling ldd = pcr.lddcreate(dem, 9999999, 9999999, 9999999, 9999999) pcr.report(ldd, path_prefix + '_ldd.map') return elif step == 'ldddem': dem = pcr.readmap(map_path) print("Computing LDD DEM ...") dem_pitfilled = pcr.lddcreatedem(dem, 9999999, 9999999, 9999999, 9999999) dem_diff = dem_pitfilled - dem pcr.report(dem_diff, path_prefix + '_dem_pits_diff.map') return # print("Computing LDD without pit filling ...") # ldd_pits = pcr.lddcreate(dem, 0, 0, 0, 0) # pcr.report(ldd_pits, path_prefix + '_ldd_with_pits.map') # print("Computing pits ...") # pits = pcr.pit(ldd_pits) # pcr.report(pits, path_prefix + '_pits.map') if step == 'fa': ldd = pcr.readmap(path_prefix + '_ldd.map') print("Computing flow accumulation ...") fa = pcr.accuflux(ldd, 1) pcr.report(fa, path_prefix + '_fa.map') return if step == 'catchments': ldd = pcr.readmap(path_prefix + '_ldd.map') print("Delineating catchments ...") catchments = pcr.catchment(ldd, pcr.pit(ldd)) pcr.report(catchments, path_prefix + '_catchments.map') return if step == 'stream_order': ldd = pcr.readmap(path_prefix + '_ldd.map') print("Computing stream order ...") stream_order = pcr.streamorder(ldd) pcr.report(stream_order, path_prefix + '_streamorder.map') return if step == 'stream': ldd = pcr.readmap(path_prefix + '_ldd.map') accuThreshold = 100 print("Computing stream ...") stream = pcr.ifthenelse( pcr.accuflux(ldd, 1) >= accuThreshold, pcr.boolean(1), pcr.boolean(0)) pcr.report(stream, path_prefix + '_stream.map') return if step == 'height_river': print("Computing heigh_river ...") stream = pcr.readmap(path_prefix + '_stream.map') dem = pcr.readmap(map_path) height_river = pcr.ifthenelse(stream, pcr.ordinal(dem), 0) pcr.report(height_river, path_prefix + '_height_river.map') return if step == 'up_elevation': print("Computing up_elevation ...") height_river = pcr.readmap(path_prefix + '_height_river.map') ldd = pcr.readmap(path_prefix + '_ldd.map') up_elevation = pcr.scalar(pcr.subcatchment(ldd, height_river)) pcr.report(up_elevation, path_prefix + '_up_elevation.map') return if step == 'hand': print("Computing HAND ...") dem = pcr.readmap(map_path) up_elevation = pcr.readmap(path_prefix + '_up_elevation.map') hand = pcr.max(dem - up_elevation, 0) pcr.report(hand, path_prefix + '_hand.map') return if step == 'dand': print("Computing DAND ...") ldd = pcr.readmap(path_prefix + '_ldd.map') stream = pcr.readmap(path_prefix + '_stream.map') dist = pcr.ldddist(ldd, stream, 1) pcr.report(dist, path_prefix + '_dist.map') return if step == 'fa_river': print("Computing FA river ...") fa = pcr.readmap(path_prefix + '_fa.map') stream = pcr.readmap(path_prefix + '_stream.map') fa_river = pcr.ifthenelse(stream, pcr.ordinal(fa), 0) pcr.report(fa_river, path_prefix + '_fa_river.map') return if step == 'faand': print("Computing FAAND ...") fa_river = pcr.readmap(path_prefix + '_fa_river.map') ldd = pcr.readmap(path_prefix + '_ldd.map') up_fa = pcr.scalar(pcr.subcatchment(ldd, fa_river)) pcr.report(up_fa, path_prefix + '_faand.map') return
def pcr_inun(dem, ids, h_bounds, ids_coastline, resistance=0., water_perc=None, zero_resistance_waterp=1.0, cellres=1, dist_method='eucledian', ldd=None): """ planar inundation routine per segment :param dem: pcr dem :param ids: local ids of boundary conditions, starting a 1 (not zero!) :param h_bounds: water level boundary at diva segment :param ids_coastline: pcraster map with coastal segments ids :param resistance: constant or pcrmap unit km-1; (default 0: no resistance is calculated) :param cellres: cell resolution in km, varies with latitude degrees :param ldd: pcraster map with local drainage direction to calculate resistance along ldd; if None (default) resistance is calculated using 'plain' nearest neighbour :return: pcrmap with flood depth """ pcr.setglobaloption("unitcell") if resistance > 0: coastline = pcr.cover(pcr.ifthenelse(pcr.scalar(ids_coastline) > 0, pcr.boolean(1), 0), pcr.boolean(0)) mask = pcr.ifthen(dem > -9999, pcr.scalar(1)) if dist_method == 'ldd': # Distance to coast along ldd dist2coast0 = pcr.ldddist(ldd, coastline, cellres) # find edge of area with distances -> water divide dist2coast_mask = pcr.cover(pcr.ifthenelse(dist2coast0 > 0, pcr.boolean(0), pcr.boolean(1)), pcr.boolean(1)) start = pcr.ifthenelse( ((pcr.window4total(pcr.scalar(dist2coast_mask)) > 0) & (dist2coast_mask == pcr.boolean(0))) | coastline, pcr.boolean(1), pcr.boolean(0)) # continue distance beyond water divide with eucledian dist dist2coast1 = pcr.spread(start, dist2coast0, cellres*mask) dist2coast = pcr.ifthenelse(dist2coast_mask, dist2coast1, dist2coast0) elif dist_method == 'eucledian': # dist to coast using nearest neighbor if water_perc is None: dist2coast = pcr.spread(coastline, 0, cellres*mask) else: # zero resistance for cells with water_perc >= zero_resistance_waterp zrw = float(zero_resistance_waterp) water_perc = pcr.ifthenelse(water_perc >= zrw, pcr.scalar(1), water_perc / zrw) dist2coast = pcr.spread(coastline, 0, cellres*mask*(1 - water_perc)) dem_adjust = dem + pcr.cover(dist2coast, 0) * pcr.scalar(resistance) # raise the elevation using a damping factor else: dem_adjust = dem dist2coast = pcr.scalar(1) fld_depth = pcr.ifthen(dem > -9999, pcr.scalar(0)) for i, h in zip(ids, h_bounds): coast_segment = pcr.ifthenelse(ids_coastline == i, pcr.boolean(1), pcr.boolean(0)) # find area below flood_level fld_prone = pcr.ifthenelse(dem_adjust <= pcr.scalar(float(h)), pcr.boolean(1), pcr.boolean(0)) # make contiguous groups of cells which are below flood level fld_clump = pcr.clump(fld_prone) # find flooded area connected to diva segment fld_coast = pcr.ifthenelse(pcr.areamaximum(pcr.scalar(fld_clump) * pcr.scalar(coast_segment), fld_clump) > 0, pcr.boolean(1), pcr.boolean(0)) # get max fld depth map fld_depth = pcr.max(fld_depth, pcr.ifthenelse(fld_coast, pcr.scalar(pcr.scalar(float(h)) - dem_adjust), 0)) return fld_depth, dist2coast, dem_adjust
def generate_hydro_datasets(path, output_dir, step): print(path) file_name = os.path.splitext(os.path.basename(path))[0] map_path = output_dir + "/" + file_name + ".map" path_prefix = map_path[:-14] if step == "ldd": cmd = u"gdal_translate -a_nodata -9999 -of PCRaster -ot Float32 " + path + " " + map_path print(cmd) subprocess.call(cmd, shell=True) # slope = pcr.slope(dem) # pcr.report(slope, path_prefix + '_slope.map') # pcr.setglobaloption("lddin") if step == "ldd": dem = pcr.readmap(map_path) print("Computing LDD ...") # enable pit filling ldd = pcr.lddcreate(dem, 9999999, 9999999, 9999999, 9999999) pcr.report(ldd, path_prefix + "_ldd.map") return elif step == "ldddem": dem = pcr.readmap(map_path) print("Computing LDD DEM ...") dem_pitfilled = pcr.lddcreatedem(dem, 9999999, 9999999, 9999999, 9999999) dem_diff = dem_pitfilled - dem pcr.report(dem_diff, path_prefix + "_dem_pits_diff.map") return # print("Computing LDD without pit filling ...") # ldd_pits = pcr.lddcreate(dem, 0, 0, 0, 0) # pcr.report(ldd_pits, path_prefix + '_ldd_with_pits.map') # print("Computing pits ...") # pits = pcr.pit(ldd_pits) # pcr.report(pits, path_prefix + '_pits.map') if step == "fa": ldd = pcr.readmap(path_prefix + "_ldd.map") print("Computing flow accumulation ...") fa = pcr.accuflux(ldd, 1) pcr.report(fa, path_prefix + "_fa.map") return if step == "catchments": ldd = pcr.readmap(path_prefix + "_ldd.map") print("Delineating catchments ...") catchments = pcr.catchment(ldd, pcr.pit(ldd)) pcr.report(catchments, path_prefix + "_catchments.map") return if step == "stream_order": ldd = pcr.readmap(path_prefix + "_ldd.map") print("Computing stream order ...") stream_order = pcr.streamorder(ldd) pcr.report(stream_order, path_prefix + "_streamorder.map") return if step == "stream": ldd = pcr.readmap(path_prefix + "_ldd.map") accuThreshold = 100 print("Computing stream ...") stream = pcr.ifthenelse(pcr.accuflux(ldd, 1) >= accuThreshold, pcr.boolean(1), pcr.boolean(0)) pcr.report(stream, path_prefix + "_stream.map") return if step == "height_river": print("Computing heigh_river ...") stream = pcr.readmap(path_prefix + "_stream.map") dem = pcr.readmap(map_path) height_river = pcr.ifthenelse(stream, pcr.ordinal(dem), 0) pcr.report(height_river, path_prefix + "_height_river.map") return if step == "up_elevation": print("Computing up_elevation ...") height_river = pcr.readmap(path_prefix + "_height_river.map") ldd = pcr.readmap(path_prefix + "_ldd.map") up_elevation = pcr.scalar(pcr.subcatchment(ldd, height_river)) pcr.report(up_elevation, path_prefix + "_up_elevation.map") return if step == "hand": print("Computing HAND ...") dem = pcr.readmap(map_path) up_elevation = pcr.readmap(path_prefix + "_up_elevation.map") hand = pcr.max(dem - up_elevation, 0) pcr.report(hand, path_prefix + "_hand.map") return if step == "dand": print("Computing DAND ...") ldd = pcr.readmap(path_prefix + "_ldd.map") stream = pcr.readmap(path_prefix + "_stream.map") dist = pcr.ldddist(ldd, stream, 1) pcr.report(dist, path_prefix + "_dist.map") return if step == "fa_river": print("Computing FA river ...") fa = pcr.readmap(path_prefix + "_fa.map") stream = pcr.readmap(path_prefix + "_stream.map") fa_river = pcr.ifthenelse(stream, pcr.ordinal(fa), 0) pcr.report(fa_river, path_prefix + "_fa_river.map") return if step == "faand": print("Computing FAAND ...") fa_river = pcr.readmap(path_prefix + "_fa_river.map") ldd = pcr.readmap(path_prefix + "_ldd.map") up_fa = pcr.scalar(pcr.subcatchment(ldd, fa_river)) pcr.report(up_fa, path_prefix + "_faand.map") return