def getLakeOutflow( self, avgChannelDischarge, length_of_time_step=vos.secondsPerDay() ): # waterHeight (m): temporary variable, a function of storage: minWaterHeight = ( 0.001 ) # (m) Rens used 0.001 m as the limit # this is to make sure there is always lake outflow, # but it will be still limited by available self.waterBodyStorage waterHeight = pcr.cover( pcr.max( minWaterHeight, (self.waterBodyStorage - pcr.cover(self.waterBodyCap, 0.0)) / self.waterBodyArea, ), 0.0, ) # weirWidth (m) : # - estimated from avgOutflow (m3/s) using the bankfull discharge formula # avgOutflow = self.avgOutflow avgOutflow = pcr.ifthenelse( avgOutflow > 0.0, avgOutflow, pcr.max(avgChannelDischarge, self.avgInflow, 0.001), ) # This is needed when new lakes/reservoirs introduced (its avgOutflow is still zero). avgOutflow = pcr.areamaximum(avgOutflow, self.waterBodyIds) # bankfullWidth = pcr.cover(pcr.scalar(4.8) * ((avgOutflow) ** (0.5)), 0.0) weirWidthUsed = bankfullWidth weirWidthUsed = pcr.max( weirWidthUsed, self.minWeirWidth ) # TODO: minWeirWidth based on the GRanD database weirWidthUsed = pcr.cover( pcr.ifthen(pcr.scalar(self.waterBodyIds) > 0.0, weirWidthUsed), 0.0 ) # avgInflow <= lakeOutflow (weirFormula) <= waterBodyStorage lakeOutflowInM3PerSec = pcr.max( self.weirFormula(waterHeight, weirWidthUsed), self.avgInflow ) # unit: m3/s # estimate volume of water relased by lakes lakeOutflow = lakeOutflowInM3PerSec * length_of_time_step # unit: m3 lakeOutflow = pcr.min(self.waterBodyStorage, lakeOutflow) # lakeOutflow = pcr.ifthen(pcr.scalar(self.waterBodyIds) > 0.0, lakeOutflow) lakeOutflow = pcr.ifthen(pcr.scalar(self.waterBodyTyp) == 1, lakeOutflow) # TODO: Consider endorheic lake/basin. No outflow for endorheic lake/basin! return lakeOutflow
def getLakeOutflow(self,\ avgChannelDischarge,length_of_time_step = vos.secondsPerDay()): # waterHeight (m): temporary variable, a function of storage: minWaterHeight = 0.001 # (m) Rens used 0.001 m as the limit # this is to make sure there is always lake outflow, # but it will be still limited by available self.waterBodyStorage waterHeight = pcr.cover( pcr.max(minWaterHeight, \ (self.waterBodyStorage - \ pcr.cover(self.waterBodyCap, 0.0))/\ self.waterBodyArea),0.) # weirWidth (m) : # - estimated from avgOutflow (m3/s) using the bankfull discharge formula # avgOutflow = self.avgOutflow avgOutflow = pcr.ifthenelse(\ avgOutflow > 0.,\ avgOutflow, pcr.max(avgChannelDischarge,self.avgInflow,0.001)) # This is needed when new lakes/reservoirs introduced (its avgOutflow is still zero). avgOutflow = pcr.areamaximum(avgOutflow, self.waterBodyIds) # bankfullWidth = pcr.cover(\ pcr.scalar(4.8) * \ ((avgOutflow)**(0.5)),0.) weirWidthUsed = bankfullWidth weirWidthUsed = pcr.max( weirWidthUsed, self.minWeirWidth ) # TODO: minWeirWidth based on the GRanD database weirWidthUsed = pcr.cover( pcr.ifthen(\ pcr.scalar(self.waterBodyIds) > 0.,\ weirWidthUsed),0.0) # avgInflow <= lakeOutflow (weirFormula) <= waterBodyStorage lakeOutflowInM3PerSec = pcr.max(\ self.weirFormula(waterHeight,weirWidthUsed),\ self.avgInflow) # unit: m3/s # estimate volume of water relased by lakes lakeOutflow = lakeOutflowInM3PerSec * length_of_time_step # unit: m3 lakeOutflow = pcr.min(self.waterBodyStorage, lakeOutflow) # lakeOutflow = pcr.ifthen( pcr.scalar(self.waterBodyIds) > 0., lakeOutflow) lakeOutflow = pcr.ifthen( pcr.scalar(self.waterBodyTyp) == 1, lakeOutflow) # TODO: Consider endorheic lake/basin. No outflow for endorheic lake/basin! return (lakeOutflow)
def premcloop(self): self.clone = pcr.boolean(cfg.cloneString) self.dem = pcr.scalar(cfg.dem) self.createInstancesPremcloop() # required for reporting as numpy self.locations = pcr.cover(pcr.nominal(cfg.locations), 0) pcr.report(self.locations, 'locats') self.forestNoForest = pcr.boolean(cfg.forestNoForest) idMap = pcr.uniqueid(self.clone) oneLocationPerArea = pcr.areamaximum(idMap, self.forestNoForest) == idMap self.locationsForParameters = pcr.cover( pcr.nominal( pcr.scalar(pcr.ifthen(oneLocationPerArea, self.forestNoForest)) + 1), 0)
def area_river_burnin(ldd, dem, order, Area): """ Calculates the lowest values in as DEM for each erea in an area map for river of order *order* Input: - ldd - dem - order - Area map Output: - dem """ strorder = pcr.streamorder(ldd) strordermax = pcr.areamaximum(strorder, Area) maxordcell = pcr.ifthen(strordermax > order, strordermax) riverdem = pcr.areaminimum(dem, Area) return pcr.ifthen(pcr.boolean(maxordcell), riverdem)
def areastat(Var, Area): """ Calculate several statistics of *Var* for each unique id in *Area* Input: - Var - Area Output: - Standard_Deviation,Average,Max,Min """ Avg = pcr.areaaverage(Var, Area) Sq = (Var - Avg) ** 2 N = pcr.areatotal(pcr.spatial(pcr.cellarea()), Area) / pcr.cellarea() Sd = (pcr.areatotal(Sq, Area) / N) ** 0.5 Max = pcr.areamaximum(Var, Area) Min = pcr.areaminimum(Var, Area) return Sd, Avg, Max, Min
def area_riverlength_factor(ldd, Area, Clength): """ ceates correction factors for riverlength for the largest streamorder in each area Input: - ldd - Area - Clength (1d length of a cell (pcr.sqrt(Area)) Output: - distance per area """ strorder = pcr.streamorder(ldd) strordermax = pcr.areamaximum(strorder, Area) dist = pcr.downstreamdist(ldd) # count nr of strorder cells in each area nr = pcr.areatotal(pcr.ifthen(strorder == strordermax, dist), Area) # N = pcr.sqrt(pcr.areatotal(pcr.scalar(pcr.boolean(Area)),Area)) N = Clength factor = nr / N return factor
def set_river_package(self, discharge, currTimeStep): logger.info("Set the river package.") # - surface water river bed/bottom elevation and conductance need_to_define_surface_water_bed = False if currTimeStep == None: # this is for a steady state simulation (no currTimeStep define) need_to_define_surface_water_bed = True else: # only at the first month of the model simulation or the first month of the year if self.firstMonthOfSimulation or currTimeStep.month == 1: need_to_define_surface_water_bed = True self.firstMonthOfSimulation = False # This part becomes False as we don't need it anymore. if need_to_define_surface_water_bed: logger.info("Estimating the surface water bed elevation and surface water bed conductance.") #~ # - for lakes and resevoirs, alternative 1: make the bottom elevation deep --- Shall we do this? #~ additional_depth = 500. #~ surface_water_bed_elevation = pcr.ifthen(pcr.scalar(self.WaterBodies.waterBodyIds) > 0.0, \ #~ self.dem_riverbed - additional_depth) # # - for lakes and resevoirs, estimate bed elevation from dem and bankfull depth surface_water_bed_elevation = pcr.ifthen(pcr.scalar(self.WaterBodies.waterBodyIds) > 0.0, self.dem_average) surface_water_bed_elevation = pcr.areaaverage(surface_water_bed_elevation, self.WaterBodies.waterBodyIds) surface_water_bed_elevation -= pcr.areamaximum(self.bankfull_depth, self.WaterBodies.waterBodyIds) # surface_water_bed_elevation = pcr.cover(surface_water_bed_elevation, self.dem_riverbed) #~ surface_water_bed_elevation = self.dem_riverbed # This is an alternative, if we do not want to introduce very deep bottom elevations of lakes and/or reservoirs. # # rounding values for surface_water_bed_elevation self.surface_water_bed_elevation = pcr.roundup(surface_water_bed_elevation * 1000.)/1000. # # - river bed condutance (unit: m2/day) bed_surface_area = pcr.ifthen(pcr.scalar(self.WaterBodies.waterBodyIds) > 0.0, \ self.WaterBodies.fracWat * self.cellAreaMap) # TODO: Incorporate the concept of dynamicFracWat # I have problem with the convergence if I use this one. bed_surface_area = pcr.min(bed_surface_area,\ pcr.ifthen(pcr.scalar(self.WaterBodies.waterBodyIds) > 0.0, \ pcr.areaaverage(self.bankfull_width * self.channelLength, self.WaterBodies.waterBodyIds))) bed_surface_area = pcr.cover(bed_surface_area, \ self.bankfull_width * self.channelLength) #~ bed_surface_area = self.bankfull_width * self.channelLength bed_conductance = (1.0/self.bed_resistance) * bed_surface_area bed_conductance = pcr.ifthenelse(bed_conductance < 1e-20, 0.0, \ bed_conductance) self.bed_conductance = pcr.cover(bed_conductance, 0.0) logger.info("Estimating outlet widths of lakes and/or reservoirs.") # - 'channel width' for lakes and reservoirs channel_width = pcr.areamaximum(self.bankfull_width, self.WaterBodies.waterBodyIds) self.channel_width = pcr.cover(channel_width, self.bankfull_width) logger.info("Estimating surface water elevation.") # - convert discharge value to surface water elevation (m) river_water_height = (self.channel_width**(-3/5)) * (discharge**(3/5)) * ((self.gradient)**(-3/10)) *(self.manningsN**(3/5)) surface_water_elevation = self.dem_riverbed + \ river_water_height # # - calculating water level (unit: m) above the flood plain # TODO: Improve this concept (using Rens's latest innundation scheme) #---------------------------------------------------------- water_above_fpl = pcr.max(0.0, surface_water_elevation - self.dem_floodplain) # unit: m, water level above the floodplain (not distributed) water_above_fpl *= self.bankfull_depth * self.bankfull_width / self.cellAreaMap # unit: m, water level above the floodplain (distributed within the cell) # TODO: Improve this concept using Rens's latest scheme # # - corrected surface water elevation surface_water_elevation = pcr.ifthenelse(surface_water_elevation > self.dem_floodplain, \ self.dem_floodplain + water_above_fpl, \ surface_water_elevation) # - surface water elevation for lakes and reservoirs: lake_reservoir_water_elevation = pcr.ifthen(self.WaterBodies.waterBodyOut, surface_water_elevation) lake_reservoir_water_elevation = pcr.areamaximum(lake_reservoir_water_elevation, self.WaterBodies.waterBodyIds) lake_reservoir_water_elevation = pcr.cover(lake_reservoir_water_elevation, \ pcr.areaaverage(surface_water_elevation, self.WaterBodies.waterBodyIds)) # - maximum and minimum values for lake_reservoir_water_elevation lake_reservoir_water_elevation = pcr.min(self.dem_floodplain, lake_reservoir_water_elevation) lake_reservoir_water_elevation = pcr.max(self.surface_water_bed_elevation, lake_reservoir_water_elevation) # - smoothing lake_reservoir_water_elevation = pcr.areaaverage(surface_water_elevation, self.WaterBodies.waterBodyIds) # # - merge lake and reservoir water elevation surface_water_elevation = pcr.cover(lake_reservoir_water_elevation, surface_water_elevation) # # - covering the missing values and rounding surface_water_elevation = pcr.cover(surface_water_elevation, self.surface_water_bed_elevation) surface_water_elevation = pcr.rounddown(surface_water_elevation * 1000.)/1000. # # - make sure that HRIV >= RBOT ; no infiltration if HRIV = RBOT (and h < RBOT) self.surface_water_elevation = pcr.max(surface_water_elevation, self.surface_water_bed_elevation) # # - pass the values to the RIV package self.pcr_modflow.setRiver(self.surface_water_elevation, self.surface_water_bed_elevation, self.bed_conductance, 1)
def __init__(self): # Print model info print('The Spatial Processes in HYdrology (SPHY) model is') print( 'developed and owned by FutureWater, Wageningen, The Netherlands') print('Version 3.0, released June 2019') print(' ') #-Missing value definition self.MV = -9999 # Read the modules to be used self.GlacFLAG = config.getint('MODULES', 'GlacFLAG') self.SnowFLAG = config.getint('MODULES', 'SnowFLAG') self.RoutFLAG = config.getint('MODULES', 'RoutFLAG') self.ResFLAG = config.getint('MODULES', 'ResFLAG') self.LakeFLAG = config.getint('MODULES', 'LakeFLAG') self.DynVegFLAG = config.getint('MODULES', 'DynVegFLAG') self.GroundFLAG = config.getint('MODULES', 'GroundFLAG') self.SedFLAG = config.getint('MODULES', 'SedFLAG') self.SedTransFLAG = config.getint('MODULES', 'SedTransFLAG') # import the required modules import datetime, calendar, ET, rootzone, subzone import utilities.reporting as reporting import utilities.timecalc as timecalc import utilities.netcdf2PCraster as netcdf2PCraster from math import pi #-standard python modules self.datetime = datetime self.calendar = calendar self.pi = pi #-FW defined modules self.reporting = reporting self.timecalc = timecalc self.netcdf2PCraster = netcdf2PCraster self.ET = ET self.rootzone = rootzone self.subzone = subzone del datetime, calendar, pi, reporting, timecalc, ET, rootzone, subzone #-import additional modules if required if self.GlacFLAG == 1: self.SnowFLAG = 1 self.GroundFLAG = 1 #-read the input and output directories from the configuration file self.inpath = config.get('DIRS', 'inputdir') self.outpath = config.get('DIRS', 'outputdir') #-set the timing criteria sy = config.getint('TIMING', 'startyear') sm = config.getint('TIMING', 'startmonth') sd = config.getint('TIMING', 'startday') ey = config.getint('TIMING', 'endyear') em = config.getint('TIMING', 'endmonth') ed = config.getint('TIMING', 'endday') self.startdate = self.datetime.datetime(sy, sm, sd) self.enddate = self.datetime.datetime(ey, em, ed) self.dateAfterUpdate = self.startdate - self.datetime.timedelta( days=1 ) #-only required for glacier retreat (create dummy value here to introduce the variable) #-set date input for reporting self.startYear = sy self.endYear = ey self.spinUpYears = config.getint('TIMING', 'spinupyears') self.simYears = self.endYear - self.startYear - self.spinUpYears + 1 #-set the 2000 julian date number self.julian_date_2000 = 2451545 #-read name of reporting table self.RepTab = config.get('REPORTING', 'RepTab') #-set the option to calculate the fluxes in mm for the upstream area self.mm_rep_FLAG = config.getint('REPORTING', 'mm_rep_FLAG') #-set the option to calculate the fluxes per component in mm for the upstream area pars = [ 'Prec', 'ETa', 'GMelt', 'QSNOW', 'QROOTR', 'QROOTD', 'QRAIN', 'QGLAC', 'QBASE', 'QTOT', 'Seep' ] for i in pars: var = i + '_mm_FLAG' setattr(self, var, config.getint('REPORTING', var)) #-set the option to calculate the timeseries of the water balance self.wbal_TSS_FLAG = config.getint('REPORTING', 'wbal_TSS_FLAG') #-setting clone map self.clonefile = self.inpath + config.get('GENERAL', 'mask') pcr.setclone(self.clonefile) self.clone = pcr.ifthen(pcr.readmap(self.clonefile), pcr.boolean(1)) self.cellArea = pcr.cellvalue(pcr.cellarea(), 1)[0] #-read general maps self.DEM = pcr.readmap(self.inpath + config.get('GENERAL', 'dem')) self.Slope = pcr.readmap(self.inpath + config.get('GENERAL', 'Slope')) self.Locations = pcr.readmap(self.inpath + config.get('GENERAL', 'locations')) #-read soil calibration fractions self.RootFieldFrac = config.getfloat('SOIL_CAL', 'RootFieldFrac') self.RootSatFrac = config.getfloat('SOIL_CAL', 'RootSatFrac') self.RootDryFrac = config.getfloat('SOIL_CAL', 'RootDryFrac') self.RootWiltFrac = config.getfloat('SOIL_CAL', 'RootWiltFrac') self.RootKsatFrac = config.getfloat('SOIL_CAL', 'RootKsatFrac') #-read soil maps #-check for PedotransferFLAG self.PedotransferFLAG = config.getint('PEDOTRANSFER', 'PedotransferFLAG') #-if pedotransfer functions are used read the sand, clay, organic matter and bulk density maps, otherwise read the soil hydraulic properties if self.PedotransferFLAG == 1: import utilities.pedotransfer self.pedotransfer = utilities.pedotransfer del utilities.pedotransfer #-read init processes pedotransfer self.pedotransfer.init(self, pcr, config, np) else: #self.Soil = pcr.readmap(self.inpath + config.get('SOIL','Soil')) self.RootFieldMap = pcr.readmap(self.inpath + config.get( 'SOIL', 'RootFieldMap')) * self.RootFieldFrac self.RootSatMap = pcr.readmap(self.inpath + config.get( 'SOIL', 'RootSatMap')) * self.RootSatFrac self.RootDryMap = pcr.readmap(self.inpath + config.get( 'SOIL', 'RootDryMap')) * self.RootDryFrac self.RootWiltMap = pcr.readmap(self.inpath + config.get( 'SOIL', 'RootWiltMap')) * self.RootWiltFrac self.RootKsat = pcr.readmap(self.inpath + config.get( 'SOIL', 'RootKsat')) * self.RootKsatFrac self.SubSatMap = pcr.readmap(self.inpath + config.get('SOIL', 'SubSatMap')) self.SubFieldMap = pcr.readmap(self.inpath + config.get('SOIL', 'SubFieldMap')) self.SubKsat = pcr.readmap(self.inpath + config.get('SOIL', 'SubKsat')) self.RootDrainVel = self.RootKsat * self.Slope #-Read and set the soil parameters pars = ['CapRiseMax', 'RootDepthFlat', 'SubDepthFlat'] for i in pars: try: setattr(self, i, pcr.readmap(self.inpath + config.get('SOILPARS', i))) except: setattr(self, i, config.getfloat('SOILPARS', i)) # groundwater storage as third storage layer. This is used instead of a fixed bottomflux if self.GroundFLAG == 1: import modules.groundwater self.groundwater = modules.groundwater del modules.groundwater #-read init processes groundwater self.groundwater.init(self, pcr, config) else: # if groundwater module is not used, read seepage and gwl_base self.SeepStatFLAG = config.getint('SOILPARS', 'SeepStatic') if self.SeepStatFLAG == 0: # set the seepage map series self.Seepmaps = self.inpath + config.get('SOILPARS', 'SeePage') else: #-set a static map or value for seepage try: self.SeePage = pcr.readmap( self.inpath + config.get('SOILPARS', 'SeePage')) except: self.SeePage = config.getfloat('SOILPARS', 'SeePage') try: self.GWL_base = pcr.readmap(self.inpath + config.get('SOILPARS', 'GWL_base')) except: self.GWL_base = config.getfloat('SOILPARS', 'GWL_base') self.SubDrainVel = self.SubKsat * self.Slope #-calculate soil properties self.RootField = self.RootFieldMap * self.RootDepthFlat self.RootSat = self.RootSatMap * self.RootDepthFlat self.RootDry = self.RootDryMap * self.RootDepthFlat self.RootWilt = self.RootWiltMap * self.RootDepthFlat self.SubSat = self.SubSatMap * self.SubDepthFlat self.SubField = self.SubFieldMap * self.SubDepthFlat self.RootTT = pcr.max((self.RootSat - self.RootField) / self.RootKsat, 0.0001) self.SubTT = pcr.max((self.SubSat - self.SubField) / self.SubKsat, 0.0001) # soil max and soil min for scaling of gwl if groundwater module is not used if self.GroundFLAG == 0: self.SoilMax = self.RootSat + self.SubSat self.SoilMin = self.RootDry + self.SubField #-read land use map self.LandUse = pcr.readmap(self.inpath + config.get('LANDUSE', 'LandUse')) #-Use the dynamic vegetation module if self.DynVegFLAG == 1: #-import dynamic vegetation module import modules.dynamic_veg self.dynamic_veg = modules.dynamic_veg del modules.dynamic_veg #-read init processes dynamic vegetation self.dynamic_veg.init(self, pcr, config) #-read the crop coefficient table if the dynamic vegetation module is not used else: self.KcStatFLAG = config.getint('LANDUSE', 'KCstatic') if self.KcStatFLAG == 1: #-read land use map and kc table self.kc_table = self.inpath + config.get('LANDUSE', 'CropFac') self.Kc = pcr.lookupscalar(self.kc_table, self.LandUse) else: #-set the kc map series self.Kcmaps = self.inpath + config.get('LANDUSE', 'KC') #-read the p factor table if the plant water stress module is used self.PlantWaterStressFLAG = config.getint('PWS', 'PWS_FLAG') if self.PlantWaterStressFLAG == 1: PFactor = self.inpath + config.get('PWS', 'PFactor') self.PMap = pcr.lookupscalar(PFactor, self.LandUse) #-read and set glacier maps and parameters if glacier module is used if self.GlacFLAG: #-import glacier module import modules.glacier self.glacier = modules.glacier del modules.glacier #-read init processes glacier module self.glacier.init(self, pcr, config, pd, np, os) #-read and set snow maps and parameters if snow modules are used if self.SnowFLAG == 1: #-import snow module import modules.snow self.snow = modules.snow del modules.snow #-read init processes glacier module self.snow.init(self, pcr, config) #-read and set climate forcing and the calculation of etref #-read precipitation data #-read flag for precipitation forcing by netcdf self.precNetcdfFLAG = config.getint('CLIMATE', 'precNetcdfFLAG') if self.precNetcdfFLAG == 1: #-read configuration for forcing by netcdf self.netcdf2PCraster.getConfigNetcdf(self, config, 'Prec', 'CLIMATE') #-determine x,y-coordinates of netcdf file and model domain and indices of netcdf corresponding to model domain self.netcdf2PCraster.netcdf2pcrInit(self, pcr, 'Prec') else: #-read precipitation forcing folder self.Prec = self.inpath + config.get('CLIMATE', 'Prec') #-read precipitation data #-read flag for temperature forcing by netcdf self.tempNetcdfFLAG = config.getint('CLIMATE', 'tempNetcdfFLAG') if self.tempNetcdfFLAG == 1: #-read configuration for forcing by netcdf self.netcdf2PCraster.getConfigNetcdf(self, config, 'Temp', 'CLIMATE') #-determine x,y-coordinates of netcdf file and model domain and indices of netcdf corresponding to model domain self.netcdf2PCraster.netcdf2pcrInit(self, pcr, 'Temp') else: #-read temperature forcing folder self.Tair = self.inpath + config.get('CLIMATE', 'Tair') #-read flag for etref time series input self.ETREF_FLAG = config.getint('ETREF', 'ETREF_FLAG') #-determine the use of a given etref time-series or calculate etref using Hargreaves if self.ETREF_FLAG == 1: self.ETref = self.inpath + config.get('ETREF', 'ETref') else: self.Lat = pcr.readmap(self.inpath + config.get('ETREF', 'Lat')) #-read flag for minimum temperature forcing by netcdf self.TminNetcdfFLAG = config.getint('ETREF', 'TminNetcdfFLAG') if self.TminNetcdfFLAG == 1: #-read configuration for forcing by netcdf self.netcdf2PCraster.getConfigNetcdf(self, config, 'Tmin', 'ETREF') #-determine x,y-coordinates of netcdf file and model domain and indices of netcdf corresponding to model domain self.netcdf2PCraster.netcdf2pcrInit(self, pcr, 'Tmin') else: self.Tmin = self.inpath + config.get('ETREF', 'Tmin') #-read flag for maximum temperature forcing by netcdf self.TmaxNetcdfFLAG = config.getint('ETREF', 'TmaxNetcdfFLAG') if self.TmaxNetcdfFLAG == 1: #-read configuration for forcing by netcdf self.netcdf2PCraster.getConfigNetcdf(self, config, 'Tmax', 'ETREF') #-determine x,y-coordinates of netcdf file and model domain and indices of netcdf corresponding to model domain self.netcdf2PCraster.netcdf2pcrInit(self, pcr, 'Tmax') else: self.Tmax = self.inpath + config.get('ETREF', 'Tmax') self.Gsc = config.getfloat('ETREF', 'Gsc') import hargreaves self.Hargreaves = hargreaves del hargreaves #-read and set routing maps and parameters if self.RoutFLAG == 1: import modules.routing self.routing = modules.routing del modules.routing #-read init processes routing self.routing.init(self, pcr, config) #-read and set routing maps and parameters if self.ResFLAG == 1 or self.LakeFLAG == 1: #-import advanced routing module import modules.advanced_routing self.advanced_routing = modules.advanced_routing del modules.advanced_routing #-read init processes advanced routing self.advanced_routing.init(self, pcr, config) #-read lake maps and parameters if lake module is used if self.LakeFLAG == 1: #-import lakes module import modules.lakes self.lakes = modules.lakes del modules.lakes #-read init processes lakes self.lakes.init(self, pcr, config) #-read reservior maps and parameters if reservoir module is used if self.ResFLAG == 1: #-import reservoirs module import modules.reservoirs self.reservoirs = modules.reservoirs del modules.reservoirs #-read init processes reservoirs self.reservoirs.init(self, pcr, config) #-read flag for calculation of ET in reservoirs self.ETOpenWaterFLAG = config.getint('OPENWATER', 'ETOpenWaterFLAG') if self.ETOpenWaterFLAG == 1: #-read kc value for open water self.kcOpenWater = config.getfloat('OPENWATER', 'kcOpenWater') #-read openwater fraction map self.openWaterFrac = pcr.readmap( self.inpath + config.get('OPENWATER', 'openWaterFrac')) #-determine openwater map with values of each reservoir/lake in the extent of the openwater self.openWater = pcr.ifthenelse(self.openWaterFrac > 0, pcr.scalar(1), pcr.scalar(0)) self.openWaterNominal = pcr.clump(pcr.nominal(self.openWater)) self.openWaterNominal = pcr.nominal( pcr.areamaximum(pcr.scalar(self.ResID), self.openWaterNominal)) else: #-set all cells to 0 for openwater fraction map self.openWaterFrac = self.DEM * 0 self.openWater = 0 self.ETOpenWater = 0 #-read maps and parameters for infiltration excess self.InfilFLAG = config.getfloat('INFILTRATION', 'Infil_excess') if self.InfilFLAG == 1: self.K_eff = config.getfloat('INFILTRATION', 'K_eff') try: self.Alpha = config.getfloat('INFILTRATION', 'Alpha') except: self.Alpha = pcr.readmap(self.inpath + config.get('INFILTRATION', 'Alpha')) try: self.Labda_Infil = config.getfloat('INFILTRATION', 'Labda_infil') except: self.Labda_Infil = pcr.readmap( self.inpath + config.get('INFILTRATION', 'Labda_infil')) try: self.paved_table = self.inpath + config.get( 'INFILTRATION', 'PavedFrac') self.pavedFrac = pcr.lookupscalar(self.paved_table, self.LandUse) except: self.pavedFrac = 0 #-read maps and parameters for soil erosion if self.SedFLAG == 1: #-read soil erosion model selector (1 for MUSLE, 2 for MMF) self.SedModel = config.getfloat('SEDIMENT', 'SedModel') #-read rock fraction map self.RockFrac = pcr.readmap(self.inpath + config.get('SEDIMENT', 'RockFrac')) #-read MUSLE input parameters if self.SedModel == 1: #-import musle module import modules.musle self.musle = modules.musle del modules.musle #-read init processes musle self.musle.init(self, pcr, config) #-read MMF input parameters if self.SedModel == 2: #-import mmf module import modules.mmf self.mmf = modules.mmf del modules.mmf #-read init processes mmf self.mmf.init(self, pcr, config) #-read input parameters for sediment transport if self.SedTransFLAG == 1: #-import sediment transport module import modules.sediment_transport self.sediment_transport = modules.sediment_transport del modules.sediment_transport #-read init processes sediment transport self.sediment_transport.init(self, pcr, config, csv, np) #-set the global option for radians pcr.setglobaloption('radians')
def getReservoirOutflow(self,\ avgChannelDischarge,length_of_time_step,downstreamDemand): # avgOutflow (m3/s) avgOutflow = self.avgOutflow # The following is needed when new lakes/reservoirs introduced (its avgOutflow is still zero). #~ # - alternative 1 #~ avgOutflow = pcr.ifthenelse(\ #~ avgOutflow > 0.,\ #~ avgOutflow, #~ pcr.max(avgChannelDischarge, self.avgInflow, 0.001)) # - alternative 2 avgOutflow = pcr.ifthenelse(\ avgOutflow > 0.,\ avgOutflow, pcr.max(avgChannelDischarge, self.avgInflow)) avgOutflow = pcr.ifthenelse(\ avgOutflow > 0.,\ avgOutflow, pcr.downstream(self.lddMap, avgOutflow)) avgOutflow = pcr.areamaximum(avgOutflow, self.waterBodyIds) # calculate resvOutflow (m2/s) (based on reservoir storage and avgDischarge): # - using reductionFactor in such a way that: # - if relativeCapacity < minResvrFrac : release is terminated # - if relativeCapacity > maxResvrFrac : longterm average reductionFactor = \ pcr.cover(\ pcr.min(1., pcr.max(0., \ self.waterBodyStorage - self.minResvrFrac*self.waterBodyCap)/\ (self.maxResvrFrac - self.minResvrFrac)*self.waterBodyCap),0.0) # resvOutflow = reductionFactor * avgOutflow * length_of_time_step # unit: m3 # maximum release <= average inflow (especially during dry condition) resvOutflow = pcr.max(0, pcr.min(resvOutflow, self.avgInflow * length_of_time_step)) # unit: m3 # downstream demand (m3/s) # reduce demand if storage < lower limit reductionFactor = vos.getValDivZero( downstreamDemand, self.minResvrFrac * self.waterBodyCap, vos.smallNumber) reductionFactor = pcr.cover(reductionFactor, 0.0) downstreamDemand = pcr.min(downstreamDemand, downstreamDemand * reductionFactor) # resvOutflow > downstreamDemand resvOutflow = pcr.max(resvOutflow, downstreamDemand * length_of_time_step) # unit: m3 # floodOutflow: additional release if storage > upper limit ratioQBankfull = 2.3 estmStorage = pcr.max(0., self.waterBodyStorage - resvOutflow) floodOutflow = \ pcr.max(0.0, estmStorage - self.waterBodyCap) +\ pcr.cover(\ pcr.max(0.0, estmStorage - self.maxResvrFrac*\ self.waterBodyCap)/\ ((1.-self.maxResvrFrac)*self.waterBodyCap),0.0)*\ pcr.max(0.0,ratioQBankfull*avgOutflow* vos.secondsPerDay()-\ resvOutflow) floodOutflow = pcr.max(0.0, pcr.min(floodOutflow,\ estmStorage - self.maxResvrFrac*\ self.waterBodyCap*0.75)) # maximum limit of floodOutflow: bring the reservoir storages only to 3/4 of upper limit capacities # update resvOutflow after floodOutflow resvOutflow = pcr.cover(resvOutflow , 0.0) +\ pcr.cover(floodOutflow, 0.0) # maximum release if storage > upper limit : bring the reservoir storages only to 3/4 of upper limit capacities resvOutflow = pcr.ifthenelse(self.waterBodyStorage > self.maxResvrFrac*self.waterBodyCap,\ pcr.min(resvOutflow,\ pcr.max(0,self.waterBodyStorage - \ self.maxResvrFrac*self.waterBodyCap*0.75)), resvOutflow) # if storage > upper limit : resvOutflow > avgInflow resvOutflow = pcr.ifthenelse(self.waterBodyStorage > self.maxResvrFrac*self.waterBodyCap,\ pcr.max(0.0, resvOutflow, self.avgInflow), resvOutflow) # resvOutflow < waterBodyStorage resvOutflow = pcr.min(self.waterBodyStorage, resvOutflow) resvOutflow = pcr.ifthen( pcr.scalar(self.waterBodyIds) > 0., resvOutflow) resvOutflow = pcr.ifthen( pcr.scalar(self.waterBodyTyp) == 2, resvOutflow) return (resvOutflow) # unit: m3
def getParameterFiles(self,currTimeStep,cellArea,ldd,\ initial_condition_dictionary = None,\ currTimeStepInDateTimeFormat = False): # parameters for Water Bodies: fracWat # waterBodyIds # waterBodyOut # waterBodyArea # waterBodyTyp # waterBodyCap # cell surface area (m2) and ldd self.cellArea = cellArea ldd = pcr.ifthen(self.landmask, ldd) # date used for accessing/extracting water body information if currTimeStepInDateTimeFormat: date_used = currTimeStep year_used = currTimeStep.year else: date_used = currTimeStep.fulldate year_used = currTimeStep.year if self.onlyNaturalWaterBodies == True: date_used = self.dateForNaturalCondition year_used = self.dateForNaturalCondition[0:4] # fracWat = fraction of surface water bodies (dimensionless) self.fracWat = pcr.scalar(0.0) if self.useNetCDF: self.fracWat = vos.netcdf2PCRobjClone(self.ncFileInp,'fracWaterInp', \ date_used, useDoy = 'yearly',\ cloneMapFileName = self.cloneMap) else: self.fracWat = vos.readPCRmapClone(\ self.fracWaterInp+str(year_used)+".map", self.cloneMap,self.tmpDir,self.inputDir) self.fracWat = pcr.cover(self.fracWat, 0.0) self.fracWat = pcr.max(0.0, self.fracWat) self.fracWat = pcr.min(1.0, self.fracWat) self.waterBodyIds = pcr.nominal(0) # waterBody ids self.waterBodyOut = pcr.boolean(0) # waterBody outlets self.waterBodyArea = pcr.scalar(0.) # waterBody surface areas # water body ids if self.useNetCDF: self.waterBodyIds = vos.netcdf2PCRobjClone(self.ncFileInp,'waterBodyIds', \ date_used, useDoy = 'yearly',\ cloneMapFileName = self.cloneMap) else: self.waterBodyIds = vos.readPCRmapClone(\ self.waterBodyIdsInp+str(year_used)+".map",\ self.cloneMap,self.tmpDir,self.inputDir,False,None,True) # self.waterBodyIds = pcr.ifthen(\ pcr.scalar(self.waterBodyIds) > 0.,\ pcr.nominal(self.waterBodyIds)) # water body outlets (correcting outlet positions) wbCatchment = pcr.catchmenttotal(pcr.scalar(1), ldd) self.waterBodyOut = pcr.ifthen(wbCatchment ==\ pcr.areamaximum(wbCatchment, \ self.waterBodyIds),\ self.waterBodyIds) # = outlet ids # This may give more than two outlets, particularly if there are more than one cells that have largest upstream areas # - make sure that there is only one outlet for each water body self.waterBodyOut = pcr.ifthen(\ pcr.areaorder(pcr.scalar(self.waterBodyOut), \ self.waterBodyOut) == 1., self.waterBodyOut) self.waterBodyOut = pcr.ifthen(\ pcr.scalar(self.waterBodyIds) > 0.,\ self.waterBodyOut) # TODO: Please also consider endorheic lakes! # correcting water body ids self.waterBodyIds = pcr.ifthen(\ pcr.scalar(self.waterBodyIds) > 0.,\ pcr.subcatchment(ldd,self.waterBodyOut)) # boolean map for water body outlets: self.waterBodyOut = pcr.ifthen(\ pcr.scalar(self.waterBodyOut) > 0.,\ pcr.boolean(1)) # reservoir surface area (m2): if self.useNetCDF: resSfArea = 1000. * 1000. * \ vos.netcdf2PCRobjClone(self.ncFileInp,'resSfAreaInp', \ date_used, useDoy = 'yearly',\ cloneMapFileName = self.cloneMap) else: resSfArea = 1000. * 1000. * vos.readPCRmapClone( self.resSfAreaInp+str(year_used)+".map",\ self.cloneMap,self.tmpDir,self.inputDir) resSfArea = pcr.areaaverage(resSfArea, self.waterBodyIds) resSfArea = pcr.cover(resSfArea, 0.) # water body surface area (m2): (lakes and reservoirs) self.waterBodyArea = pcr.max(pcr.areatotal(\ pcr.cover(\ self.fracWat*self.cellArea, 0.0), self.waterBodyIds), pcr.areaaverage(\ pcr.cover(resSfArea, 0.0) , self.waterBodyIds)) self.waterBodyArea = pcr.ifthen(self.waterBodyArea > 0.,\ self.waterBodyArea) # correcting water body ids and outlets (exclude all water bodies with surfaceArea = 0) self.waterBodyIds = pcr.ifthen(self.waterBodyArea > 0., self.waterBodyIds) self.waterBodyOut = pcr.ifthen(pcr.boolean(self.waterBodyIds), self.waterBodyOut) # water body types: # - 2 = reservoirs (regulated discharge) # - 1 = lakes (weirFormula) # - 0 = non lakes or reservoirs (e.g. wetland) self.waterBodyTyp = pcr.nominal(0) if self.useNetCDF: self.waterBodyTyp = vos.netcdf2PCRobjClone(self.ncFileInp,'waterBodyTyp', \ date_used, useDoy = 'yearly',\ cloneMapFileName = self.cloneMap) else: self.waterBodyTyp = vos.readPCRmapClone( self.waterBodyTypInp+str(year_used)+".map",\ self.cloneMap,self.tmpDir,self.inputDir,False,None,True) # excluding wetlands (waterBodyTyp = 0) in all functions related to lakes/reservoirs # self.waterBodyTyp = pcr.ifthen(\ pcr.scalar(self.waterBodyTyp) > 0,\ pcr.nominal(self.waterBodyTyp)) self.waterBodyTyp = pcr.ifthen(\ pcr.scalar(self.waterBodyIds) > 0,\ pcr.nominal(self.waterBodyTyp)) self.waterBodyTyp = pcr.areamajority(self.waterBodyTyp,\ self.waterBodyIds) # choose only one type: either lake or reservoir self.waterBodyTyp = pcr.ifthen(\ pcr.scalar(self.waterBodyTyp) > 0,\ pcr.nominal(self.waterBodyTyp)) self.waterBodyTyp = pcr.ifthen(pcr.boolean(self.waterBodyIds), self.waterBodyTyp) # correcting lakes and reservoirs ids and outlets self.waterBodyIds = pcr.ifthen( pcr.scalar(self.waterBodyTyp) > 0, self.waterBodyIds) self.waterBodyOut = pcr.ifthen( pcr.scalar(self.waterBodyIds) > 0, self.waterBodyOut) # reservoir maximum capacity (m3): self.resMaxCap = pcr.scalar(0.0) self.waterBodyCap = pcr.scalar(0.0) if self.useNetCDF: self.resMaxCap = 1000. * 1000. * \ vos.netcdf2PCRobjClone(self.ncFileInp,'resMaxCapInp', \ date_used, useDoy = 'yearly',\ cloneMapFileName = self.cloneMap) else: self.resMaxCap = 1000. * 1000. * vos.readPCRmapClone(\ self.resMaxCapInp+str(year_used)+".map", \ self.cloneMap,self.tmpDir,self.inputDir) self.resMaxCap = pcr.ifthen(self.resMaxCap > 0,\ self.resMaxCap) self.resMaxCap = pcr.areaaverage(self.resMaxCap,\ self.waterBodyIds) # water body capacity (m3): (lakes and reservoirs) self.waterBodyCap = pcr.cover( self.resMaxCap, 0.0) # Note: Most of lakes have capacities > 0. self.waterBodyCap = pcr.ifthen(pcr.boolean(self.waterBodyIds), self.waterBodyCap) # correcting water body types: # Reservoirs that have zero capacities will be assumed as lakes. self.waterBodyTyp = \ pcr.ifthen(pcr.scalar(self.waterBodyTyp) > 0.,\ self.waterBodyTyp) self.waterBodyTyp = pcr.ifthenelse(self.waterBodyCap > 0.,\ self.waterBodyTyp,\ pcr.ifthenelse(pcr.scalar(self.waterBodyTyp) == 2,\ pcr.nominal(1),\ self.waterBodyTyp)) # final corrections: self.waterBodyTyp = pcr.ifthen(self.waterBodyArea > 0.,\ self.waterBodyTyp) # make sure that all lakes and/or reservoirs have surface areas self.waterBodyTyp = \ pcr.ifthen(pcr.scalar(self.waterBodyTyp) > 0.,\ self.waterBodyTyp) # make sure that only types 1 and 2 will be considered in lake/reservoir functions self.waterBodyIds = pcr.ifthen(pcr.scalar(self.waterBodyTyp) > 0.,\ self.waterBodyIds) # make sure that all lakes and/or reservoirs have ids self.waterBodyOut = pcr.ifthen(pcr.scalar(self.waterBodyIds) > 0.,\ self.waterBodyOut) # make sure that all lakes and/or reservoirs have outlets # for a natural run (self.onlyNaturalWaterBodies == True) # which uses only the year 1900, assume all reservoirs are lakes if self.onlyNaturalWaterBodies == True and date_used == self.dateForNaturalCondition: logger.info( "Using only natural water bodies identified in the year 1900. All reservoirs in 1900 are assumed as lakes." ) self.waterBodyTyp = \ pcr.ifthen(pcr.scalar(self.waterBodyTyp) > 0.,\ pcr.nominal(1)) # check that all lakes and/or reservoirs have types, ids, surface areas and outlets: test = pcr.defined(self.waterBodyTyp) & pcr.defined(self.waterBodyArea) &\ pcr.defined(self.waterBodyIds) & pcr.boolean(pcr.areamaximum(pcr.scalar(self.waterBodyOut), self.waterBodyIds)) a, b, c = vos.getMinMaxMean( pcr.cover(pcr.scalar(test), 1.0) - pcr.scalar(1.0)) threshold = 1e-3 if abs(a) > threshold or abs(b) > threshold: logger.warning( "Missing information in some lakes and/or reservoirs.") # at the beginning of simulation period (timeStepPCR = 1) # - we have to define/get the initial conditions # if initial_condition_dictionary != None and currTimeStep.timeStepPCR == 1: self.getICs(initial_condition_dictionary) # For each new reservoir (introduced at the beginning of the year) # initiating storage, average inflow and outflow # PS: THIS IS NOT NEEDED FOR OFFLINE MODFLOW RUN! # try: self.waterBodyStorage = pcr.cover(self.waterBodyStorage, 0.0) self.avgInflow = pcr.cover(self.avgInflow, 0.0) self.avgOutflow = pcr.cover(self.avgOutflow, 0.0) self.waterBodyStorage = pcr.ifthen(self.landmask, self.waterBodyStorage) self.avgInflow = pcr.ifthen(self.landmask, self.avgInflow) self.avgOutflow = pcr.ifthen(self.landmask, self.avgOutflow) except: # PS: FOR OFFLINE MODFLOW RUN! pass # TODO: Remove try and except # cropping only in the landmask region: self.fracWat = pcr.ifthen(self.landmask, self.fracWat) self.waterBodyIds = pcr.ifthen(self.landmask, self.waterBodyIds) self.waterBodyOut = pcr.ifthen(self.landmask, self.waterBodyOut) self.waterBodyArea = pcr.ifthen(self.landmask, self.waterBodyArea) self.waterBodyTyp = pcr.ifthen(self.landmask, self.waterBodyTyp) self.waterBodyCap = pcr.ifthen(self.landmask, self.waterBodyCap)
def initial(self): """ initial part of the water abstraction module """ # self.testmap=windowaverage(self.var.Elevation,5) # self.report(self.testmap,"test.map") # ************************************************************ # ***** WATER USE # ************************************************************ settings = LisSettings.instance() option = settings.options binding = settings.binding maskinfo = MaskInfo.instance() if option['wateruse']: self.var.WUsePercRemain = loadmap('WUsePercRemain') self.var.NoWaterUseSteps = int(loadmap('maxNoWateruse')) self.var.GroundwaterBodies = loadmap('GroundwaterBodies') self.var.FractionGroundwaterUsed = np.minimum( np.maximum(loadmap('FractionGroundwaterUsed'), maskinfo.in_zero()), 1.0) self.var.FractionNonConventionalWaterUsed = loadmap( 'FractionNonConventionalWaterUsed') self.var.FractionLakeReservoirWaterUsed = loadmap( 'FractionLakeReservoirWaterUsed') self.var.EFlowThreshold = loadmap('EFlowThreshold') # EFlowThreshold is map with m3/s discharge, e.g. the 10th percentile discharge of the baseline run self.var.WUseRegionC = loadmap('WUseRegion').astype(int) self.var.IrrigationMult = loadmap('IrrigationMult') # ************************************************************ # ***** water use constant maps ****************************** # ************************************************************ self.var.IndustryConsumptiveUseFraction = loadmap( 'IndustryConsumptiveUseFraction') # fraction (0-1) self.var.WaterReUseFraction = loadmap('WaterReUseFraction') # fraction of water re-used (0-1) self.var.EnergyConsumptiveUseFraction = loadmap( 'EnergyConsumptiveUseFraction') # fraction (0-1), value depends on cooling technology of power plants self.var.LivestockConsumptiveUseFraction = loadmap( 'LivestockConsumptiveUseFraction') # fraction (0-1) self.var.LeakageFraction = np.minimum( np.maximum( loadmap('LeakageFraction') * (1 - loadmap('LeakageReductionFraction')), maskinfo.in_zero()), 1.0) self.var.DomesticLeakageConstant = np.minimum( np.maximum(1 / (1 - self.var.LeakageFraction), maskinfo.in_zero()), 1.0) # Domestic Water Abstraction becomes larger in case of leakage # LeakageFraction is LeakageFraction (0-1) multiplied by reduction scenario (10% reduction is 0.1 in map) # 0.65 leakage and 0.1 reduction leads to 0.585 effective leakage, resulting in 2.41 times more water abstraction self.var.DomesticWaterSavingConstant = np.minimum( np.maximum(1 - loadmap('WaterSavingFraction'), maskinfo.in_zero()), 1.0) # Domestic water saving if in place, changes this value from 1 to a value between 0 and 1, and will reduce demand and abstraction # so value = 0.9 if WaterSavingFraction equals 0.1 (10%) self.var.DomesticConsumptiveUseFraction = loadmap( 'DomesticConsumptiveUseFraction') # fraction (0-1), typically rather low ~ 0.10 self.var.LeakageWaterLossFraction = loadmap('LeakageWaterLoss') # fraction (0-1), 0=no leakage # Initialize water demand. Read from a static map either value or pcraster map or netcdf (single or stack). # If reading from NetCDF stack, get time step corresponding to model step. # Added management for sub-daily modelling time steps # Added possibility to use one single average year to be repeated during the simulation if option['useWaterDemandAveYear']: # CM: using one water demand average year throughout the model simulation self.var.DomesticDemandMM = loadmap( 'DomesticDemandMaps', timestampflag='closest', averageyearflag=True) * self.var.DtDay self.var.IndustrialDemandMM = loadmap( 'IndustrialDemandMaps', timestampflag='closest', averageyearflag=True) * self.var.DtDay self.var.LivestockDemandMM = loadmap( 'LivestockDemandMaps', timestampflag='closest', averageyearflag=True) * self.var.DtDay self.var.EnergyDemandMM = loadmap( 'EnergyDemandMaps', timestampflag='closest', averageyearflag=True) * self.var.DtDay else: # CM: using information on water demand from NetCDF files self.var.DomesticDemandMM = loadmap( 'DomesticDemandMaps', timestampflag='closest') * self.var.DtDay self.var.IndustrialDemandMM = loadmap( 'IndustrialDemandMaps', timestampflag='closest') * self.var.DtDay self.var.LivestockDemandMM = loadmap( 'LivestockDemandMaps', timestampflag='closest') * self.var.DtDay self.var.EnergyDemandMM = loadmap( 'EnergyDemandMaps', timestampflag='closest') * self.var.DtDay # Check consistency with the reference calendar that is read from the precipitation forcing file (global_modules.zusatz.optionBinding) if option['TransientWaterDemandChange'] and option[ 'readNetcdfStack']: for k in ('DomesticDemandMaps', 'IndustrialDemandMaps', 'LivestockDemandMaps', 'EnergyDemandMaps'): with Dataset(binding[k] + '.nc') as nc: cal_type = get_calendar_type(nc) if cal_type != binding['calendar_type']: warnings.warn( calendar_inconsistency_warning( binding[k], cal_type, binding['calendar_type'])) if option['groundwaterSmooth']: self.var.GroundwaterBodiesPcr = decompress( self.var.GroundwaterBodies) self.var.groundwaterCatch = boolean( decompress((self.var.GroundwaterBodies * self.var.Catchments).astype(int))) # nominal(scalar(GroundwaterBodies)*scalar(self.var.Catchments)); # smoothing for groundwater to correct error by using windowtotal, based on groundwater bodies and catchments self.var.LZSmoothRange = loadmap('LZSmoothRange') if option['wateruseRegion']: WUseRegion = nominal(loadmap('WUseRegion', pcr=True)) pitWuse1 = ifthen(self.var.AtLastPoint != 0, boolean(1)) pitWuse1b = ifthen(defined(pitWuse1), WUseRegion) # use every existing pit in the Ldd and number them by the water regions # coastal water regions can have more than one pit per water region pitWuseMax = areamaximum(self.var.UpArea, WUseRegion) pitWuse2 = ifthen(pitWuseMax == self.var.UpArea, WUseRegion) # search outlets in the inland water regions by using the maximum upstream area as criterium pitWuse3 = downstream(self.var.LddStructuresKinematic, WUseRegion) pitWuse3b = ifthen(pitWuse3 != WUseRegion, WUseRegion) # search point where ldd leaves a water region pitWuse = cover(pitWuse1b, pitWuse2, pitWuse3b, nominal(0)) # join all sources of pits LddWaterRegion = lddrepair( ifthenelse(pitWuse == 0, self.var.LddStructuresKinematic, 5)) # create a Ldd with pits at every water region outlet # this results in a interrupted ldd, so water cannot be transfered to the next water region lddC = compressArray(LddWaterRegion) inAr = decompress( np.arange(maskinfo.info.mapC[0], dtype="int32")) # giving a number to each non missing pixel as id self.var.downWRegion = (compressArray( downstream(LddWaterRegion, inAr))).astype(np.int32) # each upstream pixel gets the id of the downstream pixel self.var.downWRegion[lddC == 5] = maskinfo.info.mapC[0] # all pits gets a high number # ************************************************************ # ***** OUTFLOW AND INFLOW POINTS FOR WATER REGIONS ********** # ************************************************************ self.var.WaterRegionOutflowPoints = ifthen( pitWuse != 0, boolean(1)) # outflowpoints to calculate upstream inflow for balances and Water Exploitation Index # both inland outflowpoints to downstream subbasin, and coastal outlets WaterRegionInflow1 = boolean( upstream( self.var.LddStructuresKinematic, cover(scalar(self.var.WaterRegionOutflowPoints), 0))) self.var.WaterRegionInflowPoints = ifthen( WaterRegionInflow1, boolean(1)) # inflowpoints to calculate upstream inflow for balances and Water Exploitation Index else: self.var.downWRegion = self.var.downstruct.copy() self.var.downWRegion = self.var.downWRegion.astype(np.int32) # ************************************************************ # ***** Initialising cumulative output variables ************* # ************************************************************ # These are all needed to compute the cumulative mass balance error self.var.wateruseCum = maskinfo.in_zero() # water use cumulated amount self.var.WUseAddM3Dt = maskinfo.in_zero() self.var.WUseAddM3 = maskinfo.in_zero() self.var.IrriLossCUM = maskinfo.in_zero() # Cumulative irrigation loss [mm] # Cumulative abstraction from surface water [mm] self.var.TotalAbstractionFromSurfaceWaterM3 = maskinfo.in_zero() self.var.TotalAbstractionFromGroundwaterM3 = maskinfo.in_zero() self.var.TotalIrrigationAbstractionM3 = maskinfo.in_zero() self.var.TotalPaddyRiceIrrigationAbstractionM3 = maskinfo.in_zero() self.var.TotalLivestockAbstractionM3 = maskinfo.in_zero() self.var.IrrigationType = loadmap('IrrigationType') self.var.IrrigationEfficiency = loadmap('IrrigationEfficiency') self.var.ConveyanceEfficiency = loadmap('ConveyanceEfficiency') self.var.GroundwaterRegionPixels = np.take( np.bincount(self.var.WUseRegionC, weights=self.var.GroundwaterBodies), self.var.WUseRegionC) self.var.AllRegionPixels = np.take( np.bincount(self.var.WUseRegionC, weights=self.var.GroundwaterBodies * 0.0 + 1.0), self.var.WUseRegionC) self.var.RatioGroundWaterUse = self.var.AllRegionPixels / ( self.var.GroundwaterRegionPixels + 0.01) self.var.FractionGroundwaterUsed = np.minimum( self.var.FractionGroundwaterUsed * self.var.RatioGroundWaterUse, 1 - self.var.FractionNonConventionalWaterUsed) # FractionGroundwaterUsed is a percentage given at national scale # since the water needs to come from the GroundwaterBodies pixels, # the fraction needs correction for the non-Groundwaterbodies; this is done here self.var.EFlowIndicator = maskinfo.in_zero() self.var.ReservoirAbstractionM3 = maskinfo.in_zero() self.var.PotentialSurfaceWaterAvailabilityForIrrigationM3 = maskinfo.in_zero( ) self.var.LakeAbstractionM3 = maskinfo.in_zero() self.var.FractionAbstractedFromChannels = maskinfo.in_zero() self.var.AreatotalIrrigationUseM3 = maskinfo.in_zero() self.var.totalAddM3 = maskinfo.in_zero() self.var.TotalDemandM3 = maskinfo.in_zero()
def dynamic(self): ##################### # * dynamic section # ##################### #-evaluation of the current date: return current month and the time step used #-reading in fluxes over land and water area for current time step [m/d] # and read in reservoir demand and surface water extraction [m3] try: self.landSurfaceQ = clippedRead.get( pcrm.generateNameT(landSurfaceQFileName, self.currentTimeStep())) except: pass try: self.potWaterSurfaceQ = clippedRead.get( pcrm.generateNameT(waterSurfaceQFileName, self.currentTimeStep())) except: pass #-surface water extraction and reservoir demand currently set to zero, should # be computed automatically and updated to reservoirs self.potSurfaceWaterExtraction = pcr.spatial(pcr.scalar(0.)) #self.waterBodies.demand= #self.reservoirDemandTSS.assignID(self.waterBodies.ID,self.currentTimeStep(),0.)*self.timeSec #-initialization of cumulative values of actual water extractions self.actWaterSurfaceQ = pcr.spatial(pcr.scalar(0.)) self.actSurfaceWaterExtraction = pcr.spatial(pcr.scalar(0.)) #-definition of sub-loop for routing scheme - explicit scheme has to satisfy Courant condition timeLimit= pcr.cellvalue(pcr.mapminimum((pcr.cover(pcr.ifthen(self.waterBodies.distribution == 0,\ self.channelLength/self.flowVelocity),\ self.timeSec/self.nrIterDefault)*self.timeSec/self.nrIterDefault)**0.5),1)[0] nrIter = int(self.timeSec / timeLimit) nrIter = min(nrIter, int(self.timeSec / 300.)) while float(self.timeSec / nrIter) % 1 <> 0: nrIter += 1 deltaTime = self.timeSec / nrIter #-sub-loop for current time step if self.currentDate.day == 1 or nrIter >= 24: print '\n*\tprocessing %s, currently using %d substeps of %d seconds\n' % \ (self.currentDate.date(),nrIter,deltaTime) #-update discharge and storage for nrICur in range(nrIter): #-initializing discharge for the current sub-timestep and fill in values # for channels and at outlets of waterbodies # * channels * estQ= pcr.ifthenelse((self.actualStorage > 0.) & (self.waterBodies.distribution == 0) ,\ (self.wettedArea/self.alphaQ)**(1./self.betaQ),0.) #estQ= pcr.ifthenelse((self.actualStorage > 0.) & (self.waterBodies.distribution == 0) ,\ #0.5*(self.Q+(self.wettedArea/self.alphaQ)**(1./self.betaQ)),0.) #estQ= pcr.min(estQ,self.actualStorage/deltaTime) self.report(estQ, 'results/qest') self.Q = pcr.spatial(pcr.scalar(0.)) self.Q= pcr.ifthenelse(self.waterBodies.distribution == 0,\ pcr.kinematic(self.channelLDD,estQ,0.,self.alphaQ,\ self.betaQ,1,deltaTime,self.channelLength),self.Q) # * water bodies * self.waterBodies.dischargeUpdate() self.Q = self.waterBodies.returnMapValue(self.Q, self.waterBodies.actualQ) #-fluxes and resulting change in storage: first the local fluxes are evaluated # and aggregated over the water bodies where applicable; this includes the specific runoff [m/day/m2] # from input and the estimated extraction from surface water as volume per day [m3/day]; # specific runoff from the land surface is always positive whereas the fluxes over the water surface # are potential, including discharge, and are adjusted to match the availabe storage; to this end, # surface water storage and fluxes over water bodies are totalized and assigned to the outlet; # discharge is updated in a separate step, after vertical fluxes are compared to the actual storage deltaActualStorage= ((self.landFraction*self.landSurfaceQ+\ self.waterFraction*self.potWaterSurfaceQ)*self.cellArea-\ self.potSurfaceWaterExtraction)*float(self.duration)/nrIter deltaActualStorage= pcr.ifthenelse(self.waterBodies.distribution != 0,\ pcr.ifthenelse(self.waterBodies.location != 0,\ pcr.areatotal(deltaActualStorage,self.waterBodies.distribution),0),\ deltaActualStorage) adjustmentRatio= pcr.ifthenelse(deltaActualStorage < 0.,\ pcr.min(1.,-self.actualStorage/deltaActualStorage),1.) self.actWaterSurfaceQ += adjustmentRatio * self.potWaterSurfaceQ self.actSurfaceWaterExtraction += adjustmentRatio * self.actSurfaceWaterExtraction deltaActualStorage *= adjustmentRatio #-local water balance check if testLocalWaterBalance: differenceActualStorage = self.actualStorage differenceActualStorage += deltaActualStorage #-overall water balance check: net input self.cumulativeDeltaStorage += pcr.catchmenttotal( deltaActualStorage, self.LDD) #-update storage first with local changes, then balance discharge with storage and update storage # with lateral flow and return value to water bodies self.actualStorage += deltaActualStorage self.actualStorage = pcr.max(0., self.actualStorage) self.Q = pcr.min(self.Q, self.actualStorage / deltaTime) deltaActualStorage = (-self.Q + pcr.upstream(self.LDD, self.Q)) * deltaTime deltaActualStorage= pcr.ifthenelse(self.waterBodies.distribution != 0,\ pcr.ifthenelse(self.waterBodies.location != 0,\ pcr.areatotal(deltaActualStorage,self.waterBodies.distribution),0),\ deltaActualStorage) self.actualStorage += deltaActualStorage self.actualStorage = pcr.max(0., self.actualStorage) self.waterBodies.actualStorage = self.waterBodies.retrieveMapValue( self.actualStorage) #-flooded fraction returned floodedFraction,floodedDepth,\ self.wettedArea,self.alphaQ= self.kinAlphaComposite(self.actualStorage,self.floodplainMask) self.wettedArea= self.waterBodies.returnMapValue(self.wettedArea,\ self.waterBodies.channelWidth+2.*self.waterBodies.updateWaterHeight()) self.waterFraction= pcr.ifthenelse(self.waterBodies.distribution == 0,\ pcr.max(self.waterFractionMask,floodedFraction),self.waterFractionMask) self.landFraction = pcr.max(0., 1. - self.waterFraction) self.flowVelocity = pcr.ifthenelse(self.wettedArea > 0, self.Q / self.wettedArea, 0.) #-local water balance check if testLocalWaterBalance: differenceActualStorage += deltaActualStorage differenceActualStorage -= self.actualStorage totalDifference = pcr.cellvalue( pcr.maptotal(differenceActualStorage), 1)[0] minimumDifference = pcr.cellvalue( pcr.mapminimum(differenceActualStorage), 1)[0] maximumDifference = pcr.cellvalue( pcr.mapmaximum(differenceActualStorage), 1)[0] if abs(totalDifference) > 1.e-3: print 'water balance error: total %e; min %e; max %e' %\ (totalDifference,minimumDifference,maximumDifference) if reportLocalWaterBalance: pcr.report(differenceActualStorage, 'mbe_%s.map' % self.currentDate.date()) #-overall water balance check: updating cumulative discharge and total storage [m3] self.totalDischarge += self.Q * deltaTime self.totalStorage = pcr.catchmenttotal(self.actualStorage, self.LDD) #-check on occurrence of last day and report mass balance if self.currentDate == self.endDate: #-report initial maps pcr.report(self.Q, self.QIniMap) pcr.report(self.actualStorage, self.actualStorageIniMap) #-return relative and absolute water balance error per cell and # as total at basin outlets self.totalDischarge= pcr.ifthen((self.waterBodies.distribution == 0) | \ (self.waterBodies.location != 0),self.totalDischarge) self.cumulativeDeltaStorage= pcr.ifthen((self.waterBodies.distribution == 0) | \ (self.waterBodies.location != 0),self.cumulativeDeltaStorage) massBalanceError= self.totalStorage+self.totalDischarge-\ self.cumulativeDeltaStorage relMassBalanceError = 1. + pcr.ifthenelse( self.cumulativeDeltaStorage <> 0., massBalanceError / self.cumulativeDeltaStorage, 0.) totalMassBalanceError= pcr.cellvalue(pcr.maptotal(pcr.ifthen(self.basinOutlet,\ massBalanceError)),1)[0] totalCumulativeDeltaStorage= pcr.cellvalue(pcr.maptotal(pcr.ifthen(self.basinOutlet,\ self.cumulativeDeltaStorage)),1)[0] if totalCumulativeDeltaStorage > 0: totalRelativeMassBalanceError = 1. + totalMassBalanceError / totalCumulativeDeltaStorage else: totalRelativeMassBalanceError = 1. #-report maps and echo value pcr.report(massBalanceError, mbeFileName) pcr.report(relMassBalanceError, mbrFileName) print '\n*\ttotal global mass balance error [m3]: %8.3g' % totalMassBalanceError print '\n*\trelative global mass balance error [-]: %5.3f' % totalRelativeMassBalanceError #-echo to screen: total mass balance error and completion of run print '\trun completed' #-end of day: return states and fluxes #-get surface water attributes? if getSurfaceWaterAttributes: #-compute the following secondary variables: # surface water area [m2]: area given dynamic surface water fraction # residence time [days]: volume over discharge, assigned -1 in case discharge is zero # surface water depth [m], weighed by channel and floodplain volume surfaceWaterArea = self.waterFraction * self.cellArea surfaceWaterArea= pcr.ifthenelse(self.waterBodies.distribution != 0,\ pcr.ifthenelse(self.waterBodies.location != 0,\ pcr.areatotal(surfaceWaterArea,self.waterBodies.distribution),0),\ surfaceWaterArea) surfaceWaterResidenceTime = pcr.ifthenelse( self.Q > 0., self.actualStorage / (self.Q * self.timeSec), -1) surfaceWaterDepth= pcr.ifthenelse(self.actualStorage > 0.,\ pcr.max(0.,self.actualStorage-self.channelStorageCapacity)**2/\ (self.actualStorage*surfaceWaterArea),0.) surfaceWaterDepth+= pcr.ifthenelse(self.actualStorage > 0.,\ pcr.min(self.channelStorageCapacity,self.actualStorage)**2/(self.waterFractionMask*\ self.cellArea*self.actualStorage),0.) #-reports: values at outlet of lakes or reservoirs are assigned to their full extent self.report(pcr.ifthenelse(self.waterBodies.distribution != 0,\ pcr.areamaximum(surfaceWaterArea,self.waterBodies.distribution),surfaceWaterArea),\ surfaceWaterAreaFileName) self.report(pcr.ifthenelse(self.waterBodies.distribution != 0,\ pcr.areamaximum(surfaceWaterResidenceTime,self.waterBodies.distribution),surfaceWaterResidenceTime),\ surfaceWaterResidenceTimeFileName) self.report(pcr.ifthenelse(self.waterBodies.distribution != 0,\ pcr.areamaximum(surfaceWaterDepth,self.waterBodies.distribution),surfaceWaterDepth),\ surfaceWaterDepthFileName) #-reports on standard output: values at outlet of lakes or reservoirs are assigned to their full extent self.report( pcr.ifthenelse( self.waterBodies.distribution != 0, pcr.areamaximum(self.flowVelocity, self.waterBodies.distribution), self.flowVelocity), flowVelocityFileName) self.report( pcr.ifthenelse( self.waterBodies.distribution != 0, pcr.areamaximum(self.Q, self.waterBodies.distribution), self.Q), QFileName) self.report(pcr.ifthenelse(self.waterBodies.distribution == 0,\ floodedFraction,0.),floodedFractionFileName) self.report(pcr.ifthenelse(self.waterBodies.distribution == 0,\ floodedDepth,0.),floodedDepthFileName) self.report(self.actualStorage, actualStorageFileName) #-update date for time step and report relevant daily output self.currentDate = self.currentDate + datetime.timedelta(self.duration)
def dynamic(self): ##################### # * dynamic section # ##################### #-evaluation of the current date: return current month and the time step used #-reading in fluxes over land and water area for current time step [m/d] # and read in reservoir demand and surface water extraction [m3] try: self.landSurfaceQ= clippedRead.get(pcrm.generateNameT(landSurfaceQFileName,self.currentTimeStep())) except: pass try: self.potWaterSurfaceQ= clippedRead.get(pcrm.generateNameT(waterSurfaceQFileName,self.currentTimeStep())) except: pass #-surface water extraction and reservoir demand currently set to zero, should # be computed automatically and updated to reservoirs self.potSurfaceWaterExtraction= pcr.spatial(pcr.scalar(0.)) #self.waterBodies.demand= #self.reservoirDemandTSS.assignID(self.waterBodies.ID,self.currentTimeStep(),0.)*self.timeSec #-initialization of cumulative values of actual water extractions self.actWaterSurfaceQ= pcr.spatial(pcr.scalar(0.)) self.actSurfaceWaterExtraction= pcr.spatial(pcr.scalar(0.)) #-definition of sub-loop for routing scheme - explicit scheme has to satisfy Courant condition timeLimit= pcr.cellvalue(pcr.mapminimum((pcr.cover(pcr.ifthen(self.waterBodies.distribution == 0,\ self.channelLength/self.flowVelocity),\ self.timeSec/self.nrIterDefault)*self.timeSec/self.nrIterDefault)**0.5),1)[0] nrIter= int(self.timeSec/timeLimit) nrIter= min(nrIter,int(self.timeSec/300.)) while float(self.timeSec/nrIter) % 1 <> 0: nrIter+= 1 deltaTime= self.timeSec/nrIter #-sub-loop for current time step if self.currentDate.day == 1 or nrIter >= 24: print '\n*\tprocessing %s, currently using %d substeps of %d seconds\n' % \ (self.currentDate.date(),nrIter,deltaTime) #-update discharge and storage for nrICur in range(nrIter): #-initializing discharge for the current sub-timestep and fill in values # for channels and at outlets of waterbodies # * channels * estQ= pcr.ifthenelse((self.actualStorage > 0.) & (self.waterBodies.distribution == 0) ,\ (self.wettedArea/self.alphaQ)**(1./self.betaQ),0.) #estQ= pcr.ifthenelse((self.actualStorage > 0.) & (self.waterBodies.distribution == 0) ,\ #0.5*(self.Q+(self.wettedArea/self.alphaQ)**(1./self.betaQ)),0.) #estQ= pcr.min(estQ,self.actualStorage/deltaTime) self.report(estQ,'results/qest') self.Q= pcr.spatial(pcr.scalar(0.)) self.Q= pcr.ifthenelse(self.waterBodies.distribution == 0,\ pcr.kinematic(self.channelLDD,estQ,0.,self.alphaQ,\ self.betaQ,1,deltaTime,self.channelLength),self.Q) # * water bodies * self.waterBodies.dischargeUpdate() self.Q= self.waterBodies.returnMapValue(self.Q,self.waterBodies.actualQ) #-fluxes and resulting change in storage: first the local fluxes are evaluated # and aggregated over the water bodies where applicable; this includes the specific runoff [m/day/m2] # from input and the estimated extraction from surface water as volume per day [m3/day]; # specific runoff from the land surface is always positive whereas the fluxes over the water surface # are potential, including discharge, and are adjusted to match the availabe storage; to this end, # surface water storage and fluxes over water bodies are totalized and assigned to the outlet; # discharge is updated in a separate step, after vertical fluxes are compared to the actual storage deltaActualStorage= ((self.landFraction*self.landSurfaceQ+\ self.waterFraction*self.potWaterSurfaceQ)*self.cellArea-\ self.potSurfaceWaterExtraction)*float(self.duration)/nrIter deltaActualStorage= pcr.ifthenelse(self.waterBodies.distribution != 0,\ pcr.ifthenelse(self.waterBodies.location != 0,\ pcr.areatotal(deltaActualStorage,self.waterBodies.distribution),0),\ deltaActualStorage) adjustmentRatio= pcr.ifthenelse(deltaActualStorage < 0.,\ pcr.min(1.,-self.actualStorage/deltaActualStorage),1.) self.actWaterSurfaceQ+= adjustmentRatio*self.potWaterSurfaceQ self.actSurfaceWaterExtraction+= adjustmentRatio*self.actSurfaceWaterExtraction deltaActualStorage*= adjustmentRatio #-local water balance check if testLocalWaterBalance: differenceActualStorage= self.actualStorage differenceActualStorage+= deltaActualStorage #-overall water balance check: net input self.cumulativeDeltaStorage+= pcr.catchmenttotal(deltaActualStorage,self.LDD) #-update storage first with local changes, then balance discharge with storage and update storage # with lateral flow and return value to water bodies self.actualStorage+= deltaActualStorage self.actualStorage= pcr.max(0.,self.actualStorage) self.Q= pcr.min(self.Q,self.actualStorage/deltaTime) deltaActualStorage= (-self.Q+pcr.upstream(self.LDD,self.Q))*deltaTime deltaActualStorage= pcr.ifthenelse(self.waterBodies.distribution != 0,\ pcr.ifthenelse(self.waterBodies.location != 0,\ pcr.areatotal(deltaActualStorage,self.waterBodies.distribution),0),\ deltaActualStorage) self.actualStorage+= deltaActualStorage self.actualStorage= pcr.max(0.,self.actualStorage) self.waterBodies.actualStorage= self.waterBodies.retrieveMapValue(self.actualStorage) #-flooded fraction returned floodedFraction,floodedDepth,\ self.wettedArea,self.alphaQ= self.kinAlphaComposite(self.actualStorage,self.floodplainMask) self.wettedArea= self.waterBodies.returnMapValue(self.wettedArea,\ self.waterBodies.channelWidth+2.*self.waterBodies.updateWaterHeight()) self.waterFraction= pcr.ifthenelse(self.waterBodies.distribution == 0,\ pcr.max(self.waterFractionMask,floodedFraction),self.waterFractionMask) self.landFraction= pcr.max(0.,1.-self.waterFraction) self.flowVelocity= pcr.ifthenelse(self.wettedArea > 0,self.Q/self.wettedArea,0.) #-local water balance check if testLocalWaterBalance: differenceActualStorage+= deltaActualStorage differenceActualStorage-= self.actualStorage totalDifference= pcr.cellvalue(pcr.maptotal(differenceActualStorage),1)[0] minimumDifference= pcr.cellvalue(pcr.mapminimum(differenceActualStorage),1)[0] maximumDifference= pcr.cellvalue(pcr.mapmaximum(differenceActualStorage),1)[0] if abs(totalDifference) > 1.e-3: print 'water balance error: total %e; min %e; max %e' %\ (totalDifference,minimumDifference,maximumDifference) if reportLocalWaterBalance: pcr.report(differenceActualStorage,'mbe_%s.map' % self.currentDate.date()) #-overall water balance check: updating cumulative discharge and total storage [m3] self.totalDischarge+= self.Q*deltaTime self.totalStorage= pcr.catchmenttotal(self.actualStorage,self.LDD) #-check on occurrence of last day and report mass balance if self.currentDate == self.endDate: #-report initial maps pcr.report(self.Q,self.QIniMap) pcr.report(self.actualStorage,self.actualStorageIniMap) #-return relative and absolute water balance error per cell and # as total at basin outlets self.totalDischarge= pcr.ifthen((self.waterBodies.distribution == 0) | \ (self.waterBodies.location != 0),self.totalDischarge) self.cumulativeDeltaStorage= pcr.ifthen((self.waterBodies.distribution == 0) | \ (self.waterBodies.location != 0),self.cumulativeDeltaStorage) massBalanceError= self.totalStorage+self.totalDischarge-\ self.cumulativeDeltaStorage relMassBalanceError= 1.+pcr.ifthenelse(self.cumulativeDeltaStorage <> 0., massBalanceError/self.cumulativeDeltaStorage,0.) totalMassBalanceError= pcr.cellvalue(pcr.maptotal(pcr.ifthen(self.basinOutlet,\ massBalanceError)),1)[0] totalCumulativeDeltaStorage= pcr.cellvalue(pcr.maptotal(pcr.ifthen(self.basinOutlet,\ self.cumulativeDeltaStorage)),1)[0] if totalCumulativeDeltaStorage > 0: totalRelativeMassBalanceError= 1.+totalMassBalanceError/totalCumulativeDeltaStorage else: totalRelativeMassBalanceError= 1. #-report maps and echo value pcr.report(massBalanceError,mbeFileName) pcr.report(relMassBalanceError,mbrFileName) print '\n*\ttotal global mass balance error [m3]: %8.3g' % totalMassBalanceError print '\n*\trelative global mass balance error [-]: %5.3f' % totalRelativeMassBalanceError #-echo to screen: total mass balance error and completion of run print '\trun completed' #-end of day: return states and fluxes #-get surface water attributes? if getSurfaceWaterAttributes: #-compute the following secondary variables: # surface water area [m2]: area given dynamic surface water fraction # residence time [days]: volume over discharge, assigned -1 in case discharge is zero # surface water depth [m], weighed by channel and floodplain volume surfaceWaterArea= self.waterFraction*self.cellArea surfaceWaterArea= pcr.ifthenelse(self.waterBodies.distribution != 0,\ pcr.ifthenelse(self.waterBodies.location != 0,\ pcr.areatotal(surfaceWaterArea,self.waterBodies.distribution),0),\ surfaceWaterArea) surfaceWaterResidenceTime= pcr.ifthenelse(self.Q > 0.,self.actualStorage/(self.Q*self.timeSec),-1) surfaceWaterDepth= pcr.ifthenelse(self.actualStorage > 0.,\ pcr.max(0.,self.actualStorage-self.channelStorageCapacity)**2/\ (self.actualStorage*surfaceWaterArea),0.) surfaceWaterDepth+= pcr.ifthenelse(self.actualStorage > 0.,\ pcr.min(self.channelStorageCapacity,self.actualStorage)**2/(self.waterFractionMask*\ self.cellArea*self.actualStorage),0.) #-reports: values at outlet of lakes or reservoirs are assigned to their full extent self.report(pcr.ifthenelse(self.waterBodies.distribution != 0,\ pcr.areamaximum(surfaceWaterArea,self.waterBodies.distribution),surfaceWaterArea),\ surfaceWaterAreaFileName) self.report(pcr.ifthenelse(self.waterBodies.distribution != 0,\ pcr.areamaximum(surfaceWaterResidenceTime,self.waterBodies.distribution),surfaceWaterResidenceTime),\ surfaceWaterResidenceTimeFileName) self.report(pcr.ifthenelse(self.waterBodies.distribution != 0,\ pcr.areamaximum(surfaceWaterDepth,self.waterBodies.distribution),surfaceWaterDepth),\ surfaceWaterDepthFileName) #-reports on standard output: values at outlet of lakes or reservoirs are assigned to their full extent self.report(pcr.ifthenelse(self.waterBodies.distribution != 0, pcr.areamaximum(self.flowVelocity,self.waterBodies.distribution),self.flowVelocity),flowVelocityFileName) self.report(pcr.ifthenelse(self.waterBodies.distribution != 0, pcr.areamaximum(self.Q,self.waterBodies.distribution),self.Q),QFileName) self.report(pcr.ifthenelse(self.waterBodies.distribution == 0,\ floodedFraction,0.),floodedFractionFileName) self.report(pcr.ifthenelse(self.waterBodies.distribution == 0,\ floodedDepth,0.),floodedDepthFileName) self.report(self.actualStorage,actualStorageFileName) #-update date for time step and report relevant daily output self.currentDate= self.currentDate+datetime.timedelta(self.duration)
def getParameterFiles( self, currTimeStep, cellArea, ldd, initial_condition_dictionary=None ): # parameters for Water Bodies: fracWat # waterBodyIds # waterBodyOut # waterBodyArea # waterBodyTyp # waterBodyCap # cell surface area (m2) and ldd self.cellArea = cellArea ldd = pcr.ifthen(self.landmask, ldd) # date used for accessing/extracting water body information date_used = currTimeStep.fulldate year_used = currTimeStep.year if self.onlyNaturalWaterBodies == True: date_used = self.dateForNaturalCondition year_used = self.dateForNaturalCondition[0:4] # fracWat = fraction of surface water bodies (dimensionless) self.fracWat = pcr.scalar(0.0) if self.useNetCDF: self.fracWat = vos.netcdf2PCRobjClone( self.ncFileInp, "fracWaterInp", date_used, useDoy="yearly", cloneMapFileName=self.cloneMap, ) else: self.fracWat = vos.readPCRmapClone( self.fracWaterInp + str(year_used) + ".map", self.cloneMap, self.tmpDir, self.inputDir, ) self.fracWat = pcr.cover(self.fracWat, 0.0) self.fracWat = pcr.max(0.0, self.fracWat) self.fracWat = pcr.min(1.0, self.fracWat) self.waterBodyIds = pcr.nominal(0) # waterBody ids self.waterBodyOut = pcr.boolean(0) # waterBody outlets self.waterBodyArea = pcr.scalar(0.0) # waterBody surface areas # water body ids if self.useNetCDF: self.waterBodyIds = vos.netcdf2PCRobjClone( self.ncFileInp, "waterBodyIds", date_used, useDoy="yearly", cloneMapFileName=self.cloneMap, ) else: self.waterBodyIds = vos.readPCRmapClone( self.waterBodyIdsInp + str(year_used) + ".map", self.cloneMap, self.tmpDir, self.inputDir, False, None, True, ) # self.waterBodyIds = pcr.ifthen( pcr.scalar(self.waterBodyIds) > 0.0, pcr.nominal(self.waterBodyIds) ) # water body outlets (correcting outlet positions) wbCatchment = pcr.catchmenttotal(pcr.scalar(1), ldd) self.waterBodyOut = pcr.ifthen( wbCatchment == pcr.areamaximum(wbCatchment, self.waterBodyIds), self.waterBodyIds, ) # = outlet ids self.waterBodyOut = pcr.ifthen( pcr.scalar(self.waterBodyIds) > 0.0, self.waterBodyOut ) # TODO: Please also consider endorheic lakes! # correcting water body ids self.waterBodyIds = pcr.ifthen( pcr.scalar(self.waterBodyIds) > 0.0, pcr.subcatchment(ldd, self.waterBodyOut), ) # boolean map for water body outlets: self.waterBodyOut = pcr.ifthen( pcr.scalar(self.waterBodyOut) > 0.0, pcr.boolean(1) ) # reservoir surface area (m2): if self.useNetCDF: resSfArea = ( 1000.0 * 1000.0 * vos.netcdf2PCRobjClone( self.ncFileInp, "resSfAreaInp", date_used, useDoy="yearly", cloneMapFileName=self.cloneMap, ) ) else: resSfArea = ( 1000.0 * 1000.0 * vos.readPCRmapClone( self.resSfAreaInp + str(year_used) + ".map", self.cloneMap, self.tmpDir, self.inputDir, ) ) resSfArea = pcr.areaaverage(resSfArea, self.waterBodyIds) resSfArea = pcr.cover(resSfArea, 0.0) # water body surface area (m2): (lakes and reservoirs) self.waterBodyArea = pcr.max( pcr.areatotal( pcr.cover(self.fracWat * self.cellArea, 0.0), self.waterBodyIds ), pcr.areaaverage(pcr.cover(resSfArea, 0.0), self.waterBodyIds), ) self.waterBodyArea = pcr.ifthen(self.waterBodyArea > 0.0, self.waterBodyArea) # correcting water body ids and outlets (exclude all water bodies with surfaceArea = 0) self.waterBodyIds = pcr.ifthen(self.waterBodyArea > 0.0, self.waterBodyIds) self.waterBodyOut = pcr.ifthen( pcr.boolean(self.waterBodyIds), self.waterBodyOut ) # water body types: # - 2 = reservoirs (regulated discharge) # - 1 = lakes (weirFormula) # - 0 = non lakes or reservoirs (e.g. wetland) self.waterBodyTyp = pcr.nominal(0) if self.useNetCDF: self.waterBodyTyp = vos.netcdf2PCRobjClone( self.ncFileInp, "waterBodyTyp", date_used, useDoy="yearly", cloneMapFileName=self.cloneMap, ) else: self.waterBodyTyp = vos.readPCRmapClone( self.waterBodyTypInp + str(year_used) + ".map", self.cloneMap, self.tmpDir, self.inputDir, False, None, True, ) # excluding wetlands (waterBodyTyp = 0) in all functions related to lakes/reservoirs # self.waterBodyTyp = pcr.ifthen( pcr.scalar(self.waterBodyTyp) > 0, pcr.nominal(self.waterBodyTyp) ) self.waterBodyTyp = pcr.ifthen( pcr.scalar(self.waterBodyIds) > 0, pcr.nominal(self.waterBodyTyp) ) self.waterBodyTyp = pcr.areamajority( self.waterBodyTyp, self.waterBodyIds ) # choose only one type: either lake or reservoir self.waterBodyTyp = pcr.ifthen( pcr.scalar(self.waterBodyTyp) > 0, pcr.nominal(self.waterBodyTyp) ) self.waterBodyTyp = pcr.ifthen( pcr.boolean(self.waterBodyIds), self.waterBodyTyp ) # correcting lakes and reservoirs ids and outlets self.waterBodyIds = pcr.ifthen( pcr.scalar(self.waterBodyTyp) > 0, self.waterBodyIds ) self.waterBodyOut = pcr.ifthen( pcr.scalar(self.waterBodyIds) > 0, self.waterBodyOut ) # reservoir maximum capacity (m3): self.resMaxCap = pcr.scalar(0.0) self.waterBodyCap = pcr.scalar(0.0) if self.useNetCDF: self.resMaxCap = ( 1000.0 * 1000.0 * vos.netcdf2PCRobjClone( self.ncFileInp, "resMaxCapInp", date_used, useDoy="yearly", cloneMapFileName=self.cloneMap, ) ) else: self.resMaxCap = ( 1000.0 * 1000.0 * vos.readPCRmapClone( self.resMaxCapInp + str(year_used) + ".map", self.cloneMap, self.tmpDir, self.inputDir, ) ) self.resMaxCap = pcr.ifthen(self.resMaxCap > 0, self.resMaxCap) self.resMaxCap = pcr.areaaverage(self.resMaxCap, self.waterBodyIds) # water body capacity (m3): (lakes and reservoirs) self.waterBodyCap = pcr.cover( self.resMaxCap, 0.0 ) # Note: Most of lakes have capacities > 0. self.waterBodyCap = pcr.ifthen( pcr.boolean(self.waterBodyIds), self.waterBodyCap ) # correcting water body types: # Reservoirs that have zero capacities will be assumed as lakes. self.waterBodyTyp = pcr.ifthen( pcr.scalar(self.waterBodyTyp) > 0.0, self.waterBodyTyp ) self.waterBodyTyp = pcr.ifthenelse( self.waterBodyCap > 0.0, self.waterBodyTyp, pcr.ifthenelse( pcr.scalar(self.waterBodyTyp) == 2, pcr.nominal(1), self.waterBodyTyp ), ) # final corrections: self.waterBodyTyp = pcr.ifthen( self.waterBodyArea > 0.0, self.waterBodyTyp ) # make sure that all lakes and/or reservoirs have surface areas self.waterBodyTyp = pcr.ifthen( pcr.scalar(self.waterBodyTyp) > 0.0, self.waterBodyTyp ) # make sure that only types 1 and 2 will be considered in lake/reservoir functions self.waterBodyIds = pcr.ifthen( pcr.scalar(self.waterBodyTyp) > 0.0, self.waterBodyIds ) # make sure that all lakes and/or reservoirs have ids self.waterBodyOut = pcr.ifthen( pcr.scalar(self.waterBodyIds) > 0.0, self.waterBodyOut ) # make sure that all lakes and/or reservoirs have outlets # for a natural run (self.onlyNaturalWaterBodies == True) # which uses only the year 1900, assume all reservoirs are lakes if ( self.onlyNaturalWaterBodies == True and date_used == self.dateForNaturalCondition ): logger.info( "Using only natural water bodies identified in the year 1900. All reservoirs in 1900 are assumed as lakes." ) self.waterBodyTyp = pcr.ifthen( pcr.scalar(self.waterBodyTyp) > 0.0, pcr.nominal(1) ) # check that all lakes and/or reservoirs have types, ids, surface areas and outlets: test = ( pcr.defined(self.waterBodyTyp) & pcr.defined(self.waterBodyArea) & pcr.defined(self.waterBodyIds) & pcr.boolean( pcr.areamaximum(pcr.scalar(self.waterBodyOut), self.waterBodyIds) ) ) a, b, c = vos.getMinMaxMean(pcr.cover(pcr.scalar(test), 1.0) - pcr.scalar(1.0)) threshold = 1e-3 if abs(a) > threshold or abs(b) > threshold: logger.warning("Missing information in some lakes and/or reservoirs.") # at the beginning of simulation period (timeStepPCR = 1) # - we have to define/get the initial conditions # if currTimeStep.timeStepPCR == 1: self.getICs(initial_condition_dictionary) # For each new reservoir (introduced at the beginning of the year) # initiating storage, average inflow and outflow # self.waterBodyStorage = pcr.cover(self.waterBodyStorage, 0.0) self.avgInflow = pcr.cover(self.avgInflow, 0.0) self.avgOutflow = pcr.cover(self.avgOutflow, 0.0) # cropping only in the landmask region: self.fracWat = pcr.ifthen(self.landmask, self.fracWat) self.waterBodyIds = pcr.ifthen(self.landmask, self.waterBodyIds) self.waterBodyOut = pcr.ifthen(self.landmask, self.waterBodyOut) self.waterBodyArea = pcr.ifthen(self.landmask, self.waterBodyArea) self.waterBodyTyp = pcr.ifthen(self.landmask, self.waterBodyTyp) self.waterBodyCap = pcr.ifthen(self.landmask, self.waterBodyCap) self.waterBodyStorage = pcr.ifthen(self.landmask, self.waterBodyStorage) self.avgInflow = pcr.ifthen(self.landmask, self.avgInflow) self.avgOutflow = pcr.ifthen(self.landmask, self.avgOutflow)
def set_river_package(self, discharge): logger.info("Set the river package.") # specify the river package # # - surface water river bed/bottom elevation # # - for lakes and resevoirs, make the bottom elevation deep --- Shall we do this? #~ additional_depth = 500. #~ surface_water_bed_elevation = pcr.ifthen(pcr.scalar(self.WaterBodies.waterBodyIds) > 0.0, \ #~ self.dem_riverbed - additional_depth) #~ surface_water_bed_elevation = pcr.cover(surface_water_bed_elevation, self.dem_riverbed) # surface_water_bed_elevation = self.dem_riverbed # This is an alternative, if we do not want to introduce very deep bottom elevations of lakes and/or reservoirs. # # rounding values for surface_water_bed_elevation self.surface_water_bed_elevation = pcr.roundup( surface_water_bed_elevation * 1000.) / 1000. # # - river bed condutance (unit: m2/day) bed_surface_area = pcr.ifthen(pcr.scalar(self.WaterBodies.waterBodyIds) > 0.0, \ self.WaterBodies.fracWat * self.cellAreaMap) # TODO: Incorporate the concept of dynamicFracWat bed_surface_area = pcr.cover(bed_surface_area, \ self.bankfull_width * self.channelLength) bed_surface_area = self.bankfull_width * self.channelLength bed_conductance = (1.0 / self.bed_resistance) * bed_surface_area bed_conductance = pcr.ifthenelse(bed_conductance < 1e-20, 0.0, \ bed_conductance) self.bed_conductance = pcr.cover(bed_conductance, 0.0) # # - 'channel width' for lakes and reservoirs channel_width = pcr.areamaximum(self.bankfull_width, self.WaterBodies.waterBodyIds) channel_width = pcr.cover(channel_width, self.bankfull_width) # # - convert discharge value to surface water elevation (m) river_water_height = (channel_width**(-3 / 5)) * (discharge**( 3 / 5)) * ((self.gradient)**(-3 / 10)) * (self.manningsN**(3 / 5)) surface_water_elevation = self.dem_riverbed + \ river_water_height # # - calculating water level (unit: m) above the flood plain # TODO: Improve this concept (using Rens's latest innundation scheme) #---------------------------------------------------------- water_above_fpl = pcr.max( 0.0, surface_water_elevation - self.dem_floodplain ) # unit: m, water level above the floodplain (not distributed) water_above_fpl *= self.bankfull_depth * self.bankfull_width / self.cellAreaMap # unit: m, water level above the floodplain (distributed within the cell) # TODO: Improve this concept using Rens's latest scheme # # - corrected surface water elevation surface_water_elevation = pcr.ifthenelse(surface_water_elevation > self.dem_floodplain, \ self.dem_floodplain + water_above_fpl, \ surface_water_elevation) # - surface water elevation for lakes and reservoirs: lake_reservoir_water_elevation = pcr.ifthen( self.WaterBodies.waterBodyOut, surface_water_elevation) lake_reservoir_water_elevation = pcr.areamaximum( lake_reservoir_water_elevation, self.WaterBodies.waterBodyIds) lake_reservoir_water_elevation = pcr.cover(lake_reservoir_water_elevation, \ pcr.areaaverage(surface_water_elevation, self.WaterBodies.waterBodyIds)) # - maximum and minimum values for lake_reservoir_water_elevation lake_reservoir_water_elevation = pcr.min( self.dem_floodplain, lake_reservoir_water_elevation) lake_reservoir_water_elevation = pcr.max( surface_water_bed_elevation, lake_reservoir_water_elevation) # - smoothing lake_reservoir_water_elevation = pcr.areaaverage( surface_water_elevation, self.WaterBodies.waterBodyIds) # # - merge lake and reservoir water elevation surface_water_elevation = pcr.cover(lake_reservoir_water_elevation, surface_water_elevation) # # - pass values to the river package surface_water_elevation = pcr.cover(surface_water_elevation, self.surface_water_bed_elevation) surface_water_elevation = pcr.rounddown( surface_water_elevation * 1000.) / 1000. # # - make sure that HRIV >= RBOT ; no infiltration if HRIV = RBOT (and h < RBOT) self.surface_water_elevation = pcr.max( surface_water_elevation, self.surface_water_bed_elevation) # # - pass the values to the RIV package self.pcr_modflow.setRiver(self.surface_water_elevation, \ self.surface_water_bed_elevation, self.bed_conductance, 2)
def subcatch_stream( ldd, threshold, min_strahler=-999, max_strahler=999, assign_edge=False, assign_existing=False, up_area=None, ): """ (From Deltares Hydrotools) Derive catchments based upon strahler threshold Input: ldd -- pcraster object direction, local drain directions threshold -- integer, strahler threshold, subcatchments ge threshold are derived min_strahler -- integer, minimum strahler threshold of river catchments to return max_strahler -- integer, maximum strahler threshold of river catchments to return assign_unique=False -- if set to True, unassigned connected areas at the edges of the domain are assigned a unique id as well. If set to False, edges are not assigned assign_existing=False == if set to True, unassigned edges are assigned to existing basins with an upstream weighting. If set to False, edges are assigned to unique IDs, or not assigned output: stream_ge -- pcraster object, streams of strahler order ge threshold subcatch -- pcraster object, subcatchments of strahler order ge threshold """ # derive stream order stream = pcr.streamorder(ldd) stream_ge = pcr.ifthen(stream >= threshold, stream) stream_up_sum = pcr.ordinal(pcr.upstream(ldd, pcr.cover(pcr.scalar(stream_ge), 0))) # detect any transfer of strahler order, to a higher strahler order. transition_strahler = pcr.ifthenelse( pcr.downstream(ldd, stream_ge) != stream_ge, pcr.boolean(1), pcr.ifthenelse( pcr.nominal(ldd) == 5, pcr.boolean(1), pcr.ifthenelse( pcr.downstream(ldd, pcr.scalar(stream_up_sum)) > pcr.scalar(stream_ge), pcr.boolean(1), pcr.boolean(0), ), ), ) # make unique ids (write to file) transition_unique = pcr.ordinal(pcr.uniqueid(transition_strahler)) # derive upstream catchment areas (write to file) subcatch = pcr.nominal(pcr.subcatchment(ldd, transition_unique)) if assign_edge: # fill unclassified areas (in pcraster equal to zero) with a unique id, above the maximum id assigned so far unique_edge = pcr.clump(pcr.ifthen(subcatch == 0, pcr.ordinal(0))) subcatch = pcr.ifthenelse( subcatch == 0, pcr.nominal(pcr.mapmaximum(pcr.scalar(subcatch)) + pcr.scalar(unique_edge)), pcr.nominal(subcatch), ) elif assign_existing: # unaccounted areas are added to largest nearest draining basin if up_area is None: up_area = pcr.ifthen( pcr.boolean(pcr.cover(stream_ge, 0)), pcr.accuflux(ldd, 1) ) riverid = pcr.ifthen(pcr.boolean(pcr.cover(stream_ge, 0)), subcatch) friction = 1.0 / pcr.scalar( pcr.spreadzone(pcr.cover(pcr.ordinal(up_area), 0), 0, 0) ) # *(pcr.scalar(ldd)*0+1) delta = pcr.ifthen( pcr.scalar(ldd) >= 0, pcr.ifthen( pcr.cover(subcatch, 0) == 0, pcr.spreadzone(pcr.cover(riverid, 0), 0, friction), ), ) subcatch = pcr.ifthenelse(pcr.boolean(pcr.cover(subcatch, 0)), subcatch, delta) # finally, only keep basins with minimum and maximum river order flowing through them strahler_subcatch = pcr.areamaximum(stream, subcatch) subcatch = pcr.ifthen( pcr.ordinal(strahler_subcatch) >= min_strahler, pcr.ifthen(pcr.ordinal(strahler_subcatch) <= max_strahler, subcatch), ) return stream_ge, pcr.ordinal(subcatch)
def main(): """ :ivar masterdem: digital elevation model :ivar dem: digital elevation model :ivar river: optional river map """ # Default values strRiver = 8 masterdem = "dem.map" step1dir = "step1" step2dir = "step2" workdir = "." inifile = "wflow_prepare.ini" recreate = False snapgaugestoriver = False try: opts, args = getopt.getopt(sys.argv[1:], "W:hI:f",['version']) except getopt.error as msg: usage(msg) for o, a in opts: if o == "-W": workdir = a if o == "-I": inifile = a if o == "-h": usage() if o == "-f": recreate = True if o == "--version": import wflow print("wflow version: ", wflow.__version__) sys.exit(0) pcr.setglobaloption("unitcell") os.chdir(workdir) config = OpenConf(workdir + "/" + inifile) masterdem = configget(config, "files", "masterdem", "dem.map") pcr.setclone(masterdem) strRiver = int(configget(config, "settings", "riverorder", "4")) try: gauges_x = config.get("settings", "gauges_x") gauges_y = config.get("settings", "gauges_y") except: print("gauges_x and gauges_y are required entries in the ini file") sys.exit(1) step1dir = configget(config, "directories", "step1dir", "step1") step2dir = configget(config, "directories", "step2dir", "step2") # upscalefactor = float(config.get("settings","upscalefactor")) corevolume = float(configget(config, "settings", "corevolume", "1E35")) catchmentprecipitation = float( configget(config, "settings", "catchmentprecipitation", "1E35") ) corearea = float(configget(config, "settings", "corearea", "1E35")) outflowdepth = float(configget(config, "settings", "lddoutflowdepth", "1E35")) initialscale = int(configget(config, "settings", "initialscale", "1")) csize = float(configget(config, "settings", "cellsize", "1")) snapgaugestoriver = bool( int(configget(config, "settings", "snapgaugestoriver", "1")) ) lddglobaloption = configget(config, "settings", "lddglobaloption", "lddout") pcr.setglobaloption(lddglobaloption) lu_water = configget(config, "files", "lu_water", "") lu_paved = configget(config, "files", "lu_paved", "") # X/Y coordinates of the gauges the system X = np.fromstring(gauges_x, sep=',') Y = np.fromstring(gauges_y, sep=',') tr.Verbose = 1 # make the directories to save results in if not os.path.isdir(step1dir + "/"): os.makedirs(step1dir) if not os.path.isdir(step2dir): os.makedirs(step2dir) if initialscale > 1: print("Initial scaling of DEM...") os.system( "resample -r " + str(initialscale) + " " + masterdem + " " + step1dir + "/dem_scaled.map" ) print("Reading dem...") dem = pcr.readmap(step1dir + "/dem_scaled.map") ldddem = dem else: print ("Reading dem...") dem = pcr.readmap(masterdem) ldddem = dem try: catchmask = config.get("files", "catchment_mask") except: print("No catchment mask...") else: print("clipping DEM with mask.....") mask = pcr.readmap(catchmask) ldddem = pcr.ifthen(pcr.boolean(mask), ldddem) dem = pcr.ifthen(pcr.boolean(mask), dem) # See if there is a shape file of the river to burn in try: rivshp = config.get("files", "river") except: print("no river file specified") outletpointX = float(configget(config, "settings", "outflowpointX", "0.0")) outletpointY = float(configget(config, "settings", "outflowpointY", "0.0")) else: print("river file specified.....") try: outletpointX = float(configget(config, "settings", "outflowpointX", "0.0")) outletpointY = float(configget(config, "settings", "outflowpointY", "0.0")) except: print( "Need to specify the river outletpoint (a point at the end of the river within the current map)" ) exit(1) outletpointmap = tr.points_to_map(dem, outletpointX, outletpointY, 0.5) pcr.report(outletpointmap, step1dir + "/outletpoint.map") # rivshpattr = config.get("files","riverattr") pcr.report(dem * 0.0, step1dir + "/nilmap.map") thestr = ( "gdal_translate -of GTiff " + step1dir + "/nilmap.map " + step1dir + "/riverburn.tif" ) os.system(thestr) rivshpattr = os.path.splitext(os.path.basename(rivshp))[0] os.system( "gdal_rasterize -burn 1 -l " + rivshpattr + " " + rivshp + " " + step1dir + "/riverburn.tif" ) thestr = ( "gdal_translate -of PCRaster " + step1dir + "/riverburn.tif " + step1dir + "/riverburn.map" ) os.system(thestr) riverburn = pcr.readmap(step1dir + "/riverburn.map") # Determine regional slope assuming that is the way the river should run # Determine regional slope assuming that is the way the river should run # pcr.setglobaloption("unitcell") # demregional=pcr.windowaverage(dem,100) ldddem = pcr.ifthenelse(riverburn >= 1.0, dem - 1000, dem) pcr.setglobaloption("unittrue") upscalefactor = int(csize / pcr.celllength()) print("Creating ldd...") ldd = tr.lddcreate_save( step1dir + "/ldd.map", ldddem, recreate, outflowdepth=outflowdepth, corevolume=corevolume, catchmentprecipitation=catchmentprecipitation, corearea=corearea, ) print("Determining streamorder...") stro = pcr.streamorder(ldd) pcr.report(stro, step1dir + "/streamorder.map") strdir = pcr.ifthen(stro >= strRiver, stro) pcr.report(strdir, step1dir + "/streamorderrive.map") pcr.report(pcr.boolean(pcr.ifthen(stro >= strRiver, stro)), step1dir + "/rivers.map") pcr.setglobaloption("unittrue") # outlet (and other gauges if given) # TODO: check is x/y set if not skip this print("Outlet...") outlmap = tr.points_to_map(dem, X, Y, 0.5) if snapgaugestoriver: print("Snapping gauges to nearest river cells...") pcr.report(outlmap, step1dir + "/orggauges.map") outlmap = tr.snaptomap(outlmap, strdir) # noutletmap = tr.points_to_map(dem,XX,YY,0.5) # pcr.report(noutletmap,'noutlet.map') pcr.report(outlmap, step1dir + "/gauges.map") # check if there is a pre-define catchment map try: catchmask = config.get("files", "catchment_mask") except: print("No catchment mask, finding outlet") # Find catchment (overall) outlet = tr.find_outlet(ldd) sub = tr.subcatch(ldd, outlet) pcr.report(sub, step1dir + "/catchment_overall.map") else: print("reading and converting catchment mask.....") os.system( "resample -r " + str(initialscale) + " " + catchmask + " " + step1dir + "/catchment_overall.map" ) sub = pcr.readmap(step1dir + "/catchment_overall.map") print("Scatch...") sd = tr.subcatch(ldd, pcr.ifthen(outlmap > 0, outlmap)) pcr.report(sd, step1dir + "/scatch.map") pcr.setglobaloption("unitcell") print("Upscalefactor: " + str(upscalefactor)) if upscalefactor > 1: gc.collect() print("upscale river length1 (checkerboard map)...") ck = tr.checkerboard(dem, upscalefactor) pcr.report(ck, step1dir + "/ck.map") pcr.report(dem, step1dir + "/demck.map") print("upscale river length2...") fact = tr.area_riverlength_factor(ldd, ck, upscalefactor) pcr.report(fact, step1dir + "/riverlength_fact.map") # print("make dem statistics...") dem_ = pcr.areaaverage(dem, ck) pcr.report(dem_, step1dir + "/demavg.map") print("Create DEM statistics...") dem_ = pcr.areaminimum(dem, ck) pcr.report(dem_, step1dir + "/demmin.map") dem_ = pcr.areamaximum(dem, ck) pcr.report(dem_, step1dir + "/demmax.map") # calculate percentiles order = pcr.areaorder(dem, ck) n = pcr.areatotal(pcr.spatial(pcr.scalar(1.0)), ck) #: calculate 25 percentile perc = tr.area_percentile(dem, ck, n, order, 25.0) pcr.report(perc, step1dir + "/dem25.map") perc = tr.area_percentile(dem, ck, n, order, 10.0) pcr.report(perc, step1dir + "/dem10.map") perc = tr.area_percentile(dem, ck, n, order, 50.0) pcr.report(perc, step1dir + "/dem50.map") perc = tr.area_percentile(dem, ck, n, order, 33.0) pcr.report(perc, step1dir + "/dem33.map") perc = tr.area_percentile(dem, ck, n, order, 66.0) pcr.report(perc, step1dir + "/dem66.map") perc = tr.area_percentile(dem, ck, n, order, 75.0) pcr.report(perc, step1dir + "/dem75.map") perc = tr.area_percentile(dem, ck, n, order, 90.0) pcr.report(perc, step1dir + "/dem90.map") else: print("No fancy scaling done. Going strait to step2....") pcr.report(dem, step1dir + "/demavg.map") Xul = float(config.get("settings", "Xul")) Yul = float(config.get("settings", "Yul")) Xlr = float(config.get("settings", "Xlr")) Ylr = float(config.get("settings", "Ylr")) gdalstr = ( "gdal_translate -projwin " + str(Xul) + " " + str(Yul) + " " + str(Xlr) + " " + str(Ylr) + " -of PCRaster " ) # gdalstr = "gdal_translate -a_ullr " + str(Xul) + " " + str(Yul) + " " +str(Xlr) + " " +str(Ylr) + " -of PCRaster " print(gdalstr) pcr.report(pcr.cover(1.0), step1dir + "/wflow_riverlength_fact.map") # Now us gdat tp convert the maps os.system( gdalstr + step1dir + "/wflow_riverlength_fact.map" + " " + step2dir + "/wflow_riverlength_fact.map" ) os.system( gdalstr + step1dir + "/demavg.map" + " " + step2dir + "/wflow_dem.map" ) os.system( gdalstr + step1dir + "/demavg.map" + " " + step2dir + "/wflow_demmin.map" ) os.system( gdalstr + step1dir + "/demavg.map" + " " + step2dir + "/wflow_demmax.map" ) os.system( gdalstr + step1dir + "/gauges.map" + " " + step2dir + "/wflow_gauges.map" ) os.system( gdalstr + step1dir + "/rivers.map" + " " + step2dir + "/wflow_river.map" ) os.system( gdalstr + step1dir + "/streamorder.map" + " " + step2dir + "/wflow_streamorder.map" ) os.system( gdalstr + step1dir + "/gauges.map" + " " + step2dir + "/wflow_outlet.map" ) os.system( gdalstr + step1dir + "/scatch.map" + " " + step2dir + "/wflow_catchment.map" ) os.system(gdalstr + step1dir + "/ldd.map" + " " + step2dir + "/wflow_ldd.map") os.system( gdalstr + step1dir + "/scatch.map" + " " + step2dir + "/wflow_subcatch.map" ) if lu_water: os.system(gdalstr + lu_water + " " + step2dir + "/WaterFrac.map") if lu_paved: os.system(gdalstr + lu_paved + " " + step2dir + "/PathFrac.map") try: lumap = config.get("files", "landuse") except: print("no landuse map...creating uniform map") # clone=pcr.readmap(step2dir + "/wflow_dem.map") pcr.setclone(step2dir + "/wflow_dem.map") pcr.report(pcr.nominal(1), step2dir + "/wflow_landuse.map") else: os.system( "resample --clone " + step2dir + "/wflow_dem.map " + lumap + " " + step2dir + "/wflow_landuse.map" ) try: soilmap = config.get("files", "soil") except: print("no soil map..., creating uniform map") pcr.setclone(step2dir + "/wflow_dem.map") pcr.report(pcr.nominal(1), step2dir + "/wflow_soil.map") else: os.system( "resample --clone " + step2dir + "/wflow_dem.map " + soilmap + " " + step2dir + "/wflow_soil.map" )
pcr.cover(\ vos.readPCRmapClone(reservoir_capacity_file, \ clone_map_file, \ tmp_folder, \ None, False, None, False), 0.0)) * 1000. * 1000. water_body_id = vos.readPCRmapClone(water_body_id_file, \ clone_map_file, \ tmp_folder, \ None, False, None, True ) water_body_id = pcr.ifthen(pcr.scalar(water_body_id) > 0.00, water_body_id) water_body_id = pcr.ifthen( landmask, water_body_id) # # water body outlet wbCatchment = pcr.catchmenttotal(pcr.scalar(1), ldd_map_low_resolution) water_body_outlet = pcr.ifthen(wbCatchment ==\ pcr.areamaximum(wbCatchment, \ water_body_id),\ water_body_id) # = outlet ids # This may give more than two outlets, particularly if there are more than one cells that have largest upstream areas # - make sure that there is only one outlet for each water body water_body_outlet = pcr.ifthen(\ pcr.areaorder(pcr.scalar( water_body_outlet), \ water_body_outlet) == 1., water_body_outlet) water_body_outlet = pcr.ifthen(\ pcr.scalar(water_body_outlet) > 0., water_body_outlet) # calculate overbank volume from reservoirs (and lakes) lake_reservoir_volume = pcr.areatotal(extreme_value_map, water_body_id) lake_reservoir_overbank_volume = pcr.cover( pcr.max(0.0, lake_reservoir_volume - reservoir_capacity), 0.0) #~ pcr.aguila(lake_reservoir_overbank_volume) # # transfer 75% of overbank volume to the downstream (several cells downstream)
useDoy = None, cloneMapFileName = None,\ LatitudeLongitude = True,\ specificFillValue = None) areal_groundwater_recharge = pcr.areatotal(groundwater_recharge * cell_area, class_map)/pcr.areatotal(cell_area, class_map) # - ignore negative groundwater recharge (due to capillary rise) areal_groundwater_recharge = pcr.max(0.0, areal_groundwater_recharge) # areal groundwater contribution to meet enviromental flow (unit: m/year) groundwater_contribution_to_environmental_flow = pcr.max(0.10, fraction_reserved_recharge * groundwater_recharge) groundwater_contribution_to_environmental_flow_filename = output_directory + "/" + "groundwater_contribution_to_environmental_flow.m.per.year.map" pcr.report(pcr.ifthen(landmask, groundwater_contribution_to_environmental_flow), groundwater_contribution_to_environmental_flow_filename) areal_groundwater_contribution_to_environmental_flow = pcr.areatotal(groundwater_contribution_to_environmental_flow * cell_area, class_map)/pcr.areatotal(cell_area, class_map) areal_groundwater_contribution_to_environmental_flow = pcr.min(0.75 * areal_groundwater_recharge, areal_groundwater_contribution_to_environmental_flow) # groundwater stress map (dimensionless) groundwater_stress_map = pcr.ifthen(landmask, \ areal_groundwater_abstraction/(pcr.cover(pcr.max(0.001, areal_groundwater_recharge - areal_groundwater_contribution_to_environmental_flow), 0.001))) # fill in the entire cell groundwater_stress_map = pcr.ifthen(landmask, \ pcr.areamaximum(groundwater_stress_map, class_map_all)) groundwater_stress_map_filename = output_directory + "/" + str(sys.argv[2]) + "_" + str(start_year) + "to" + str(end_year) + ".groundwater_stress.map" pcr.report(groundwater_stress_map, groundwater_stress_map_filename) pcr.aguila(groundwater_stress_map) # groundwater footprint map (km2) groundwater_footprint_map = groundwater_stress_map * pcr.cover(pcr.areatotal(cell_area, class_map), 0.0) / (1000. * 1000.) groundwater_footprint_map_filename = output_directory + "/" + str(sys.argv[2]) + "_" + str(start_year) + "to" + str(end_year) + ".groundwater_footprint.km2.map" pcr.report(groundwater_footprint_map, groundwater_footprint_map_filename) pcr.aguila(groundwater_footprint_map)
#~ pcr.aguila(basin_map) # - extend/extrapolate the basin basin_map = pcr.cover(basin_map, pcr.windowmajority(basin_map, 0.5)) basin_map = pcr.cover(basin_map, pcr.windowmajority(basin_map, 0.5)) basin_map = pcr.cover(basin_map, pcr.windowmajority(basin_map, 0.5)) basin_map = pcr.cover(basin_map, pcr.windowmajority(basin_map, 1.0)) basin_map = pcr.cover(basin_map, pcr.windowmajority(basin_map, 1.5)) basin_map = pcr.ifthen(landmask, basin_map) #~ pcr.aguila(basin_map) msg = "Redefining the basin map (so that it is consistent with the ldd map used in PCR-GLOBWB):" logger.info(msg) # - calculate the upstream area of every pixel: upstream_area = pcr.catchmenttotal(cell_area, ldd) # - calculate the catchment area of every basin: upstream_area_maximum = pcr.areamaximum(upstream_area, basin_map) # - identify the outlet of every basin (in order to rederive the basin so that it is consistent with the ldd) outlet = pcr.nominal( pcr.uniqueid( pcr.ifthen(upstream_area == upstream_area_maximum, pcr.boolean(1.0)))) # - ignoring outlets with small upstream areas threshold = 50. * 1000. * 1000. # unit: m2 outlet = pcr.ifthen(upstream_area_maximum > threshold, outlet) #~ pcr.aguila(outlet) outlet = pcr.cover(outlet, pcr.nominal(0.0)) # - recalculate the basin basin_map = pcr.nominal(pcr.subcatchment(ldd, outlet)) basin_map = pcr.clump(basin_map) basin_map = pcr.ifthen(landmask, basin_map) pcr.report(basin_map, "basin_map.map") #~ pcr.aguila(basin_map)
def subcatch_stream(ldd, threshold, stream=None, min_strahler=-999, max_strahler=999, assign_edge=False, assign_existing=False, up_area=None, basin=None): """ Derive catchments based upon strahler threshold Input: ldd -- pcraster object direction, local drain directions threshold -- integer, strahler threshold, subcatchments ge threshold are derived stream=None -- pcraster object ordinal, stream order map (made with pcr.streamorder), if provided, stream order map is not generated on the fly but used from this map. Useful when a subdomain within a catchment is provided, which would cause edge effects in the stream order map min_strahler=-999 -- integer, minimum strahler threshold of river catchments to return max_strahler=999 -- integer, maximum strahler threshold of river catchments to return assign_unique=False -- if set to True, unassigned connected areas at the edges of the domain are assigned a unique id as well. If set to False, edges are not assigned assign_existing=False == if set to True, unassigned edges are assigned to existing basins with an upstream weighting. If set to False, edges are assigned to unique IDs, or not assigned output: stream_ge -- pcraster object, streams of strahler order ge threshold subcatch -- pcraster object, subcatchments of strahler order ge threshold """ # derive stream order if stream is None: stream = pcr.streamorder(ldd) stream_ge = pcr.ifthen(stream >= threshold, stream) stream_up_sum = pcr.ordinal(pcr.upstream(ldd, pcr.cover(pcr.scalar(stream_ge), 0))) # detect any transfer of strahler order, to a higher strahler order. transition_strahler = pcr.ifthenelse(pcr.downstream(ldd, stream_ge) != stream_ge, pcr.boolean(1), pcr.ifthenelse(pcr.nominal(ldd) == 5, pcr.boolean(1), pcr.ifthenelse(pcr.downstream(ldd, pcr.scalar(stream_up_sum)) > pcr.scalar(stream_ge), pcr.boolean(1), pcr.boolean(0)))) # make unique ids (write to file) transition_unique = pcr.ordinal(pcr.uniqueid(transition_strahler)) # derive upstream catchment areas (write to file) subcatch = pcr.nominal(pcr.subcatchment(ldd, transition_unique)) # mask out areas outside basin if basin is not None: subcatch = pcr.ifthen(basin, subcatch) if assign_edge: # fill unclassified areas (in pcraster equal to zero) with a unique id, above the maximum id assigned so far unique_edge = pcr.clump(pcr.ifthen(subcatch==0, pcr.ordinal(0))) subcatch = pcr.ifthenelse(subcatch==0, pcr.nominal(pcr.mapmaximum(pcr.scalar(subcatch)) + pcr.scalar(unique_edge)), pcr.nominal(subcatch)) elif assign_existing: # unaccounted areas are added to largest nearest draining basin if up_area is None: up_area = pcr.ifthen(pcr.boolean(pcr.cover(stream_ge, 0)), pcr.accuflux(ldd, 1)) riverid = pcr.ifthen(pcr.boolean(pcr.cover(stream_ge, 0)), subcatch) friction = 1./pcr.scalar(pcr.spreadzone(pcr.cover(pcr.ordinal(up_area), 0), 0, 0)) # *(pcr.scalar(ldd)*0+1) delta = pcr.ifthen(pcr.scalar(ldd)>=0, pcr.ifthen(pcr.cover(subcatch, 0)==0, pcr.spreadzone(pcr.cover(riverid, 0), 0, friction))) subcatch = pcr.ifthenelse(pcr.boolean(pcr.cover(subcatch, 0)), subcatch, delta) # finally, only keep basins with minimum and maximum river order flowing through them strahler_subcatch = pcr.areamaximum(stream, subcatch) subcatch = pcr.ifthen(pcr.ordinal(strahler_subcatch) >= min_strahler, pcr.ifthen(pcr.ordinal(strahler_subcatch) <= max_strahler, subcatch)) return stream_ge, pcr.ordinal(subcatch)
vos.readPCRmapClone(reservoir_capacity_file, \ clone_map_file, \ tmp_folder, \ None, False, None, False), 0.0)) * 1000. * 1000. water_body_id = vos.readPCRmapClone(water_body_id_file, \ clone_map_file, \ tmp_folder, \ None, False, None, True ) water_body_id = pcr.ifthen( pcr.scalar(water_body_id) > 0.00, water_body_id) water_body_id = pcr.ifthen(landmask, water_body_id) # # water body outlet wbCatchment = pcr.catchmenttotal(pcr.scalar(1), ldd_map_low_resolution) water_body_outlet = pcr.ifthen(wbCatchment ==\ pcr.areamaximum(wbCatchment, \ water_body_id),\ water_body_id) # = outlet ids # This may give more than two outlets, particularly if there are more than one cells that have largest upstream areas # - make sure that there is only one outlet for each water body water_body_outlet = pcr.ifthen(\ pcr.areaorder(pcr.scalar( water_body_outlet), \ water_body_outlet) == 1., water_body_outlet) water_body_outlet = pcr.ifthen(\ pcr.scalar(water_body_outlet) > 0., water_body_outlet) # calculate overbank volume from reservoirs (and lakes) lake_reservoir_volume = pcr.areatotal(extreme_value_map, water_body_id) lake_reservoir_overbank_volume = pcr.cover( pcr.max(0.0, lake_reservoir_volume - reservoir_capacity), 0.0) #~ pcr.aguila(lake_reservoir_overbank_volume) # # transfer 75% of overbank volume to the downstream (several cells downstream)
def getReservoirOutflow( self, avgChannelDischarge, length_of_time_step, downstreamDemand ): # avgOutflow (m3/s) avgOutflow = self.avgOutflow # The following is needed when new lakes/reservoirs introduced (its avgOutflow is still zero). # ~ # - alternative 1 # ~ avgOutflow = pcr.ifthenelse(\ # ~ avgOutflow > 0.,\ # ~ avgOutflow, # ~ pcr.max(avgChannelDischarge, self.avgInflow, 0.001)) # - alternative 2 avgOutflow = pcr.ifthenelse( avgOutflow > 0.0, avgOutflow, pcr.max(avgChannelDischarge, self.avgInflow) ) avgOutflow = pcr.ifthenelse( avgOutflow > 0.0, avgOutflow, pcr.downstream(self.lddMap, avgOutflow) ) avgOutflow = pcr.areamaximum(avgOutflow, self.waterBodyIds) # calculate resvOutflow (m2/s) (based on reservoir storage and avgDischarge): # - using reductionFactor in such a way that: # - if relativeCapacity < minResvrFrac : release is terminated # - if relativeCapacity > maxResvrFrac : longterm average reductionFactor = pcr.cover( pcr.min( 1.0, pcr.max( 0.0, self.waterBodyStorage - self.minResvrFrac * self.waterBodyCap ) / (self.maxResvrFrac - self.minResvrFrac) * self.waterBodyCap, ), 0.0, ) # resvOutflow = reductionFactor * avgOutflow * length_of_time_step # unit: m3 # maximum release <= average inflow (especially during dry condition) resvOutflow = pcr.max( 0, pcr.min(resvOutflow, self.avgInflow * length_of_time_step) ) # unit: m3 # downstream demand (m3/s) # reduce demand if storage < lower limit reductionFactor = vos.getValDivZero( downstreamDemand, self.minResvrFrac * self.waterBodyCap, vos.smallNumber ) reductionFactor = pcr.cover(reductionFactor, 0.0) downstreamDemand = pcr.min(downstreamDemand, downstreamDemand * reductionFactor) # resvOutflow > downstreamDemand resvOutflow = pcr.max( resvOutflow, downstreamDemand * length_of_time_step ) # unit: m3 # floodOutflow: additional release if storage > upper limit ratioQBankfull = 2.3 estmStorage = pcr.max(0.0, self.waterBodyStorage - resvOutflow) floodOutflow = pcr.max(0.0, estmStorage - self.waterBodyCap) + pcr.cover( pcr.max(0.0, estmStorage - self.maxResvrFrac * self.waterBodyCap) / ((1.0 - self.maxResvrFrac) * self.waterBodyCap), 0.0, ) * pcr.max( 0.0, ratioQBankfull * avgOutflow * vos.secondsPerDay() - resvOutflow ) floodOutflow = pcr.max( 0.0, pcr.min( floodOutflow, estmStorage - self.maxResvrFrac * self.waterBodyCap * 0.75 ), ) # maximum limit of floodOutflow: bring the reservoir storages only to 3/4 of upper limit capacities # update resvOutflow after floodOutflow resvOutflow = pcr.cover(resvOutflow, 0.0) + pcr.cover(floodOutflow, 0.0) # maximum release if storage > upper limit : bring the reservoir storages only to 3/4 of upper limit capacities resvOutflow = pcr.ifthenelse( self.waterBodyStorage > self.maxResvrFrac * self.waterBodyCap, pcr.min( resvOutflow, pcr.max( 0, self.waterBodyStorage - self.maxResvrFrac * self.waterBodyCap * 0.75, ), ), resvOutflow, ) # if storage > upper limit : resvOutflow > avgInflow resvOutflow = pcr.ifthenelse( self.waterBodyStorage > self.maxResvrFrac * self.waterBodyCap, pcr.max(0.0, resvOutflow, self.avgInflow), resvOutflow, ) # resvOutflow < waterBodyStorage resvOutflow = pcr.min(self.waterBodyStorage, resvOutflow) resvOutflow = pcr.ifthen(pcr.scalar(self.waterBodyIds) > 0.0, resvOutflow) resvOutflow = pcr.ifthen(pcr.scalar(self.waterBodyTyp) == 2, resvOutflow) return resvOutflow # unit: m3
#~ pcr.aguila(basin_map) # - extend/extrapolate the basin basin_map = pcr.cover(basin_map, pcr.windowmajority(basin_map, 0.5)) basin_map = pcr.cover(basin_map, pcr.windowmajority(basin_map, 0.5)) basin_map = pcr.cover(basin_map, pcr.windowmajority(basin_map, 0.5)) basin_map = pcr.cover(basin_map, pcr.windowmajority(basin_map, 1.0)) basin_map = pcr.cover(basin_map, pcr.windowmajority(basin_map, 1.5)) basin_map = pcr.ifthen(landmask, basin_map) #~ pcr.aguila(basin_map) msg = "Redefining the basin map (so that it is consistent with the ldd map used in PCR-GLOBWB):" logger.info(msg) # - calculate the upstream area of every pixel: upstream_area = pcr.catchmenttotal(cell_area, ldd) # - calculate the catchment area of every basin: upstream_area_maximum = pcr.areamaximum(upstream_area, basin_map) # - identify the outlet of every basin (in order to rederive the basin so that it is consistent with the ldd) outlet = pcr.nominal(pcr.uniqueid(pcr.ifthen(upstream_area == upstream_area_maximum, pcr.boolean(1.0)))) # - ignoring outlets with small upstream areas threshold = 50. * 1000. * 1000. # unit: m2 outlet = pcr.ifthen(upstream_area_maximum > threshold, outlet) #~ pcr.aguila(outlet) outlet = pcr.cover(outlet, pcr.nominal(0.0)) # - recalculate the basin basin_map = pcr.nominal(pcr.subcatchment(ldd, outlet)) basin_map = pcr.clump(basin_map) basin_map = pcr.ifthen(landmask, basin_map) pcr.report(basin_map , "basin_map.map") #~ pcr.aguila(basin_map) # - calculate the basin area basin_area = pcr.areatotal(cell_area, basin_map)
def getParameterFiles(self, date_given, cellArea, ldd): # parameters for Water Bodies: fracWat # waterBodyIds # waterBodyOut # waterBodyArea # waterBodyTyp # waterBodyCap # cell surface area (m2) and ldd self.cellArea = cellArea ldd = pcr.ifthen(self.landmask, ldd) # date and year used for accessing/extracting water body information date_used = date_given if self.onlyNaturalWaterBodies == True: date_used = self.dateForNaturalCondition year_used = date_used[0:4] # fracWat = fraction of surface water bodies (dimensionless) self.fracWat = pcr.scalar(0.0) if self.useNetCDF: self.fracWat = vos.netcdf2PCRobjClone(self.ncFileInp,'fracWaterInp', \ date_used, useDoy = 'yearly',\ cloneMapFileName = self.cloneMap) self.fracWat = pcr.cover(self.fracWat, 0.0) self.fracWat = pcr.max(0.0, self.fracWat) self.fracWat = pcr.min(1.0, self.fracWat) self.waterBodyIds = pcr.nominal(0) # waterBody ids self.waterBodyOut = pcr.boolean(0) # waterBody outlets self.waterBodyArea = pcr.scalar(0.) # waterBody surface areas # water body ids if self.useNetCDF: self.waterBodyIds = vos.netcdf2PCRobjClone(self.ncFileInp,'waterBodyIds', \ date_used, useDoy = 'yearly',\ cloneMapFileName = self.cloneMap) self.waterBodyIds = pcr.ifthen(\ pcr.scalar(self.waterBodyIds) > 0.,\ pcr.nominal(self.waterBodyIds)) # water body outlets (correcting outlet positions) wbCatchment = pcr.catchmenttotal(pcr.scalar(1), ldd) self.waterBodyOut = pcr.ifthen(wbCatchment ==\ pcr.areamaximum(wbCatchment, \ self.waterBodyIds),\ self.waterBodyIds) # = outlet ids self.waterBodyOut = pcr.ifthen(\ pcr.scalar(self.waterBodyIds) > 0.,\ self.waterBodyOut) # TODO: Please also consider endorheic lakes! # correcting water body ids self.waterBodyIds = pcr.ifthen(\ pcr.scalar(self.waterBodyIds) > 0.,\ pcr.subcatchment(ldd,self.waterBodyOut)) # boolean map for water body outlets: self.waterBodyOut = pcr.ifthen(\ pcr.scalar(self.waterBodyOut) > 0.,\ pcr.boolean(1)) # reservoir surface area (m2): if self.useNetCDF: resSfArea = 1000. * 1000. * \ vos.netcdf2PCRobjClone(self.ncFileInp,'resSfAreaInp', \ date_used, useDoy = 'yearly',\ cloneMapFileName = self.cloneMap) resSfArea = pcr.areaaverage(resSfArea, self.waterBodyIds) resSfArea = pcr.cover(resSfArea, 0.) # water body surface area (m2): (lakes and reservoirs) self.waterBodyArea = pcr.max(pcr.areatotal(\ pcr.cover(\ self.fracWat*self.cellArea, 0.0), self.waterBodyIds), pcr.areaaverage(\ pcr.cover(resSfArea, 0.0) , self.waterBodyIds)) self.waterBodyArea = pcr.ifthen(self.waterBodyArea > 0.,\ self.waterBodyArea) # correcting water body ids and outlets (exclude all water bodies with surfaceArea = 0) self.waterBodyIds = pcr.ifthen(self.waterBodyArea > 0., self.waterBodyIds) self.waterBodyOut = pcr.ifthen(pcr.boolean(self.waterBodyIds), self.waterBodyOut) # water body types: # - 2 = reservoirs (regulated discharge) # - 1 = lakes (weirFormula) # - 0 = non lakes or reservoirs (e.g. wetland) self.waterBodyTyp = pcr.nominal(0) if self.useNetCDF: self.waterBodyTyp = vos.netcdf2PCRobjClone(self.ncFileInp,'waterBodyTyp', \ date_used, useDoy = 'yearly',\ cloneMapFileName = self.cloneMap) # excluding wetlands (waterBodyTyp = 0) in all functions related to lakes/reservoirs # self.waterBodyTyp = pcr.ifthen(\ pcr.scalar(self.waterBodyTyp) > 0,\ pcr.nominal(self.waterBodyTyp)) self.waterBodyTyp = pcr.ifthen(\ pcr.scalar(self.waterBodyIds) > 0,\ pcr.nominal(self.waterBodyTyp)) self.waterBodyTyp = pcr.areamajority(self.waterBodyTyp,\ self.waterBodyIds) # choose only one type: either lake or reservoir self.waterBodyTyp = pcr.ifthen(\ pcr.scalar(self.waterBodyTyp) > 0,\ pcr.nominal(self.waterBodyTyp)) self.waterBodyTyp = pcr.ifthen(pcr.boolean(self.waterBodyIds), self.waterBodyTyp) # correcting lakes and reservoirs ids and outlets self.waterBodyIds = pcr.ifthen( pcr.scalar(self.waterBodyTyp) > 0, self.waterBodyIds) self.waterBodyOut = pcr.ifthen( pcr.scalar(self.waterBodyIds) > 0, self.waterBodyOut) # reservoir maximum capacity (m3): self.resMaxCap = pcr.scalar(0.0) self.waterBodyCap = pcr.scalar(0.0) if self.useNetCDF: self.resMaxCap = 1000. * 1000. * \ vos.netcdf2PCRobjClone(self.ncFileInp,'resMaxCapInp', \ date_used, useDoy = 'yearly',\ cloneMapFileName = self.cloneMap) self.resMaxCap = pcr.ifthen(self.resMaxCap > 0,\ self.resMaxCap) self.resMaxCap = pcr.areaaverage(self.resMaxCap,\ self.waterBodyIds) # water body capacity (m3): (lakes and reservoirs) self.waterBodyCap = pcr.cover( self.resMaxCap, 0.0) # Note: Most of lakes have capacities > 0. self.waterBodyCap = pcr.ifthen(pcr.boolean(self.waterBodyIds), self.waterBodyCap) # correcting water body types: # Reservoirs that have zero capacities will be assumed as lakes. self.waterBodyTyp = \ pcr.ifthen(pcr.scalar(self.waterBodyTyp) > 0.,\ self.waterBodyTyp) self.waterBodyTyp = pcr.ifthenelse(self.waterBodyCap > 0.,\ self.waterBodyTyp,\ pcr.ifthenelse(pcr.scalar(self.waterBodyTyp) == 2,\ pcr.nominal(1),\ self.waterBodyTyp)) # final corrections: self.waterBodyTyp = pcr.ifthen(self.waterBodyArea > 0.,\ self.waterBodyTyp) # make sure that all lakes and/or reservoirs have surface areas self.waterBodyTyp = \ pcr.ifthen(pcr.scalar(self.waterBodyTyp) > 0.,\ self.waterBodyTyp) # make sure that only types 1 and 2 will be considered in lake/reservoir functions self.waterBodyIds = pcr.ifthen(pcr.scalar(self.waterBodyTyp) > 0.,\ self.waterBodyIds) # make sure that all lakes and/or reservoirs have ids self.waterBodyOut = pcr.ifthen(pcr.scalar(self.waterBodyIds) > 0.,\ self.waterBodyOut) # make sure that all lakes and/or reservoirs have outlets # for a natural run (self.onlyNaturalWaterBodies == True) # which uses only the year 1900, assume all reservoirs are lakes if self.onlyNaturalWaterBodies == True and date_used == self.dateForNaturalCondition: logger.info( "Using only natural water bodies identified in the year 1900. All reservoirs in 1900 are assumed as lakes." ) self.waterBodyTyp = \ pcr.ifthen(pcr.scalar(self.waterBodyTyp) > 0.,\ pcr.nominal(1)) # check that all lakes and/or reservoirs have types, ids, surface areas and outlets: test = pcr.defined(self.waterBodyTyp) & pcr.defined(self.waterBodyArea) &\ pcr.defined(self.waterBodyIds) & pcr.boolean(pcr.areamaximum(pcr.scalar(self.waterBodyOut), self.waterBodyIds)) a, b, c = vos.getMinMaxMean( pcr.cover(pcr.scalar(test), 1.0) - pcr.scalar(1.0)) threshold = 1e-3 if abs(a) > threshold or abs(b) > threshold: logger.warning( "Missing information in some lakes and/or reservoirs.") # cropping only in the landmask region: self.fracWat = pcr.ifthen(self.landmask, self.fracWat) self.waterBodyIds = pcr.ifthen(self.landmask, self.waterBodyIds) self.waterBodyOut = pcr.ifthen(self.landmask, self.waterBodyOut) self.waterBodyArea = pcr.ifthen(self.landmask, self.waterBodyArea) self.waterBodyTyp = pcr.ifthen(self.landmask, self.waterBodyTyp) self.waterBodyCap = pcr.ifthen(self.landmask, self.waterBodyCap)
def main(): """ :ivar masterdem: digital elevation model :ivar dem: digital elevation model :ivar river: optional river map """ # Default values strRiver = 8 masterdem = "dem.map" step1dir = "step1" step2dir = "step2" workdir = "." inifile = "wflow_prepare.ini" recreate = False snapgaugestoriver = False try: opts, args = getopt.getopt(sys.argv[1:], "W:hI:f") except getopt.error as msg: usage(msg) for o, a in opts: if o == "-W": workdir = a if o == "-I": inifile = a if o == "-h": usage() if o == "-f": recreate = True pcr.setglobaloption("unitcell") os.chdir(workdir) config = OpenConf(workdir + "/" + inifile) masterdem = configget(config, "files", "masterdem", "dem.map") pcr.setclone(masterdem) strRiver = int(configget(config, "settings", "riverorder", "4")) try: gauges_x = config.get("settings", "gauges_x") gauges_y = config.get("settings", "gauges_y") except: print("gauges_x and gauges_y are required entries in the ini file") sys.exit(1) step1dir = configget(config, "directories", "step1dir", "step1") step2dir = configget(config, "directories", "step2dir", "step2") # upscalefactor = float(config.get("settings","upscalefactor")) corevolume = float(configget(config, "settings", "corevolume", "1E35")) catchmentprecipitation = float( configget(config, "settings", "catchmentprecipitation", "1E35")) corearea = float(configget(config, "settings", "corearea", "1E35")) outflowdepth = float( configget(config, "settings", "lddoutflowdepth", "1E35")) initialscale = int(configget(config, "settings", "initialscale", "1")) csize = float(configget(config, "settings", "cellsize", "1")) snapgaugestoriver = bool( int(configget(config, "settings", "snapgaugestoriver", "1"))) lddglobaloption = configget(config, "settings", "lddglobaloption", "lddout") pcr.setglobaloption(lddglobaloption) lu_water = configget(config, "files", "lu_water", "") lu_paved = configget(config, "files", "lu_paved", "") # X/Y coordinates of the gauges the system exec("X=tr.array(" + gauges_x + ")") exec("Y=tr.array(" + gauges_y + ")") tr.Verbose = 1 # make the directories to save results in mkoutputdirs(step1dir, step2dir) ldddem = readdem(initialscale, masterdem, step1dir) dem = ldddem try: catchmask = config.get("files", "catchment_mask") except: print("No catchment mask...") else: print("clipping DEM with mask.....") mask = pcr.readmap(catchmask) ldddem = pcr.ifthen(pcr.boolean(mask), ldddem) dem = pcr.ifthen(pcr.boolean(mask), dem) # See if there is a shape file of the river to burn in try: rivshp = config.get("files", "river") except: print("no river file specified") outletpointX = float( configget(config, "settings", "outflowpointX", "0.0")) outletpointY = float( configget(config, "settings", "outflowpointY", "0.0")) else: print("river file specified.....") try: outletpointX = float( configget(config, "settings", "outflowpointX", "0.0")) outletpointY = float( configget(config, "settings", "outflowpointY", "0.0")) except: print( "Need to specify the river outletpoint (a point at the end of the river within the current map)" ) exit(1) outletpointmap = tr.points_to_map(dem, outletpointX, outletpointY, 0.5) pcr.report(outletpointmap, step1dir + "/outletpoint.map") rivshpattr = config.get("files", "riverattr") pcr.report(dem * 0.0, step1dir + "/nilmap.map") thestr = ("gdal_translate -of GTiff " + step1dir + "/nilmap.map " + step1dir + "/riverburn.tif") os.system(thestr) os.system("gdal_rasterize -burn 1 -l " + rivshpattr + " " + rivshp + " " + step1dir + "/riverburn.tif") thestr = ("gdal_translate -of PCRaster " + step1dir + "/riverburn.tif " + step1dir + "/riverburn.map") os.system(thestr) riverburn = pcr.readmap(step1dir + "/riverburn.map") # Determine regional slope assuming that is the way the river should run pcr.setglobaloption("unitcell") demregional = pcr.windowaverage(dem, 100) ldddem = pcr.ifthenelse(riverburn >= 1.0, demregional - 1000, dem) pcr.setglobaloption("unittrue") upscalefactor = int(csize / pcr.celllength()) print("Creating ldd...") ldd = tr.lddcreate_save( step1dir + "/ldd.map", ldddem, recreate, outflowdepth=outflowdepth, corevolume=corevolume, catchmentprecipitation=catchmentprecipitation, corearea=corearea, ) print("Determining streamorder...") stro = pcr.streamorder(ldd) pcr.report(stro, step1dir + "/streamorder.map") strdir = pcr.ifthen(stro >= strRiver, stro) pcr.report(strdir, step1dir + "/streamorderrive.map") pcr.report(pcr.boolean(pcr.ifthen(stro >= strRiver, stro)), step1dir + "/rivers.map") pcr.setglobaloption("unittrue") # outlet (and other gauges if given) # TODO: check is x/y set if not skip this print("Outlet...") outlmap = tr.points_to_map(dem, X, Y, 0.5) if snapgaugestoriver: print("Snapping gauges to nearest river cells...") pcr.report(outlmap, step1dir + "/orggauges.map") outlmap = tr.snaptomap(outlmap, strdir) # noutletmap = tr.points_to_map(dem,XX,YY,0.5) # pcr.report(noutletmap,'noutlet.map') pcr.report(outlmap, step1dir + "/gauges.map") # check if there is a pre-define catchment map try: catchmask = config.get("files", "catchment_mask") except: print("No catchment mask, finding outlet") # Find catchment (overall) outlet = tr.find_outlet(ldd) sub = pcr.subcatch(ldd, outlet) pcr.report(sub, step1dir + "/catchment_overall.map") else: print("reading and converting catchment mask.....") os.system("resample -r " + str(initialscale) + " " + catchmask + " " + step1dir + "/catchment_overall.map") sub = pcr.readmap(step1dir + "/catchment_overall.map") print("Scatch...") sd = pcr.subcatch(ldd, pcr.ifthen(outlmap > 0, outlmap)) pcr.report(sd, step1dir + "/scatch.map") pcr.setglobaloption("unitcell") print("Upscalefactor: " + str(upscalefactor)) if upscalefactor > 1: gc.collect() print("upscale river length1 (checkerboard map)...") ck = tr.checkerboard(dem, upscalefactor) pcr.report(ck, step1dir + "/ck.map") pcr.report(dem, step1dir + "/demck.map") print("upscale river length2...") fact = tr.area_riverlength_factor(ldd, ck, upscalefactor) pcr.report(fact, step1dir + "/riverlength_fact.map") # print("make dem statistics...") dem_ = pcr.areaaverage(dem, ck) pcr.report(dem_, step1dir + "/demavg.map") print("Create DEM statistics...") dem_ = pcr.areaminimum(dem, ck) pcr.report(dem_, step1dir + "/demmin.map") dem_ = pcr.areamaximum(dem, ck) pcr.report(dem_, step1dir + "/demmax.map") # calculate percentiles order = pcr.areaorder(dem, ck) n = pcr.areatotal(pcr.spatial(pcr.scalar(1.0)), ck) #: calculate 25 percentile perc = tr.area_percentile(dem, ck, n, order, 25.0) pcr.report(perc, step1dir + "/dem25.map") perc = tr.area_percentile(dem, ck, n, order, 10.0) pcr.report(perc, step1dir + "/dem10.map") perc = tr.area_percentile(dem, ck, n, order, 50.0) pcr.report(perc, step1dir + "/dem50.map") perc = tr.area_percentile(dem, ck, n, order, 33.0) pcr.report(perc, step1dir + "/dem33.map") perc = tr.area_percentile(dem, ck, n, order, 66.0) pcr.report(perc, step1dir + "/dem66.map") perc = tr.area_percentile(dem, ck, n, order, 75.0) pcr.report(perc, step1dir + "/dem75.map") perc = tr.area_percentile(dem, ck, n, order, 90.0) pcr.report(perc, step1dir + "/dem90.map") else: print("No fancy scaling done. Going strait to step2....") pcr.report(dem, step1dir + "/demavg.map") Xul = float(config.get("settings", "Xul")) Yul = float(config.get("settings", "Yul")) Xlr = float(config.get("settings", "Xlr")) Ylr = float(config.get("settings", "Ylr")) gdalstr = ("gdal_translate -projwin " + str(Xul) + " " + str(Yul) + " " + str(Xlr) + " " + str(Ylr) + " -of PCRaster ") # gdalstr = "gdal_translate -a_ullr " + str(Xul) + " " + str(Yul) + " " +str(Xlr) + " " +str(Ylr) + " -of PCRaster " print(gdalstr) pcr.report(pcr.cover(1.0), step1dir + "/wflow_riverlength_fact.map") # Now us gdat tp convert the maps os.system(gdalstr + step1dir + "/wflow_riverlength_fact.map" + " " + step2dir + "/wflow_riverlength_fact.map") os.system(gdalstr + step1dir + "/demavg.map" + " " + step2dir + "/wflow_dem.map") os.system(gdalstr + step1dir + "/demavg.map" + " " + step2dir + "/wflow_demmin.map") os.system(gdalstr + step1dir + "/demavg.map" + " " + step2dir + "/wflow_demmax.map") os.system(gdalstr + step1dir + "/gauges.map" + " " + step2dir + "/wflow_gauges.map") os.system(gdalstr + step1dir + "/rivers.map" + " " + step2dir + "/wflow_river.map") os.system(gdalstr + step1dir + "/streamorder.map" + " " + step2dir + "/wflow_streamorder.map") os.system(gdalstr + step1dir + "/gauges.map" + " " + step2dir + "/wflow_outlet.map") os.system(gdalstr + step1dir + "/scatch.map" + " " + step2dir + "/wflow_catchment.map") os.system(gdalstr + step1dir + "/ldd.map" + " " + step2dir + "/wflow_ldd.map") os.system(gdalstr + step1dir + "/scatch.map" + " " + step2dir + "/wflow_subcatch.map") if lu_water: os.system(gdalstr + lu_water + " " + step2dir + "/WaterFrac.map") if lu_paved: os.system(gdalstr + lu_paved + " " + step2dir + "/PathFrac.map") try: lumap = config.get("files", "landuse") except: print("no landuse map...creating uniform map") # clone=pcr.readmap(step2dir + "/wflow_dem.map") pcr.setclone(step2dir + "/wflow_dem.map") pcr.report(pcr.nominal(1), step2dir + "/wflow_landuse.map") else: os.system("resample --clone " + step2dir + "/wflow_dem.map " + lumap + " " + step2dir + "/wflow_landuse.map") try: soilmap = config.get("files", "soil") except: print("no soil map..., creating uniform map") pcr.setclone(step2dir + "/wflow_dem.map") pcr.report(pcr.nominal(1), step2dir + "/wflow_soil.map") else: os.system("resample --clone " + step2dir + "/wflow_dem.map " + soilmap + " " + step2dir + "/wflow_soil.map") ################################## # Step 2 starts here ################################## pcr.setclone(step2dir + "/cutout.map") strRiver = int(configget(config, "settings", "riverorder_step2", "4")) corevolume = float(configget(config, "settings", "corevolume", "1E35")) catchmentprecipitation = float( configget(config, "settings", "catchmentprecipitation", "1E35")) corearea = float(configget(config, "settings", "corearea", "1E35")) outflowdepth = float( configget(config, "settings", "lddoutflowdepth", "1E35")) lddmethod = configget(config, "settings", "lddmethod", "dem") lddglobaloption = configget(config, "settings", "lddglobaloption", "lddout") pcr.setglobaloption(lddglobaloption) nrrow = round(abs(Yul - Ylr) / csize) nrcol = round(abs(Xlr - Xul) / csize) mapstr = ("mapattr -s -S -R " + str(nrrow) + " -C " + str(nrcol) + " -l " + str(csize) + " -x " + str(Xul) + " -y " + str(Yul) + " -P yb2t " + step2dir + "/cutout.map") os.system(mapstr) pcr.setclone(step2dir + "/cutout.map") lu_water = configget(config, "files", "lu_water", "") lu_paved = configget(config, "files", "lu_paved", "") if lu_water: os.system("resample --clone " + step2dir + "/cutout.map " + lu_water + " " + step2dir + "/wflow_waterfrac.map") if lu_paved: os.system("resample --clone " + step2dir + "/cutout.map " + lu_paved + " " + step2dir + "/PathFrac.map") # try: lumap = config.get("files", "landuse") except: print("no landuse map...creating uniform map") clone = pcr.readmap(step2dir + "/cutout.map") pcr.report(pcr.nominal(clone), step2dir + "/wflow_landuse.map") else: os.system("resample --clone " + step2dir + "/cutout.map " + lumap + " " + step2dir + "/wflow_landuse.map") try: soilmap = config.get("files", "soil") except: print("no soil map..., creating uniform map") clone = pcr.readmap(step2dir + "/cutout.map") pcr.report(pcr.nominal(clone), step2dir + "/wflow_soil.map") else: os.system("resample --clone " + step2dir + "/cutout.map " + soilmap + " " + step2dir + "/wflow_soil.map") resamplemaps(step1dir, step2dir) dem = pcr.readmap(step2dir + "/wflow_dem.map") demmin = pcr.readmap(step2dir + "/wflow_demmin.map") demmax = pcr.readmap(step2dir + "/wflow_demmax.map") catchcut = pcr.readmap(step2dir + "/catchment_cut.map") # now apply the area of interest (catchcut) to the DEM # dem=pcr.ifthen(catchcut >=1 , dem) # # See if there is a shape file of the river to burn in try: rivshp = config.get("files", "river") except: print("no river file specified") riverburn = pcr.readmap(step2dir + "/wflow_riverburnin.map") else: print("river file speficied.....") rivshpattr = config.get("files", "riverattr") pcr.report(dem * 0.0, step2dir + "/nilmap.map") thestr = ("gdal_translate -of GTiff " + step2dir + "/nilmap.map " + step2dir + "/wflow_riverburnin.tif") os.system(thestr) os.system("gdal_rasterize -burn 1 -l " + rivshpattr + " " + rivshp + " " + step2dir + "/wflow_riverburnin.tif") thestr = ("gdal_translate -of PCRaster " + step2dir + "/wflow_riverburnin.tif " + step2dir + "/wflow_riverburnin.map") os.system(thestr) riverburn = pcr.readmap(step2dir + "/wflow_riverburnin.map") # ldddem = pcr.ifthenelse(riverburn >= 1.0, dem -1000 , dem) # Only burn within the original catchment riverburn = pcr.ifthen(pcr.scalar(catchcut) >= 1, riverburn) # Now setup a very high wall around the catchment that is scale # based on the distance to the catchment so that it slopes away from the # catchment if lddmethod != "river": print("Burning in highres-river ...") disttocatch = pcr.spread(pcr.nominal(catchcut), 0.0, 1.0) demmax = pcr.ifthenelse( pcr.scalar(catchcut) >= 1.0, demmax, demmax + (pcr.celllength() * 100.0) / disttocatch, ) pcr.setglobaloption("unitcell") demregional = pcr.windowaverage(demmin, 100) demburn = pcr.cover( pcr.ifthen(pcr.boolean(riverburn), demregional - 100.0), demmax) else: print("using average dem..") demburn = dem ldd = tr.lddcreate_save( step2dir + "/ldd.map", demburn, True, outflowdepth=outflowdepth, corevolume=corevolume, catchmentprecipitation=catchmentprecipitation, corearea=corearea, ) # Find catchment (overall) outlet = tr.find_outlet(ldd) sub = pcr.subcatch(ldd, outlet) pcr.report(sub, step2dir + "/wflow_catchment.map") pcr.report(outlet, step2dir + "/wflow_outlet.map") # make river map strorder = pcr.streamorder(ldd) pcr.report(strorder, step2dir + "/wflow_streamorder.map") river = pcr.ifthen(pcr.boolean(strorder >= strRiver), strorder) pcr.report(river, step2dir + "/wflow_river.map") # make subcatchments # os.system("col2map --clone " + step2dir + "/cutout.map gauges.col " + step2dir + "/wflow_gauges.map") exec("X=tr.array(" + gauges_x + ")") exec("Y=tr.array(" + gauges_y + ")") pcr.setglobaloption("unittrue") outlmap = tr.points_to_map(dem, X, Y, 0.5) pcr.report(outlmap, step2dir + "/wflow_gauges_.map") if snapgaugestoriver: print("Snapping gauges to river") pcr.report(outlmap, step2dir + "/wflow_orggauges.map") outlmap = tr.snaptomap(outlmap, river) outlmap = pcr.ifthen(outlmap > 0, outlmap) pcr.report(outlmap, step2dir + "/wflow_gauges.map") scatch = pcr.subcatch(ldd, outlmap) pcr.report(scatch, step2dir + "/wflow_subcatch.map")
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