def dynamic(self): """ *Required* This is where all the time dependent functions are executed. Time dependent output should also be saved here. """ self.wf_updateparameters() # read the temperature map for each step (see parameters()) self.wf_multparameters() # needed so parameters can be altered in the inifile under [variable_change_once] # snow routine snowfall = self.precipitation snowfall = pcr.scalar(self.temperature < 3.0) * snowfall self.snow = self.snow + snowfall melt = (self.meltf * self.temperature) melt = pcr.scalar(self.temperature > 3.0) * melt melt = pcr.max(0.0, pcr.min(self.snow, melt)) self.snow = self.snow - melt self.precipitation = self.precipitation - snowfall + melt # soil storage self.PotenEvap = self.PET * self.cropf Peff = self.precipitation - self.PotenEvap Aw_1 = self.Available_water # Soil wetting below capacity self.whc = pcr.max(0.0, self.whc) self.below_cap = (Aw_1 + pcr.max(0.0, Peff)) <= self.whc self.available_water_below_cap = (self.Available_water * pcr.scalar(self.below_cap)) + (pcr.max(0.0, Peff) * pcr.scalar(self.below_cap)) # Soil wetting above capacity self.above_cap = (Aw_1 + Peff) > self.whc self.excess = (Aw_1 * pcr.scalar(self.above_cap)) + (Peff * pcr.scalar(self.above_cap)) - (self.whc * pcr.scalar(self.above_cap)) self.available_water_above_cap = (self.whc * pcr.scalar(self.above_cap)) self.Available_water = self.available_water_below_cap + self.available_water_above_cap # soil drying self.drying = Peff <= 0.0 self.exp_content = (Peff)/(self.whc) self.available_water_drying = (Aw_1 * pcr.scalar(self.drying)) * pcr.exp(self.exp_content) # soil that is not drying self.not_drying = Peff > 0.0 self.Available_water = self.Available_water * pcr.scalar(self.not_drying) self.Available_water = self.Available_water + self.available_water_drying self.excess = self.excess * pcr.scalar(self.not_drying) # seepage to groundwater self.runoff = self.togwf * self.excess self.togw = self.excess - self.runoff # adding water to groundwater and taking water from groundwater self.Ground_water = self.Ground_water + self.togw self.sloflo = (self.Ground_water/self.C) self.Ground_water = self.Ground_water - self.sloflo # adding water from groundwater to runoff self.runoff = self.runoff + self.sloflo
def upscale_riverlength(ldd, order, factor): """ Upscales the riverlength using 'factor' The resulting maps can be resampled (e.g. using resample.exe) by factor and should include the accurate length as determined with the original higher resolution maps. This function is **depricated**, use are_riverlength instead as this version is very slow for large maps Input: - ldd - minimum streamorder to include Output: - distance per factor cells """ strorder = pcr.streamorder(ldd) strorder = pcr.ifthen(strorder >= order, strorder) dist = pcr.cover( pcr.max(pcr.celllength(), pcr.ifthen(pcr.boolean(strorder), pcr.downstreamdist(ldd))), 0, ) totdist = pcr.max( pcr.ifthen( pcr.boolean(strorder), pcr.windowtotal(pcr.ifthen(pcr.boolean(strorder), dist), pcr.celllength() * factor), ), dist, ) return totdist
def additional_post_processing(self): # estimate of total groundwwater storage that is accesible (based on the assumption of a certain limit of pumping depth) if "accesibleGroundwaterVolume" or "accesibleGroundwaterThickness" in self.variables_for_report: if self._model.modflow.number_of_layers == 1: \ self.accesibleGroundwaterThickness = pcr.ifthen(self._model.landmask, \ self._model.modflow.specific_yield_1 * \ pcr.max(0.0, self.groundwaterHeadLayer1 - pcr.max(self._model.modflow.max_accesible_elevation, \ self._model.modflow.bottom_layer_1))) if self._model.modflow.number_of_layers == 2: \ self.accesibleGroundwaterThickness = pcr.ifthen(self._model.landmask, \ self._model.modflow.specific_yield_1 * \ pcr.max(0.0, self.groundwaterHeadLayer1 - pcr.max(self._model.modflow.max_accesible_elevation, \ self._model.modflow.bottom_layer_1))) + \ pcr.ifthen(self._model.landmask, \ self._model.modflow.specific_yield_2 * \ pcr.max(0.0, self.groundwaterHeadLayer1 - pcr.max(self._model.modflow.max_accesible_elevation, \ self._model.modflow.bottom_layer_2))) self.accesibleGroundwaterVolume = self.accesibleGroundwaterThickness *\ self._model.modflow.cellAreaMap # TODO: Make the reporting of accesibleGroundwaterThickness more generic. # report elevation in pcraster map self.top_uppermost_layer = pcr.ifthen(self._model.landmask, self._model.modflow.top_layer_2) self.bottom_uppermost_layer = pcr.ifthen( self._model.landmask, self._model.modflow.bottom_layer_2) self.bottom_lowermost_layer = pcr.ifthen( self._model.landmask, self._model.modflow.bottom_layer_1)
def estimate_bottom_of_bank_storage(self): # influence zone depth (m) # TODO: Define this one as part of influence_zone_depth = 5.0 # bottom_elevation > flood_plain elevation - influence zone bottom_of_bank_storage = self.dem_floodplain - influence_zone_depth # reducing noise (so we will not introduce unrealistic sinks) # TODO: Define the window size as part of the configuration/ini file bottom_of_bank_storage = pcr.max(bottom_of_bank_storage,\ pcr.windowaverage(bottom_of_bank_storage, 3.0 * pcr.clone().cellSize())) # bottom_elevation > river bed bottom_of_bank_storage = pcr.max(self.dem_riverbed, bottom_of_bank_storage) # reducing noise by comparing to its downstream value (so we will not introduce unrealistic sinks) bottom_of_bank_storage = pcr.max(bottom_of_bank_storage, \ (bottom_of_bank_storage + pcr.cover(pcr.downstream(self.lddMap, bottom_of_bank_storage), bottom_of_bank_storage))/2.) # bottom_elevation >= 0.0 (must be higher than sea level) bottom_of_bank_storage = pcr.max(0.0, bottom_of_bank_storage) # bottom_elevation < dem_average (this is to drain overland flow) bottom_of_bank_storage = pcr.min(bottom_of_bank_storage, self.dem_average) bottom_of_bank_storage = pcr.cover(bottom_of_bank_storage, self.dem_average) # TODO: Check again this concept. # TODO: We may want to improve this concept - by incorporating the following # - smooth bottom_elevation # - upstream areas in the mountainous regions and above perrenial stream starting points may also be drained (otherwise water will accumulate) # - bottom_elevation > minimum elevation that is estimated from the maximum of S3 from the PCR-GLOBWB simulation return bottom_of_bank_storage
def estimate_bottom_of_bank_storage(self): # influence zone depth (m) influence_zone_depth = 0.50 # bottom_elevation > flood_plain elevation - influence zone bottom_of_bank_storage = self.dem_floodplain - influence_zone_depth #~ # bottom_elevation > river bed #~ bottom_of_bank_storage = pcr.max(self.dem_riverbed, bottom_of_bank_storage) # bottom_elevation > its downstream value bottom_of_bank_storage = pcr.max(bottom_of_bank_storage, \ pcr.cover(pcr.downstream(self.lddMap, bottom_of_bank_storage), bottom_of_bank_storage)) # bottom_elevation >= 0.0 (must be higher than sea level) bottom_of_bank_storage = pcr.max(0.0, bottom_of_bank_storage) # reducing noise bottom_of_bank_storage = pcr.max(bottom_of_bank_storage,\ pcr.windowaverage(bottom_of_bank_storage, 3.0 * pcr.clone().cellSize())) # bottom_elevation < dem_average bottom_of_bank_storage = pcr.min(bottom_of_bank_storage, self.dem_average) bottom_of_bank_storage = pcr.cover(bottom_of_bank_storage, self.dem_average) # TODO: Check again this concept. # TODO: We may want to improve this concept - by incorporating the following # - smooth bottom_elevation # - upstream areas in the mountainous regions and above perrenial stream starting points may also be drained (otherwise water will accumulate) # - bottom_elevation > minimum elevation that is estimated from the maximum of S3 from the PCR-GLOBWB simulation return bottom_of_bank_storage
def downscalePrecipitation(self, currTimeStep, useFactor=True, minCorrelationCriteria=0.85): preSlope = 0.001 * vos.netcdf2PCRobjClone(\ self.precipLapseRateNC, 'precipitation',\ currTimeStep.month, useDoy = "Yes",\ cloneMapFileName=self.cloneMap,\ LatitudeLongitude = True) preSlope = pcr.cover(preSlope, 0.0) preSlope = pcr.max(0., preSlope) preCriteria = vos.netcdf2PCRobjClone(\ self.precipitCorrelNC, 'precipitation',\ currTimeStep.month, useDoy = "Yes",\ cloneMapFileName=self.cloneMap,\ LatitudeLongitude = True) preSlope = pcr.ifthenelse(preCriteria > minCorrelationCriteria,\ preSlope, 0.0) preSlope = pcr.cover(preSlope, 0.0) if useFactor == True: factor = pcr.max(0., self.precipitation + preSlope * self.anomalyDEM) factor = factor / \ pcr.areaaverage(factor, self.meteoDownscaleIds) factor = pcr.cover(factor, 1.0) self.precipitation = factor * self.precipitation else: self.precipitation = self.precipitation + preSlope * self.anomalyDEM self.precipitation = pcr.max(0.0, self.precipitation)
def returnFloodedFraction(self,volume): #-returns the flooded fraction given the flood volume and the associated water height # using a logistic smoother near intersections (K&K, 2007) #-find the match on the basis of the shortest distance to the available intersections or steps deltaXMin= self.floodVolume[self.nrEntries-1] y_i= pcr.scalar(1.) k= [pcr.scalar(0.)]*2 mInt= pcr.scalar(0.) for iCnt in range(self.nrEntries-1,0,-1): #-find x_i for current volume and update match if applicable # also update slope and intercept deltaX= volume-self.floodVolume[iCnt] mask= pcr.abs(deltaX) < pcr.abs(deltaXMin) deltaXMin= pcr.ifthenelse(mask,deltaX,deltaXMin) y_i= pcr.ifthenelse(mask,self.areaFractions[iCnt],y_i) k[0]= pcr.ifthenelse(mask,self.kSlope[iCnt-1],k[0]) k[1]= pcr.ifthenelse(mask,self.kSlope[iCnt],k[1]) mInt= pcr.ifthenelse(mask,self.mInterval[iCnt],mInt) #-all values returned, process data: calculate scaled deltaX and smoothed function # on the basis of the integrated logistic functions PHI(x) and 1-PHI(x) deltaX= deltaXMin deltaXScaled= pcr.ifthenelse(deltaX < 0.,pcr.scalar(-1.),1.)*\ pcr.min(criterionKK,pcr.abs(deltaX/pcr.max(1.,mInt))) logInt= self.integralLogisticFunction(deltaXScaled) #-compute fractional flooded area and flooded depth floodedFraction= pcr.ifthenelse(volume > 0.,\ pcr.ifthenelse(pcr.abs(deltaXScaled) < criterionKK,\ y_i-k[0]*mInt*logInt[0]+k[1]*mInt*logInt[1],\ y_i+pcr.ifthenelse(deltaX < 0.,k[0],k[1])*deltaX),0.) floodedFraction= pcr.max(0.,pcr.min(1.,floodedFraction)) floodDepth= pcr.ifthenelse(floodedFraction > 0.,volume/(floodedFraction*self.cellArea),0.) return floodedFraction, floodDepth
def returnFloodedFraction(self, volume): #-returns the flooded fraction given the flood volume and the associated water height # using a logistic smoother near intersections (K&K, 2007) #-find the match on the basis of the shortest distance to the available intersections or steps deltaXMin = self.floodVolume[self.nrEntries - 1] y_i = pcr.scalar(1.) k = [pcr.scalar(0.)] * 2 mInt = pcr.scalar(0.) for iCnt in range(self.nrEntries - 1, 0, -1): #-find x_i for current volume and update match if applicable # also update slope and intercept deltaX = volume - self.floodVolume[iCnt] mask = pcr.abs(deltaX) < pcr.abs(deltaXMin) deltaXMin = pcr.ifthenelse(mask, deltaX, deltaXMin) y_i = pcr.ifthenelse(mask, self.areaFractions[iCnt], y_i) k[0] = pcr.ifthenelse(mask, self.kSlope[iCnt - 1], k[0]) k[1] = pcr.ifthenelse(mask, self.kSlope[iCnt], k[1]) mInt = pcr.ifthenelse(mask, self.mInterval[iCnt], mInt) #-all values returned, process data: calculate scaled deltaX and smoothed function # on the basis of the integrated logistic functions PHI(x) and 1-PHI(x) deltaX = deltaXMin deltaXScaled= pcr.ifthenelse(deltaX < 0.,pcr.scalar(-1.),1.)*\ pcr.min(criterionKK,pcr.abs(deltaX/pcr.max(1.,mInt))) logInt = self.integralLogisticFunction(deltaXScaled) #-compute fractional flooded area and flooded depth floodedFraction= pcr.ifthenelse(volume > 0.,\ pcr.ifthenelse(pcr.abs(deltaXScaled) < criterionKK,\ y_i-k[0]*mInt*logInt[0]+k[1]*mInt*logInt[1],\ y_i+pcr.ifthenelse(deltaX < 0.,k[0],k[1])*deltaX),0.) floodedFraction = pcr.max(0., pcr.min(1., floodedFraction)) floodDepth = pcr.ifthenelse(floodedFraction > 0., volume / (floodedFraction * self.cellArea), 0.) return floodedFraction, floodDepth
def moveFromChannelToWaterBody(self,\ newStorageAtLakeAndReservoirs,\ timestepsToAvgDischarge,\ maxTimestepsToAvgDischargeShort,\ length_of_time_step = vos.secondsPerDay()): # new lake and/or reservoir storages (m3) newStorageAtLakeAndReservoirs = pcr.cover(\ pcr.areatotal(newStorageAtLakeAndReservoirs,\ self.waterBodyIds),0.0) # incoming volume (m3) self.inflow = newStorageAtLakeAndReservoirs - self.waterBodyStorage # inflowInM3PerSec (m3/s) inflowInM3PerSec = self.inflow / length_of_time_step # updating (short term) average inflow (m3/s) ; # - needed to constrain lake outflow: # temp = pcr.max(1.0, pcr.min(maxTimestepsToAvgDischargeShort, self.timestepsToAvgDischarge - 1.0 + length_of_time_step / vos.secondsPerDay())) deltaInflow = inflowInM3PerSec - self.avgInflow R = deltaInflow * ( length_of_time_step / vos.secondsPerDay() ) / temp self.avgInflow = self.avgInflow + R self.avgInflow = pcr.max(0.0, self.avgInflow) # # for the reference, see the "weighted incremental algorithm" in http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance # updating waterBodyStorage (m3) self.waterBodyStorage = newStorageAtLakeAndReservoirs
def agriZone_Ep_Sa_beta(self, k): """ - Potential evaporation is decreased by energy used for interception evaporation - Formula for evaporation based on LP - Outgoing fluxes are determined based on (value in previous timestep + inflow) and if this leads to negative storage, the outgoing fluxes are corrected to rato --> Eu is no longer taken into account for this correction - Qa u is determined from overflow from Sa --> incorporation of beta function - Fa is based on storage in Sa - Code for ini-file: 6 """ JarvisCoefficients.calcEp(self, k) self.PotEvaporation = pcr.cover( pcr.ifthenelse(self.EpHour >= 0, self.EpHour, 0), 0) self.samax2 = self.samax[k] * pcr.scalar(self.catchArea) self.Qaadd = pcr.max(self.Sa_t[k] + self.Pe - self.samax2, 0) self.Sa[k] = self.Sa_t[k] + (self.Pe - self.Qaadd) self.SaN = pcr.min(pcr.max(self.Sa[k] / self.samax2, 0), 1) self.SuN = self.Su[k] / self.sumax[k] self.Ea1 = pcr.max((self.PotEvaporation - self.Ei), 0) * pcr.min( self.Sa[k] / (self.samax2 * self.LP[k]), 1) self.Qa1 = (self.Pe - self.Qaadd) * (1 - (1 - self.SaN)**self.beta[k]) self.Fa1 = pcr.ifthenelse( self.SaN > 0, self.Fmin[k] + (self.Fmax[k] - self.Fmin[k]) * e**(-self.decF[k] * (1 - self.SaN)), 0, ) self.Sa[k] = self.Sa_t[k] + (self.Pe - self.Qaadd) - self.Qa1 - self.Fa1 - self.Ea1 self.Sa_diff = pcr.ifthenelse(self.Sa[k] < 0, self.Sa[k], 0) self.Qa = (self.Qa1 + (self.Qa1 / pcr.ifthenelse(self.Fa1 + self.Ea1 + self.Qa1 > 0, self.Fa1 + self.Ea1 + self.Qa1, 1)) * self.Sa_diff) self.Fa = (self.Fa1 + (self.Fa1 / pcr.ifthenelse(self.Fa1 + self.Ea1 + self.Qa1 > 0, self.Fa1 + self.Ea1 + self.Qa1, 1)) * self.Sa_diff) self.Ea = (self.Ea1 + (self.Ea1 / pcr.ifthenelse(self.Fa1 + self.Ea1 + self.Qa1 > 0, self.Fa1 + self.Ea1 + self.Qa1, 1)) * self.Sa_diff) self.Sa[k] = self.Sa_t[k] + (self.Pe - self.Qaadd) - self.Ea - self.Fa - self.Qa self.Sa[k] = pcr.ifthenelse(self.Sa[k] < 0, 0, self.Sa[k]) self.Sa_diff2 = pcr.ifthen(self.Sa[k] < 0, self.Sa[k]) self.wbSa_[k] = (self.Pe - self.Ea - self.Qa - self.Qaadd - self.Fa - self.Sa[k] + self.Sa_t[k]) self.Ea_[k] = self.Ea self.Qa_[k] = self.Qa + self.Qaadd self.Fa_[k] = self.Fa
def getWaterBodyOutflow( self, maxTimestepsToAvgDischargeLong, avgChannelDischarge, length_of_time_step=vos.secondsPerDay(), downstreamDemand=None, ): # outflow in volume from water bodies with lake type (m3): lakeOutflow = self.getLakeOutflow(avgChannelDischarge, length_of_time_step) # outflow in volume from water bodies with reservoir type (m3): if isinstance(downstreamDemand, types.NoneType): downstreamDemand = pcr.scalar(0.0) reservoirOutflow = self.getReservoirOutflow(avgChannelDischarge, length_of_time_step, downstreamDemand) # outgoing/release volume from lakes and/or reservoirs self.waterBodyOutflow = pcr.cover(reservoirOutflow, lakeOutflow) # make sure that all water bodies have outflow: self.waterBodyOutflow = pcr.max(0., pcr.cover(self.waterBodyOutflow, 0.0)) # limit outflow to available storage factor = 0.25 # to avoid flip flop self.waterBodyOutflow = pcr.min(self.waterBodyStorage * factor, self.waterBodyOutflow) # unit: m3 # use round values self.waterBodyOutflow = (pcr.rounddown(self.waterBodyOutflow / 1.) * 1. ) # unit: m3 # outflow rate in m3 per sec waterBodyOutflowInM3PerSec = (self.waterBodyOutflow / length_of_time_step) # unit: m3/s # updating (long term) average outflow (m3/s) ; # - needed to constrain/maintain reservoir outflow: # temp = pcr.max( 1.0, pcr.min( maxTimestepsToAvgDischargeLong, self.timestepsToAvgDischarge - 1.0 + length_of_time_step / vos.secondsPerDay(), ), ) deltaOutflow = waterBodyOutflowInM3PerSec - self.avgOutflow R = deltaOutflow * (length_of_time_step / vos.secondsPerDay()) / temp self.avgOutflow = self.avgOutflow + R self.avgOutflow = pcr.max(0.0, self.avgOutflow) # # for the reference, see the "weighted incremental algorithm" in http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance # update waterBodyStorage (after outflow): self.waterBodyStorage = self.waterBodyStorage - self.waterBodyOutflow self.waterBodyStorage = pcr.max(0.0, self.waterBodyStorage)
def downscaleReferenceETPot(self, zeroCelciusInKelvin=273.15): temperatureInKelvin = self.temperature + zeroCelciusInKelvin factor = pcr.max(0.0, temperatureInKelvin) factor = factor / \ pcr.areaaverage(factor, self.meteoDownscaleIds) factor = pcr.cover(factor, 1.0) self.referencePotET = pcr.max(0.0, factor * self.referencePotET)
def SnowPackHBV(Snow, SnowWater, Precipitation, Temperature, TTI, TT, TTM, Cfmax, WHC): """ HBV Type snowpack modelling using a Temperature degree factor. All correction factors (RFCF and SFCF) are set to 1. The refreezing efficiency factor is set to 0.05. :param Snow: :param SnowWater: :param Precipitation: :param Temperature: :param TTI: :param TT: :param TTM: :param Cfmax: :param WHC: :return: Snow,SnowMelt,Precipitation """ RFCF = 1.0 # correction factor for rainfall CFR = 0.05000 # refreeing efficiency constant in refreezing of freewater in snow SFCF = 1.0 # correction factor for snowfall RainFrac = pcr.ifthenelse( 1.0 * TTI == 0.0, pcr.ifthenelse(Temperature <= TT, pcr.scalar(0.0), pcr.scalar(1.0)), pcr.min((Temperature - (TT - TTI / 2)) / TTI, pcr.scalar(1.0)), ) RainFrac = pcr.max( RainFrac, pcr.scalar(0.0)) # fraction of precipitation which falls as rain SnowFrac = 1 - RainFrac # fraction of precipitation which falls as snow Precipitation = (SFCF * SnowFrac * Precipitation + RFCF * RainFrac * Precipitation ) # different correction for rainfall and snowfall SnowFall = SnowFrac * Precipitation # snowfall depth RainFall = RainFrac * Precipitation # rainfall depth PotSnowMelt = pcr.ifthenelse( Temperature > TTM, Cfmax * (Temperature - TTM), pcr.scalar(0.0)) # Potential snow melt, based on temperature PotRefreezing = pcr.ifthenelse( Temperature < TTM, Cfmax * CFR * (TTM - Temperature), 0.0) # Potential refreezing, based on temperature Refreezing = pcr.ifthenelse(Temperature < TTM, pcr.min(PotRefreezing, SnowWater), 0.0) # actual refreezing # No landuse correction here SnowMelt = pcr.min(PotSnowMelt, Snow) # actual snow melt Snow = Snow + SnowFall + Refreezing - SnowMelt # dry snow content SnowWater = SnowWater - Refreezing # free water content in snow MaxSnowWater = Snow * WHC # Max water in the snow SnowWater = (SnowWater + SnowMelt + RainFall ) # Add all water and potentially supersaturate the snowpack RainFall = pcr.max(SnowWater - MaxSnowWater, 0.0) # rain + surpluss snowwater SnowWater = SnowWater - RainFall return Snow, SnowWater, SnowMelt, RainFall, SnowFall
def volume_spread(ldd, hand, subcatch, volume, volume_thres=0., area_multiplier=1., iterations=15): """ Estimate 2D flooding from a 1D simulation per subcatchment reach Input: ldd -- pcraster object direction, local drain directions hand -- pcraster object float32, elevation data normalised to nearest drain subcatch -- pcraster object ordinal, subcatchments with IDs volume -- pcraster object float32, scalar flood volume (i.e. m3 volume outside the river bank within subcatchment) volume_thres=0. -- scalar threshold, at least this amount of m3 of volume should be present in a catchment area_multiplier=1. -- in case the maps are not in m2, set a multiplier other than 1. to convert iterations=15 -- number of iterations to use Output: inundation -- pcraster object float32, scalar inundation estimate """ #initial values pcr.setglobaloption("unittrue") dem_min = pcr.areaminimum(hand, subcatch) # minimum elevation in subcatchments # pcr.report(dem_min, 'dem_min.map') dem_norm = hand - dem_min # pcr.report(dem_norm, 'dem_norm.map') # surface of each subcatchment surface = pcr.areaarea(subcatch) * area_multiplier pcr.report(surface, 'surface.map') error_abs = pcr.scalar(1e10) # initial error (very high) volume_catch = pcr.areatotal(volume, subcatch) # pcr.report(volume_catch, 'volume_catch.map') depth_catch = volume_catch / surface pcr.report(depth_catch, 'depth_catch.map') dem_max = pcr.ifthenelse(volume_catch > volume_thres, pcr.scalar(32.), pcr.scalar(0)) # bizarre high inundation depth dem_min = pcr.scalar(0.) for n in range(iterations): print('Iteration: {:02d}'.format(n + 1)) #####while np.logical_and(error_abs > error_thres, dem_min < dem_max): dem_av = (dem_min + dem_max) / 2 # pcr.report(dem_av, 'dem_av00.{:03d}'.format(n + 1)) # compute value at dem_av average_depth_catch = pcr.areaaverage(pcr.max(dem_av - dem_norm, 0), subcatch) # pcr.report(average_depth_catch, 'depth_c0.{:03d}'.format(n + 1)) error = pcr.cover((depth_catch - average_depth_catch) / depth_catch, depth_catch * 0) # pcr.report(error, 'error000.{:03d}'.format(n + 1)) dem_min = pcr.ifthenelse(error > 0, dem_av, dem_min) dem_max = pcr.ifthenelse(error <= 0, dem_av, dem_max) # error_abs = np.abs(error) # TODO: not needed probably, remove inundation = pcr.max(dem_av - dem_norm, 0) return inundation
def diffuseTransportXY(dMat,fracX,fracY): #-evaluates transport in the four cardinal directions with the # shift function (1: up, left; -1: right, down), returning the # resulting change at each location dMatWest= pcr.max(0,pcr.shift0(-fracX*dMat, 0, 1)) dMatEast= pcr.max(0,pcr.shift0( fracX*dMat, 0,-1)) dMatNorth= pcr.max(0,pcr.shift0( fracY*dMat, 1, 0)) dMatSouth= pcr.max(0,pcr.shift0(-fracY*dMat,-1, 0)) return -dMat+dMatNorth+dMatEast+dMatSouth+dMatWest
def initial(self): ##################### # * initial section # ##################### #-constants # betaQ [-]: constant of kinematic wave momentum equation self.betaQ = 0.6 #-channel LDD self.channelLDD= pcr.ifthenelse(self.waterBodies.distribution != 0,\ pcr.ldd(5),self.LDD) #-channel area and storage self.channelArea = self.channelWidth * self.channelLength self.channelStorageCapacity= pcr.ifthenelse(self.waterBodies.distribution == 0,\ self.channelArea*self.channelDepth,pcr.scalar(0.)) #-basin outlets self.basinOutlet = pcr.pit(self.LDD) != 0 #-read initial conditions self.Q = clippedRead.get(self.QIniMap) self.actualStorage = clippedRead.get(self.actualStorageIniMap) self.actualStorage= pcr.ifthenelse(self.waterBodies.distribution != 0,\ pcr.ifthenelse(self.waterBodies.location != 0,\ pcr.areatotal(self.actualStorage,self.waterBodies.distribution),0),\ self.actualStorage) self.waterBodies.actualStorage = self.waterBodies.retrieveMapValue( self.actualStorage) #-update targets of average and bankful discharge self.waterBodies.averageQ = self.waterBodies.retrieveMapValue( self.averageQ) self.waterBodies.bankfulQ = self.waterBodies.retrieveMapValue( self.bankfulQ) #-return the parameters for the kinematic wave, # including alpha, wetted area, flood fraction, flood volume and depth # and the corresponding land area 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) #-update on velocity and check on Q - NOTE: does not work in case of reservoirs! self.flowVelocity = pcr.ifthenelse(self.wettedArea > 0, self.Q / self.wettedArea, 0.) pcr.report( self.flowVelocity, pcrm.generateNameT(flowVelocityFileName, 0).replace('.000', '.ini')) #-setting initial values for specific runoff and surface water extraction self.landSurfaceQ = pcr.scalar(0.) self.potWaterSurfaceQ = pcr.scalar(0.) self.surfaceWaterExtraction = pcr.scalar(0.) #-budget check: setting initial values for cumulative discharge and # net cumulative input, including initial storage [m3] self.totalDischarge = pcr.scalar(0.) self.cumulativeDeltaStorage = pcr.catchmenttotal( self.actualStorage, self.LDD)
def possiblyAdjustSoilMoistureThickWhenRegolithThicknessChanges(self): amountOfMoistureThickAdded = pcr.max( 0, self.wiltingPointThick - self.soilMoistureThick) amountOfMoistureThickRemoved = pcr.max( 0, self.soilMoistureThick - self.soilPorosityThick) amountOfMoistureThickNetAdded = amountOfMoistureThickAdded - amountOfMoistureThickRemoved self.soilMoistureThick = pcr.min( pcr.max(self.soilMoistureThick, self.wiltingPointThick), self.soilPorosityThick) return amountOfMoistureThickNetAdded
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 getICs(self, iniItems, iniConditions=None): #print iniItems.groundwaterOptions['storGroundwaterFossilIni'] # initial condition for storGroundwater (unit: m) if iniConditions == None: # when the model just start self.storGroundwater = vos.readPCRmapClone(\ iniItems.groundwaterOptions['storGroundwaterIni'], self.cloneMap,self.tmpDir,self.inputDir) self.avgAbstraction = vos.readPCRmapClone(\ iniItems.groundwaterOptions['avgTotalGroundwaterAbstractionIni'], self.cloneMap,self.tmpDir,self.inputDir) else: # during/after spinUp self.storGroundwater = iniConditions['groundwater'][ 'storGroundwater'] self.avgAbstraction = iniConditions['groundwater'][ 'avgTotalGroundwaterAbstractionIni'] # initial condition for storGroundwaterFossil (unit: m) # # Note that storGroundwaterFossil should not be depleted during the spin-up. # if iniItems.groundwaterOptions['storGroundwaterFossilIni'] != "Maximum": #logger.info("Using a pre-defined initial condition for fossil groundwater storage.") self.storGroundwaterFossil = vos.readPCRmapClone(\ iniItems.groundwaterOptions['storGroundwaterFossilIni'], self.cloneMap,self.tmpDir,self.inputDir) # if self.limitFossilGroundwaterAbstraction and iniItems.groundwaterOptions[ 'storGroundwaterFossilIni'] != "Maximum": #logger.info("The pre-defined initial condition for fossil groundwater is limited by fossilWaterCap (full capacity).") self.storGroundwaterFossil = pcr.min(self.storGroundwaterFossil, self.fossilWaterCap) # if self.limitFossilGroundwaterAbstraction and iniItems.groundwaterOptions[ 'storGroundwaterFossilIni'] == "Maximum": #logger.info("Assuming 'full' fossilWaterCap as the initial condition for fossil groundwater storage.") self.storGroundwaterFossil = self.fossilWaterCap # make sure that active storGroundwater and avgAbstraction cannot be negative # self.storGroundwater = pcr.cover(self.storGroundwater, 0.0) self.storGroundwater = pcr.max(0., self.storGroundwater) self.storGroundwater = pcr.ifthen(self.landmask,\ self.storGroundwater) # self.avgAbstraction = pcr.cover(self.avgAbstraction, 0.0) self.avgAbstraction = pcr.max(0., self.avgAbstraction) self.avgAbstraction = pcr.ifthen(self.landmask,\ self.avgAbstraction) # storGroundwaterFossil can be negative (particularly if limitFossilGroundwaterAbstraction == False) self.storGroundwaterFossil = pcr.ifthen(self.landmask,\ self.storGroundwaterFossil)
def agriZone_Ep_Sa_cropG(self, k): """ - Potential evaporation is decreased by energy used for interception evaporation - Formula for evaporation based on LP - Outgoing fluxes are determined based on (value in previous timestep + inflow) and if this leads to negative storage, the outgoing fluxes are corrected to rato --> Eu is no longer taken into account for this correction - Qa u is determined from overflow from Sa - Fa is based on storage in Sa - Code for ini-file: 4 """ JarvisCoefficients.calcEp(self, k) self.PotEvaporation = pcr.cover(pcr.ifthenelse(self.EpHour >= 0, self.EpHour, 0), 0) self.samax2 = self.samax[k] * self.cropG self.Qaadd = pcr.max(self.Sa_t[k] - self.samax2, 0) self.Qa = pcr.max(self.Pe - (self.samax2 - self.Sa_t[k]), 0) + self.Qaadd self.Sa[k] = self.Sa_t[k] + (self.Pe - self.Qa) self.SaN = pcr.min(self.Sa[k] / self.samax2, 1) self.SuN = self.Su[k] / self.sumax[k] self.Ea1 = pcr.max((self.PotEvaporation - self.Ei), 0) * pcr.min( self.Sa[k] / (self.samax2 * self.LP[k]), 1 ) self.Fa1 = pcr.ifthenelse( self.SaN > 0, self.Fmin[k] + (self.Fmax[k] - self.Fmin[k]) * e ** (-self.decF[k] * (1 - self.SaN)), 0, ) self.Sa[k] = self.Sa_t[k] + (self.Pe - self.Qa) - self.Fa1 - self.Ea1 self.Sa_diff = pcr.ifthenelse(self.Sa[k] < 0, self.Sa[k], 0) self.Fa = ( self.Fa1 + (self.Fa1 / pcr.ifthenelse(self.Fa1 + self.Ea1 > 0, self.Fa1 + self.Ea1, 1)) * self.Sa_diff ) self.Ea = ( self.Ea1 + (self.Ea1 / pcr.ifthenelse(self.Fa1 + self.Ea1 > 0, self.Fa1 + self.Ea1, 1)) * self.Sa_diff ) self.Sa[k] = self.Sa_t[k] + (self.Pe - self.Qa) - self.Ea - self.Fa self.Sa[k] = pcr.ifthenelse(self.Sa[k] < 0, 0, self.Sa[k]) self.Sa_diff2 = pcr.ifthen(self.Sa[k] < 0, self.Sa[k]) self.wbSa_[k] = self.Pe - self.Ea - self.Qa - self.Fa - self.Sa[k] + self.Sa_t[k] self.Ea_[k] = self.Ea self.Qa_[k] = self.Qa self.Fa_[k] = self.Fa
def readTopo(self, iniItems): # maps of elevation attributes: topoParams = ['tanslope', 'slopeLength', 'orographyBeta'] if iniItems.landSurfaceOptions['topographyNC'] == str(None): for var in topoParams: input = iniItems.landSurfaceOptions[str(var)] vars(self)[var] = pcr.scalar(0.0) vars(self)[var] = vos.readPCRmapClone(input, self.cloneMap, self.tmpDir, self.inputDir) vars(self)[var] = pcr.cover(vars(self)[var], 0.0) else: topoPropertiesNC = vos.getFullPath(\ iniItems.landSurfaceOptions[\ 'topographyNC'], self.inputDir) for var in topoParams: vars(self)[var] = vos.netcdf2PCRobjCloneWithoutTime(\ topoPropertiesNC,var, \ cloneMapFileName = self.cloneMap) vars(self)[var] = pcr.cover(vars(self)[var], 0.0) self.tanslope = pcr.max(self.tanslope, 0.00001) # maps of relative elevation above flood plains dzRel = [ 'dzRel0001', 'dzRel0005', 'dzRel0010', 'dzRel0020', 'dzRel0030', 'dzRel0040', 'dzRel0050', 'dzRel0060', 'dzRel0070', 'dzRel0080', 'dzRel0090', 'dzRel0100' ] if iniItems.landSurfaceOptions['topographyNC'] == str(None): for i in range(0, len(dzRel)): var = dzRel[i] input = iniItems.landSurfaceOptions[str(var)] vars(self)[var] = vos.readPCRmapClone(input, self.cloneMap, self.tmpDir, self.inputDir) vars(self)[var] = pcr.cover(vars(self)[var], 0.0) if i > 0: vars(self)[var] = pcr.max( vars(self)[var], vars(self)[dzRel[i - 1]]) else: for i in range(0, len(dzRel)): var = dzRel[i] vars(self)[var] = vos.netcdf2PCRobjCloneWithoutTime(\ topoPropertiesNC,var, \ cloneMapFileName = self.cloneMap) vars(self)[var] = pcr.cover(vars(self)[var], 0.0) if i > 0: vars(self)[var] = pcr.max( vars(self)[var], vars(self)[dzRel[i - 1]])
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 volume_spread(ldd, hand, subcatch, volume, volume_thres=0., cell_surface=1., iterations=15, logging=logging, order=0): """ Estimate 2D flooding from a 1D simulation per subcatchment reach Input: ldd -- pcraster object direction, local drain directions hand -- pcraster object float32, elevation data normalised to nearest drain subcatch -- pcraster object ordinal, subcatchments with IDs volume -- pcraster object float32, scalar flood volume (i.e. m3 volume outside the river bank within subcatchment) volume_thres=0. -- scalar threshold, at least this amount of m3 of volume should be present in a catchment area_multiplier=1. -- in case the maps are not in m2, set a multiplier other than 1. to convert iterations=15 -- number of iterations to use Output: inundation -- pcraster object float32, scalar inundation estimate """ #initial values pcr.setglobaloption("unitcell") dem_min = pcr.areaminimum(hand, subcatch) # minimum elevation in subcatchments dem_norm = hand - dem_min # surface of each subcatchment surface = pcr.areaarea(subcatch) * pcr.areaaverage( cell_surface, subcatch) # area_multiplier error_abs = pcr.scalar(1e10) # initial error (very high) volume_catch = pcr.areatotal(volume, subcatch) depth_catch = volume_catch / surface # meters water disc averaged over subcatchment # ilt(depth_catch, 'depth_catch_{:02d}.map'.format(order)) # pcr.report(volume, 'volume_{:02d}.map'.format(order)) dem_max = pcr.ifthenelse(volume_catch > volume_thres, pcr.scalar(32.), pcr.scalar(0)) # bizarre high inundation depth dem_min = pcr.scalar(0.) for n in range(iterations): logging.debug('Iteration: {:02d}'.format(n + 1)) #####while np.logical_and(error_abs > error_thres, dem_min < dem_max): dem_av = (dem_min + dem_max) / 2 # compute value at dem_av average_depth_catch = pcr.areaaverage(pcr.max(dem_av - dem_norm, 0), subcatch) error = pcr.cover((depth_catch - average_depth_catch) / depth_catch, depth_catch * 0) dem_min = pcr.ifthenelse(error > 0, dem_av, dem_min) dem_max = pcr.ifthenelse(error <= 0, dem_av, dem_max) inundation = pcr.max(dem_av - dem_norm, 0) pcr.setglobaloption('unittrue') return inundation
def dynamic(self): logger.info("Step 4: Monte Carlo simulation") # draw a random value (uniform for the entire map) z = pcr.mapnormal() #~ self.report(z,"z") # constraints, in order to make sure that random values are in the table of "lookup_table_average_thickness" z = pcr.max(-5.0, z) z = pcr.min(5.0, z) # assign average thickness (also uniform for the entire map) based on z self.Davg = pcr.lookupscalar(self.lookup_table_average_thickness, z) # self.report(self.Davg, "davg") self.lnDavg = pcr.ln(self.Davg) # sedimentary basin thickness (varying over cells and samples) lnD = self.F * (self.lnCV * self.lnDavg) + self.lnDavg # set the minimum depth (must be bigger than zero) minimum_depth = 0.005 lnD = pcr.max(pcr.ln(minimum_depth), lnD) # extrapolation lnD = pcr.cover(lnD, \ pcr.windowaverage(lnD, 1.50*vos.getMapAttributes(self.clone_map_file,"cellsize"))) lnD = pcr.cover(lnD, \ pcr.windowaverage(pcr.cover(lnD, pcr.ln(minimum_depth)), 3.00*vos.getMapAttributes(self.clone_map_file,"cellsize"))) lnD = pcr.cover(lnD, \ pcr.windowaverage(pcr.cover(lnD, pcr.ln(minimum_depth)), 0.50)) # smoothing per quarter arc degree lnD = pcr.windowaverage(lnD, 0.25) # thickness in meter self.D = pcr.exp(lnD) #~ # smoothing bottom elevation #~ dem_bottom = pcr.windowaverage(self.dem_average - self.D, 0.50) #~ # thickness in meter #~ self.D = pcr.max(0.0, self.dem_average - dem_bottom) #~ # smoothing #~ self.D = pcr.windowaverage(self.D, 1.50*vos.getMapAttributes(self.clone_map_file,"cellsize")) # accuracy until cm only self.D = pcr.rounddown(self.D * 100.) / 100. self.report(self.D, "damc")
def readTopo(self, iniItems, optionDict): # a dictionary/section of options that will be used if optionDict == None: optionDict = iniItems._sections["landSurfaceOptions"] # maps of elevation attributes: topoParams = ['tanslope','slopeLength','orographyBeta'] if optionDict['topographyNC'] == str(None): for var in topoParams: input = configget(iniItems,"landSurfaceOptions",str(var),"None") vars(self)[var] = vos.readPCRmapClone(input,self.cloneMap, self.tmpDir,self.inputDir) if var != "slopeLength": vars(self)[var] = pcr.cover(vars(self)[var], 0.0) else: topoPropertiesNC = vos.getFullPath(\ optionDict['topographyNC'], self.inputDir) for var in topoParams: vars(self)[var] = vos.netcdf2PCRobjCloneWithoutTime(\ topoPropertiesNC,var, \ cloneMapFileName = self.cloneMap) if var != "slopeLength": vars(self)[var] = pcr.cover(vars(self)[var], 0.0) #~ self.tanslope = pcr.max(self.tanslope, 0.00001) # In principle, tanslope can be zero. Zero tanslope will provide zero TCL (no interflow) # covering slopeLength with its maximum value self.slopeLength = pcr.cover(self.slopeLength, pcr.mapmaximum(self.slopeLength)) # maps of relative elevation above flood plains dzRel = ['dzRel0001','dzRel0005', 'dzRel0010','dzRel0020','dzRel0030','dzRel0040','dzRel0050', 'dzRel0060','dzRel0070','dzRel0080','dzRel0090','dzRel0100'] if optionDict['topographyNC'] == str(None): for i in range(0, len(dzRel)): var = dzRel[i] input = optionDict[str(var)] vars(self)[var] = vos.readPCRmapClone(input,self.cloneMap, self.tmpDir,self.inputDir) vars(self)[var] = pcr.cover(vars(self)[var], 0.0) if i > 0: vars(self)[var] = pcr.max(vars(self)[var], vars(self)[dzRel[i-1]]) else: for i in range(0, len(dzRel)): var = dzRel[i] vars(self)[var] = vos.netcdf2PCRobjCloneWithoutTime(\ topoPropertiesNC,var, \ cloneMapFileName = self.cloneMap) vars(self)[var] = pcr.cover(vars(self)[var], 0.0) if i > 0: vars(self)[var] = pcr.max(vars(self)[var], vars(self)[dzRel[i-1]])
def volume_spread(ldd, hand, subcatch, volume, volume_thres=0., area_multiplier=1., iterations=15): """ Estimate 2D flooding from a 1D simulation per subcatchment reach Input: ldd -- pcraster object direction, local drain directions hand -- pcraster object float32, elevation data normalised to nearest drain subcatch -- pcraster object ordinal, subcatchments with IDs volume -- pcraster object float32, scalar flood volume (i.e. m3 volume outside the river bank within subcatchment) volume_thres=0. -- scalar threshold, at least this amount of m3 of volume should be present in a catchment area_multiplier=1. -- in case the maps are not in m2, set a multiplier other than 1. to convert iterations=15 -- number of iterations to use Output: inundation -- pcraster object float32, scalar inundation estimate """ #initial values pcr.setglobaloption("unittrue") dem_min = pcr.areaminimum(hand, subcatch) # minimum elevation in subcatchments # pcr.report(dem_min, 'dem_min.map') dem_norm = hand - dem_min # pcr.report(dem_norm, 'dem_norm.map') # surface of each subcatchment surface = pcr.areaarea(subcatch)*area_multiplier pcr.report(surface, 'surface.map') error_abs = pcr.scalar(1e10) # initial error (very high) volume_catch = pcr.areatotal(volume, subcatch) # pcr.report(volume_catch, 'volume_catch.map') depth_catch = volume_catch/surface pcr.report(depth_catch, 'depth_catch.map') dem_max = pcr.ifthenelse(volume_catch > volume_thres, pcr.scalar(32.), pcr.scalar(0)) # bizarre high inundation depth dem_min = pcr.scalar(0.) for n in range(iterations): print('Iteration: {:02d}'.format(n + 1)) #####while np.logical_and(error_abs > error_thres, dem_min < dem_max): dem_av = (dem_min + dem_max)/2 # pcr.report(dem_av, 'dem_av00.{:03d}'.format(n + 1)) # compute value at dem_av average_depth_catch = pcr.areaaverage(pcr.max(dem_av - dem_norm, 0), subcatch) # pcr.report(average_depth_catch, 'depth_c0.{:03d}'.format(n + 1)) error = pcr.cover((depth_catch-average_depth_catch)/depth_catch, depth_catch*0) # pcr.report(error, 'error000.{:03d}'.format(n + 1)) dem_min = pcr.ifthenelse(error > 0, dem_av, dem_min) dem_max = pcr.ifthenelse(error <= 0, dem_av, dem_max) # error_abs = np.abs(error) # TODO: not needed probably, remove inundation = pcr.max(dem_av - dem_norm, 0) return inundation
def initial(self): ##################### # * initial section # ##################### #-constants # betaQ [-]: constant of kinematic wave momentum equation self.betaQ= 0.6 #-channel LDD self.channelLDD= pcr.ifthenelse(self.waterBodies.distribution != 0,\ pcr.ldd(5),self.LDD) #-channel area and storage self.channelArea= self.channelWidth*self.channelLength self.channelStorageCapacity= pcr.ifthenelse(self.waterBodies.distribution == 0,\ self.channelArea*self.channelDepth,pcr.scalar(0.)) #-basin outlets self.basinOutlet= pcr.pit(self.LDD) != 0 #-read initial conditions self.Q= clippedRead.get(self.QIniMap) self.actualStorage= clippedRead.get(self.actualStorageIniMap) self.actualStorage= pcr.ifthenelse(self.waterBodies.distribution != 0,\ pcr.ifthenelse(self.waterBodies.location != 0,\ pcr.areatotal(self.actualStorage,self.waterBodies.distribution),0),\ self.actualStorage) self.waterBodies.actualStorage= self.waterBodies.retrieveMapValue(self.actualStorage) #-update targets of average and bankful discharge self.waterBodies.averageQ= self.waterBodies.retrieveMapValue(self.averageQ) self.waterBodies.bankfulQ= self.waterBodies.retrieveMapValue(self.bankfulQ) #-return the parameters for the kinematic wave, # including alpha, wetted area, flood fraction, flood volume and depth # and the corresponding land area 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) #-update on velocity and check on Q - NOTE: does not work in case of reservoirs! self.flowVelocity= pcr.ifthenelse(self.wettedArea > 0,self.Q/self.wettedArea,0.) pcr.report(self.flowVelocity,pcrm.generateNameT(flowVelocityFileName,0).replace('.000','.ini')) #-setting initial values for specific runoff and surface water extraction self.landSurfaceQ= pcr.scalar(0.) self.potWaterSurfaceQ= pcr.scalar(0.) self.surfaceWaterExtraction= pcr.scalar(0.) #-budget check: setting initial values for cumulative discharge and # net cumulative input, including initial storage [m3] self.totalDischarge= pcr.scalar(0.) self.cumulativeDeltaStorage= pcr.catchmenttotal(self.actualStorage,self.LDD)
def getWaterBodyDimensions(self): # Lake properties max depth and total lake area lakeMaxDepth = ((3.0 * self.waterBodyStorage) / (self.waterBodyShapeFactor**2))**(1. / 3.) lakeArea = (lakeMaxDepth * self.waterBodyShapeFactor)**2 # reservoir properties max depth at outlet and total reservoir area reservoirMaxDepth = ((6.0 * self.waterBodyStorage) / (self.waterBodyShapeFactor**2))**(1. / 3.) reservoirArea = 0.5 * (reservoirMaxDepth * self.waterBodyShapeFactor)**2 # dynamic waterbody area, cannot exceed static waterbody extent as defined by input self.dynamicArea = pcr.cover(pcr.ifthenelse(pcr.scalar(self.waterBodyTyp) == 1, lakeArea,\ pcr.ifthen(pcr.scalar(self.waterBodyTyp) == 2, reservoirArea)), 0.) self.dynamicArea = pcr.min(self.dynamicArea, self.waterBodyArea) # dynamic water fraction in gridcell self.dynamicFracWat = self.dynamicArea * self.waterBodyRelativeFrac / self.cellArea #TODO check if this is correct self.dynamicFracWat = pcr.cover( pcr.min(pcr.max(self.dynamicFracWat, 0.), self.fracWat), 0.) self.dynamicFracWat = self.fracWat #TODO remove this line self.dynamicFracWat = ifthen(self.landmask, self.dynamicFracWat) self.maxWaterDepth = pcr.cover(pcr.ifthenelse(pcr.scalar(self.waterBodyTyp) == 1, lakeMaxDepth,\ pcr.ifthen(pcr.scalar(self.waterBodyTyp) == 2, reservoirMaxDepth)))
def downscaleTemperature(self, currTimeStep, useFactor=False, maxCorrelationCriteria=-0.75, zeroCelciusInKelvin=273.15): tmpSlope = 1.000 * vos.netcdf2PCRobjClone(\ self.temperLapseRateNC, 'temperature',\ currTimeStep.month, useDoy = "Yes",\ cloneMapFileName=self.cloneMap,\ LatitudeLongitude = True) tmpSlope = pcr.min(0., tmpSlope) # must be negative tmpCriteria = vos.netcdf2PCRobjClone(\ self.temperatCorrelNC, 'temperature',\ currTimeStep.month, useDoy = "Yes",\ cloneMapFileName=self.cloneMap,\ LatitudeLongitude = True) tmpSlope = pcr.ifthenelse(tmpCriteria < maxCorrelationCriteria,\ tmpSlope, 0.0) tmpSlope = pcr.cover(tmpSlope, 0.0) if useFactor == True: temperatureInKelvin = self.temperature + zeroCelciusInKelvin factor = pcr.max(0.0, temperatureInKelvin + tmpSlope * self.anomalyDEM) factor = factor / \ pcr.areaaverage(factor, self.meteoDownscaleIds) factor = pcr.cover(factor, 1.0) self.temperature = factor * temperatureInKelvin - zeroCelciusInKelvin else: self.temperature = self.temperature + tmpSlope * self.anomalyDEM
def getValDivZero(x,y,y_lim=smallNumber,z_def= 0.): #-returns the result of a division that possibly involves a zero # denominator; in which case, a default value is substituted: # x/y= z in case y > y_lim, # x/y= z_def in case y <= y_lim, where y_lim -> 0. # z_def is set to zero if not otherwise specified return pcr.ifthenelse(y > y_lim,x/pcr.max(y_lim,y),z_def)
def getICs(self, initial_condition): avgInflow = initial_condition['avgLakeReservoirInflowShort'] avgOutflow = initial_condition['avgLakeReservoirOutflowLong'] if initial_condition['waterBodyStorage'] is not None: # read directly waterBodyStorage = initial_condition['waterBodyStorage'] else: # calculate waterBodyStorage at cells where lakes and/or reservoirs are defined # storageAtLakeAndReservoirs = pcr.cover(\ pcr.ifthen(pcr.scalar(self.waterBodyIds) > 0., initial_condition['channelStorage']), 0.0) # # - move only non negative values and use rounddown values storageAtLakeAndReservoirs = pcr.max( 0.00, pcr.rounddown(storageAtLakeAndReservoirs)) # # lake and reservoir storages = waterBodyStorage (m3) ; values are given for the entire lake / reservoir cells waterBodyStorage = pcr.ifthen(pcr.scalar(self.waterBodyIds) > 0., \ pcr.areatotal(storageAtLakeAndReservoirs,\ self.waterBodyIds)) self.avgInflow = pcr.cover(avgInflow, 0.0) # unit: m3/s self.avgOutflow = pcr.cover(avgOutflow, 0.0) # unit: m3/s self.waterBodyStorage = pcr.cover(waterBodyStorage, 0.0) # unit: m3 self.avgInflow = pcr.ifthen(self.landmask, self.avgInflow) self.avgOutflow = pcr.ifthen(self.landmask, self.avgOutflow) self.waterBodyStorage = pcr.ifthen(self.landmask, self.waterBodyStorage)
def weirFormula(self, waterHeight, weirWidth): # output: m3/s sillElev = pcr.scalar(0.0) weirCoef = pcr.scalar(1.0) weirFormula = \ (1.7*weirCoef*pcr.max(0,waterHeight-sillElev)**1.5) *\ weirWidth # m3/s return (weirFormula)
def weirFormula(self, waterHeight, weirWidth): # output: m3/s sillElev = pcr.scalar(0.0) weirCoef = pcr.scalar(1.0) weirFormula = ( 1.7 * weirCoef * pcr.max(0, waterHeight - sillElev) ** 1.5 ) * weirWidth # m3/s return weirFormula
def volume_spread(ldd, hand, subcatch, volume, volume_thres=0., cell_surface=1., iterations=15, logging=logging, order=0, neg_HAND=None): """ Estimate 2D flooding from a 1D simulation per subcatchment reach Input: ldd -- pcraster object direction, local drain directions hand -- pcraster object float32, elevation data normalised to nearest drain subcatch -- pcraster object ordinal, subcatchments with IDs volume -- pcraster object float32, scalar flood volume (i.e. m3 volume outside the river bank within subcatchment) volume_thres=0. -- scalar threshold, at least this amount of m3 of volume should be present in a catchment area_multiplier=1. -- in case the maps are not in m2, set a multiplier other than 1. to convert iterations=15 -- number of iterations to use neg_HAND -- if set to 1, HAND maps can have negative values when elevation outside of stream is lower than stream (for example when there are natural embankments) Output: inundation -- pcraster object float32, scalar inundation estimate """ #initial values pcr.setglobaloption("unitcell") dem_min = pcr.areaminimum(hand, subcatch) # minimum elevation in subcatchments dem_norm = hand - dem_min # surface of each subcatchment surface = pcr.areaarea(subcatch)*pcr.areaaverage(cell_surface, subcatch) # area_multiplier error_abs = pcr.scalar(1e10) # initial error (very high) volume_catch = pcr.areatotal(volume, subcatch) depth_catch = volume_catch/surface # meters water disc averaged over subcatchment # ilt(depth_catch, 'depth_catch_{:02d}.map'.format(order)) # pcr.report(volume, 'volume_{:02d}.map'.format(order)) if neg_HAND == 1: dem_max = pcr.ifthenelse(volume_catch > volume_thres, pcr.scalar(32.), pcr.scalar(-32.)) # bizarre high inundation depth☻ dem_min = pcr.scalar(-32.) else: dem_max = pcr.ifthenelse(volume_catch > volume_thres, pcr.scalar(32.), pcr.scalar(0.)) # bizarre high inundation depth☻ dem_min = pcr.scalar(0.) for n in range(iterations): logging.debug('Iteration: {:02d}'.format(n + 1)) #####while np.logical_and(error_abs > error_thres, dem_min < dem_max): dem_av = (dem_min + dem_max)/2 # compute value at dem_av average_depth_catch = pcr.areaaverage(pcr.max(dem_av - dem_norm, 0), subcatch) error = pcr.cover((depth_catch-average_depth_catch)/depth_catch, depth_catch*0) dem_min = pcr.ifthenelse(error > 0, dem_av, dem_min) dem_max = pcr.ifthenelse(error <= 0, dem_av, dem_max) inundation = pcr.max(dem_av - dem_norm, 0) pcr.setglobaloption('unittrue') return inundation
def calculateThicknessOfSaturatedLayer(self): # thickness of saturated layer in m water depth (no pores) self.saturatedLayerThick = pcr.max( self.soilMoistureThick - self.fieldCapacityFraction * self.regolithThickness, pcr.scalar(0.0)) # thickness of saturated layer in m (including pores) self.saturatedLayerThickness = self.saturatedLayerThick / self.soilPorosityFraction
def derive_HAND(dem, ldd, accuThreshold, rivers=None, basin=None, up_area=None): """ Function derives Height-Above-Nearest-Drain. See http://www.sciencedirect.com/science/article/pii/S003442570800120X Input: dem -- pcraster object float32, elevation data ldd -- pcraster object direction, local drain directions accuThreshold -- upstream amount of cells as threshold for river delineation rivers=None -- you can provide a rivers layer here. Pixels that are identified as river should have a value > 0, other pixels a value of zero. basin=None -- set a boolean pcraster map where areas with True are estimated using the nearest drain in ldd distance and areas with False by means of the nearest friction distance. Friction distance estimated using the upstream area as weight (i.e. drains with a bigger upstream area have a lower friction) the spreadzone operator is used in this case. up_area=None -- provide the upstream area (if not assigned a guesstimate is prepared, assuming the LDD covers a full catchment area) Output: hand -- pcraster bject float32, height, normalised to nearest stream dist -- distance to nearest stream measured in cell lengths according to D8 directions """ if rivers is None: # prepare stream from a strahler threshold stream = pcr.ifthenelse( pcr.accuflux(ldd, 1) >= accuThreshold, pcr.boolean(1), pcr.boolean(0)) else: # convert stream network to boolean stream = pcr.boolean(pcr.cover(rivers, 0)) # determine height in river (in DEM*100 unit as ordinal) height_river = pcr.ifthenelse(stream, pcr.ordinal(dem * 100), 0) if basin is None: up_elevation = pcr.scalar(pcr.subcatchment(ldd, height_river)) else: # use basin to allocate areas outside basin to the nearest stream. Nearest is weighted by upstream area if up_area is None: up_area = pcr.accuflux(ldd, 1) up_area = pcr.ifthen(stream, up_area) # mask areas outside streams friction = 1. / pcr.scalar( pcr.spreadzone(pcr.cover(pcr.ordinal(up_area), 0), 0, 0)) # if basin, use nearest river within subcatchment, if outside basin, use weighted-nearest river up_elevation = pcr.ifthenelse( basin, pcr.scalar(pcr.subcatchment(ldd, height_river)), pcr.scalar(pcr.spreadzone(height_river, 0, friction))) # replace areas outside of basin by a spread zone calculation. hand = pcr.max(pcr.scalar(pcr.ordinal(dem * 100)) - up_elevation, 0) / 100 # convert back to float in DEM units # hand = (pcr.scalar(pcr.ordinal(dem*100))-up_elevation)/100 # convert back to float in DEM units dist = pcr.ldddist(ldd, stream, 1) # compute horizontal distance estimate return hand, dist
def rainfall_interception_gash(Cmax, EoverR, CanopyGapFraction, Precipitation, CanopyStorage, maxevap=9999): """ Interception according to the Gash model (For daily timesteps). """ # TODO: add other rainfall interception method (lui) # TODO: Include subdaily Gash model # TODO: add LAI variation in year # Hack for stemflow pt = 0.1 * CanopyGapFraction P_sat = pcr.max( pcr.scalar(0.0), pcr.cover( (-Cmax / EoverR) * pcr.ln(1.0 - (EoverR / (1.0 - CanopyGapFraction - pt))), pcr.scalar(0.0), ), ) # large storms P > P_sat largestorms = Precipitation > P_sat Iwet = pcr.ifthenelse( largestorms, ((1 - CanopyGapFraction - pt) * P_sat) - Cmax, Precipitation * (1 - CanopyGapFraction - pt), ) Isat = pcr.ifthenelse(largestorms, (EoverR) * (Precipitation - P_sat), 0.0) Idry = pcr.ifthenelse(largestorms, Cmax, 0.0) Itrunc = 0 StemFlow = pt * Precipitation ThroughFall = Precipitation - Iwet - Idry - Isat - Itrunc - StemFlow Interception = Iwet + Idry + Isat + Itrunc # Non corect for area without any Interception (say open water Cmax -- zero) CmaxZero = Cmax <= 0.0 ThroughFall = pcr.ifthenelse(CmaxZero, Precipitation, ThroughFall) Interception = pcr.ifthenelse(CmaxZero, pcr.scalar(0.0), Interception) StemFlow = pcr.ifthenelse(CmaxZero, pcr.scalar(0.0), StemFlow) # Now corect for maximum potential evap OverEstimate = pcr.ifthenelse(Interception > maxevap, Interception - maxevap, pcr.scalar(0.0)) Interception = pcr.min(Interception, maxevap) # Add surpluss to the thoughdfall ThroughFall = ThroughFall + OverEstimate return ThroughFall, Interception, StemFlow, CanopyStorage
def get_satDegUpp000005_from_observation(self): # assumption for observation values # - this should be replaced by values from the ECV soil moisture value (sattelite data) # - uncertainty should be included here # - note that the value should be between 0.0 and 1.0 observed_satDegUpp000005 = pcr.min(1.0,\ pcr.max(0.0,\ pcr.normal(pcr.boolean(1)) + 1.0)) return observed_satDegUpp000005
def rainfall_interception_modrut( Precipitation, PotEvap, CanopyStorage, CanopyGapFraction, Cmax ): """ Interception according to a modified Rutter model. The model is solved explicitly and there is no drainage below Cmax. Returns: - NetInterception: P - TF - SF (may be different from the actual wet canopy evaporation) - ThroughFall: - StemFlow: - LeftOver: Amount of potential eveporation not used - Interception: Actual wet canopy evaporation in this thimestep - CanopyStorage: Canopy storage at the end of the timestep """ ########################################################################## # Interception according to a modified Rutter model with hourly timesteps# ########################################################################## p = CanopyGapFraction pt = 0.1 * p # Amount of P that falls on the canopy Pfrac = pcr.max((1 - p - pt), 0) * Precipitation # S cannot be larger than Cmax, no gravity drainage below that DD = pcr.ifthenelse(CanopyStorage > Cmax, CanopyStorage - Cmax, 0.0) CanopyStorage = CanopyStorage - DD # Add the precipitation that falls on the canopy to the store CanopyStorage = CanopyStorage + Pfrac # Now do the Evap, make sure the store does not get negative dC = -1 * pcr.min(CanopyStorage, PotEvap) CanopyStorage = CanopyStorage + dC LeftOver = PotEvap + dC # Amount of evap not used # Now drain the canopy storage again if needed... D = pcr.ifthenelse(CanopyStorage > Cmax, CanopyStorage - Cmax, 0.0) CanopyStorage = CanopyStorage - D # Calculate throughfall ThroughFall = DD + D + p * Precipitation StemFlow = Precipitation * pt # Calculate interception, this is NET Interception NetInterception = Precipitation - ThroughFall - StemFlow Interception = -dC return NetInterception, ThroughFall, StemFlow, LeftOver, Interception, CanopyStorage
def kinAlphaDynamic(self,watStor): #-given the total water storage in the cell, returns the Q-A relationship # for the kinematic wave and required parameters floodVol= pcr.max(0,watStor-self.channelStorageCapacity) floodFrac, floodZ= self.returnFloodedFraction(floodVol) #-wetted perimeter, cross-sectional area and # corresponding mannings' n wetA= watStor/self.channelLength #-wetted perimeter, alpha and composite manning's n wetPFld= pcr.max(0.,floodFrac*self.cellArea/self.channelLength-\ self.channelWidth)+2.*floodZ wetPCh= self.channelWidth+\ 2.*pcr.min(self.channelDepth,watStor/self.channelArea) wetP= wetPFld+wetPCh manQ= (wetPCh/wetP*self.channelManN**1.5+\ wetPFld/wetP*self.floodplainManN**1.5)**(2./3.) alphaQ= (manQ*wetP**(2./3.)*self.channelGradient**-0.5)**self.betaQ #-returning variables of interest: flooded fraction, cross-sectional area # and alphaQ return floodFrac,floodZ,wetA,alphaQ
def rainfall_interception_gash( Cmax, EoverR, CanopyGapFraction, Precipitation, CanopyStorage, maxevap=9999 ): """ Interception according to the Gash model (For daily timesteps). """ # TODO: add other rainfall interception method (lui) # TODO: Include subdaily Gash model # TODO: add LAI variation in year # Hack for stemflow pt = 0.1 * CanopyGapFraction P_sat = pcr.max( pcr.scalar(0.0), pcr.cover( (-Cmax / EoverR) * pcr.ln(1.0 - (EoverR / (1.0 - CanopyGapFraction - pt))), pcr.scalar(0.0), ), ) # large storms P > P_sat largestorms = Precipitation > P_sat Iwet = pcr.ifthenelse( largestorms, ((1 - CanopyGapFraction - pt) * P_sat) - Cmax, Precipitation * (1 - CanopyGapFraction - pt), ) Isat = pcr.ifthenelse(largestorms, (EoverR) * (Precipitation - P_sat), 0.0) Idry = pcr.ifthenelse(largestorms, Cmax, 0.0) Itrunc = 0 StemFlow = pt * Precipitation ThroughFall = Precipitation - Iwet - Idry - Isat - Itrunc - StemFlow Interception = Iwet + Idry + Isat + Itrunc # Non corect for area without any Interception (say open water Cmax -- zero) CmaxZero = Cmax <= 0.0 ThroughFall = pcr.ifthenelse(CmaxZero, Precipitation, ThroughFall) Interception = pcr.ifthenelse(CmaxZero, pcr.scalar(0.0), Interception) StemFlow = pcr.ifthenelse(CmaxZero, pcr.scalar(0.0), StemFlow) # Now corect for maximum potential evap OverEstimate = pcr.ifthenelse( Interception > maxevap, Interception - maxevap, pcr.scalar(0.0) ) Interception = pcr.min(Interception, maxevap) # Add surpluss to the thoughdfall ThroughFall = ThroughFall + OverEstimate return ThroughFall, Interception, StemFlow, CanopyStorage
def moveFromChannelToWaterBody( self, newStorageAtLakeAndReservoirs, timestepsToAvgDischarge, maxTimestepsToAvgDischargeShort, length_of_time_step=vos.secondsPerDay(), ): # new lake and/or reservoir storages (m3) newStorageAtLakeAndReservoirs = pcr.cover( pcr.areatotal(newStorageAtLakeAndReservoirs, self.waterBodyIds), 0.0 ) # incoming volume (m3) self.inflow = newStorageAtLakeAndReservoirs - self.waterBodyStorage # inflowInM3PerSec (m3/s) inflowInM3PerSec = self.inflow / length_of_time_step # updating (short term) average inflow (m3/s) ; # - needed to constrain lake outflow: # temp = pcr.max( 1.0, pcr.min( maxTimestepsToAvgDischargeShort, self.timestepsToAvgDischarge - 1.0 + length_of_time_step / vos.secondsPerDay(), ), ) deltaInflow = inflowInM3PerSec - self.avgInflow R = deltaInflow * (length_of_time_step / vos.secondsPerDay()) / temp self.avgInflow = self.avgInflow + R self.avgInflow = pcr.max(0.0, self.avgInflow) # # for the reference, see the "weighted incremental algorithm" in http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance # updating waterBodyStorage (m3) self.waterBodyStorage = newStorageAtLakeAndReservoirs
def derive_HAND(dem, ldd, accuThreshold, rivers=None, basin=None, up_area=None, neg_HAND=None): """ Function derives Height-Above-Nearest-Drain. See http://www.sciencedirect.com/science/article/pii/S003442570800120X Input: dem -- pcraster object float32, elevation data ldd -- pcraster object direction, local drain directions accuThreshold -- upstream amount of cells as threshold for river delineation rivers=None -- you can provide a rivers layer here. Pixels that are identified as river should have a value > 0, other pixels a value of zero. basin=None -- set a boolean pcraster map where areas with True are estimated using the nearest drain in ldd distance and areas with False by means of the nearest friction distance. Friction distance estimated using the upstream area as weight (i.e. drains with a bigger upstream area have a lower friction) the spreadzone operator is used in this case. up_area=None -- provide the upstream area (if not assigned a guesstimate is prepared, assuming the LDD covers a full catchment area) neg_HAND=None -- if set to 1, HAND maps can have negative values when elevation outside of stream is lower than stream (for example when there are natural embankments) Output: hand -- pcraster bject float32, height, normalised to nearest stream dist -- distance to nearest stream measured in cell lengths according to D8 directions """ if rivers is None: # prepare stream from a strahler threshold stream = pcr.ifthenelse(pcr.accuflux(ldd, 1) >= accuThreshold, pcr.boolean(1), pcr.boolean(0)) else: # convert stream network to boolean stream = pcr.boolean(pcr.cover(rivers, 0)) # determine height in river (in DEM*100 unit as ordinal) height_river = pcr.ifthenelse(stream, pcr.ordinal(dem*100), 0) if basin is None: up_elevation = pcr.scalar(pcr.subcatchment(ldd, height_river)) else: # use basin to allocate areas outside basin to the nearest stream. Nearest is weighted by upstream area if up_area is None: up_area = pcr.accuflux(ldd, 1) up_area = pcr.ifthen(stream, up_area) # mask areas outside streams friction = 1./pcr.scalar(pcr.spreadzone(pcr.cover(pcr.ordinal(up_area), 0), 0, 0)) # if basin, use nearest river within subcatchment, if outside basin, use weighted-nearest river up_elevation = pcr.ifthenelse(basin, pcr.scalar(pcr.subcatchment(ldd, height_river)), pcr.scalar(pcr.spreadzone(height_river, 0, friction))) # replace areas outside of basin by a spread zone calculation. # make negative HANDS also possible if neg_HAND == 1: hand = (pcr.scalar(pcr.ordinal(dem*100))-up_elevation)/100 # convert back to float in DEM units else: hand = pcr.max(pcr.scalar(pcr.ordinal(dem*100))-up_elevation, 0)/100 # convert back to float in DEM units dist = pcr.ldddist(ldd, stream, 1) # compute horizontal distance estimate return hand, dist
def inverse_gumbel(p_zero, loc, scale, return_period): """ This function computes values for a given return period using the zero probability, location and shape parameters given. """ p = pcr.scalar(1. - 1./return_period) # p_residual is the probability density function of the population consisting of any values above zero p_residual = pcr.min(pcr.max((p - p_zero) / (1.0 - p_zero), 0.0), 1.0) #~ # - alternative equation found on: https://repos.deltares.nl/repos/Hydrology/trunk/GLOFRIS/src/rp_bias_corr.py (see the method inv_gumbel) #~ p_residual = np.minimum(np.maximum((p-p_zero)/(1-p_zero), 0), np.float64(1-1./1e9)) # I think this is the correct equation""" reduced_variate = -pcr.ln(-pcr.ln(p_residual)) flvol = reduced_variate * scale + loc # infinite numbers can occur. reduce these to zero! # if any values become negative due to the statistical extrapolation, fix them to zero (may occur if the sample size for fitting was small and a small return period is requested) flvol = pcr.max(0.0, pcr.cover(flvol, 0.0)) return flvol
def upscale_riverlength(ldd, order, factor): """ Upscales the riverlength using 'factor' The resulting maps can be resampled (e.g. using resample.exe) by factor and should include the accurate length as determined with the original higher resolution maps. This function is **depricated**, use are_riverlength instead as this version is very slow for large maps Input: - ldd - minimum streamorder to include Output: - distance per factor cells """ strorder = pcr.streamorder(ldd) strorder = pcr.ifthen(strorder >= order, strorder) dist = pcr.cover( pcr.max( pcr.celllength(), pcr.ifthen(pcr.boolean(strorder), pcr.downstreamdist(ldd)) ), 0, ) totdist = pcr.max( pcr.ifthen( pcr.boolean(strorder), pcr.windowtotal( pcr.ifthen(pcr.boolean(strorder), dist), pcr.celllength() * factor ), ), dist, ) return totdist
def derive_HAND(dem, ldd, accuThreshold, rivers=None, basin=None): """ Function derives Height-Above-Nearest-Drain. See http://www.sciencedirect.com/science/article/pii/S003442570800120X Input: dem -- pcraster object float32, elevation data ldd -- pcraster object direction, local drain directions accuThreshold -- upstream amount of cells as threshold for river delineation rivers=None -- you can provide a rivers layer here. Pixels that are identified as river should have a value > 0, other pixels a value of zero. basin=None -- set a boolean pcraster map where areas with True are estimated using the nearest drain in ldd distance and areas with False by means of the nearest friction distance. Friction distance estimated using the upstream area as weight (i.e. drains with a bigger upstream area have a lower friction) the spreadzone operator is used in this case. Output: hand -- pcraster bject float32, height, normalised to nearest stream dist -- distance to nearest stream measured in cell lengths according to D8 directions """ if rivers is None: stream = pcr.ifthenelse( pcr.accuflux(ldd, 1) >= accuThreshold, pcr.boolean(1), pcr.boolean(0) ) else: stream = pcr.boolean(pcr.cover(rivers, 0)) height_river = pcr.ifthenelse(stream, pcr.ordinal(dem * 100), 0) if basin is None: up_elevation = pcr.scalar(pcr.subcatchment(ldd, height_river)) else: drainage_surf = pcr.ifthen(rivers, pcr.accuflux(ldd, 1)) weight = 1.0 / pcr.scalar( pcr.spreadzone(pcr.cover(pcr.ordinal(drainage_surf), 0), 0, 0) ) up_elevation = pcr.ifthenelse( basin, pcr.scalar(pcr.subcatchment(ldd, height_river)), pcr.scalar(pcr.spreadzone(height_river, 0, weight)), ) # replace areas outside of basin by a spread zone calculation. hand = pcr.max(pcr.scalar(pcr.ordinal(dem * 100)) - up_elevation, 0) / 100 dist = pcr.ldddist(ldd, stream, 1) return hand, dist
def agriZone_Jarvis(self, k): """ - Potential evaporation is decreased by energy used for interception evaporation - Formula for evaporation based on Jarvis stress functions - Outgoing fluxes are determined based on (value in previous timestep + inflow) and if this leads to negative storage, the outgoing fluxes are corrected to rato --> Eu is no longer taken into account for this correction - Qa u is determined from overflow from Sa - Code for ini-file: 1 """ self.Qa = pcr.max(self.Pe - (self.samax[k] - self.Sa_t[k]), 0) self.Sa[k] = self.Sa_t[k] + (self.Pe - self.Qa) self.SaN = pcr.min(self.Sa[k] / self.samax2, 1) self.SuN = self.Su[k] / self.sumax[k] JarvisCoefficients.calcEu( self, k, 1 ) # calculation of Ea based on Jarvis stress functions self.Ea1 = self.Eu self.Fa1 = self.Fmin[k] + (self.Fmax[k] - self.Fmin[k]) * e ** ( -self.decF[k] * self.SuN ) self.Sa[k] = self.Sa_t[k] + (self.Pe - self.Qa) - self.Fa1 - self.Ea1 self.Sa_diff = pcr.ifthenelse(self.Sa[k] < 0, self.Sa[k], 0) self.Fa = ( self.Fa1 + (self.Fa1 / pcr.ifthenelse(self.Fa1 + self.Ea1 > 0, self.Fa1 + self.Ea1, 1)) * self.Sa_diff ) self.Ea = ( self.Ea1 + (self.Ea1 / pcr.ifthenelse(self.Fa1 + self.Ea1 > 0, self.Fa1 + self.Ea1, 1)) * self.Sa_diff ) self.Sa[k] = self.Sa_t[k] + (self.Pe - self.Qa) - self.Ea - self.Fa self.Sa[k] = pcr.ifthenelse(self.Sa[k] < 0, 0, self.Sa[k]) self.Sa_diff2 = pcr.ifthen(self.Sa[k] < 0, self.Sa[k]) self.wbSa_[k] = self.Pe - self.Ea - self.Qa - self.Fa - self.Sa[k] + self.Sa_t[k] self.Ea_[k] = self.Ea self.Qa_[k] = self.Qa self.Fa_[k] = self.Fa
def riverlength(ldd, order): """ Determines the length of a river using the ldd. only determined for order and higher. Input: - ldd, order (streamorder) Returns: - totallength,lengthpercell, streamorder """ strorder = pcr.streamorder(ldd) strorder = pcr.ifthen(strorder >= pcr.ordinal(order), strorder) dist = pcr.max( pcr.celllength(), pcr.ifthen(pcr.boolean(strorder), pcr.downstreamdist(ldd)) ) return pcr.catchmenttotal(pcr.cover(dist, 0), ldd), dist, strorder
def agriZone_no_reservoir(self, k): """ This function is used when no unsaturated zone reservoir is used and only passes fluxes from the upper reservoirs to the lower self.Qa_[k] = 0. self.Ea_[k] = 0. self.Sa[k] = 0. self.Fa_[k] = Pe Storage in unsaturated zone = 0. """ self.Qa_[k] = 0.0 self.Ea_[k] = 0.0 self.Sa[k] = 0.0 self.Fa_[k] = pcr.max(self.Pe_[k], 0) self.wbSa_[k] = ( self.Pe_[k] - self.Ea_[k] - self.Qa_[k] - self.Fa_[k] - self.Sa[k] + self.Sa_t[k] )
def getICs(self, initial_condition): avgInflow = initial_condition["avgLakeReservoirInflowShort"] avgOutflow = initial_condition["avgLakeReservoirOutflowLong"] # if not isinstance(initial_condition["waterBodyStorage"], type(None)): # read directly waterBodyStorage = initial_condition["waterBodyStorage"] else: # calculate waterBodyStorage at cells where lakes and/or reservoirs are defined # storageAtLakeAndReservoirs = pcr.cover( pcr.ifthen( pcr.scalar(self.waterBodyIds) > 0.0, initial_condition["channelStorage"], ), 0.0, ) # # - move only non negative values and use rounddown values storageAtLakeAndReservoirs = pcr.max( 0.00, pcr.rounddown(storageAtLakeAndReservoirs) ) # # lake and reservoir storages = waterBodyStorage (m3) ; values are given for the entire lake / reservoir cells waterBodyStorage = pcr.ifthen( pcr.scalar(self.waterBodyIds) > 0.0, pcr.areatotal(storageAtLakeAndReservoirs, self.waterBodyIds), ) self.avgInflow = pcr.cover(avgInflow, 0.0) # unit: m3/s self.avgOutflow = pcr.cover(avgOutflow, 0.0) # unit: m3/s self.waterBodyStorage = pcr.cover(waterBodyStorage, 0.0) # unit: m3 self.avgInflow = pcr.ifthen(self.landmask, self.avgInflow) self.avgOutflow = pcr.ifthen(self.landmask, self.avgOutflow) self.waterBodyStorage = pcr.ifthen(self.landmask, self.waterBodyStorage)
def agriZone_Ep_Sa_beta_frostSamax_surfTemp(self, k): """ - Potential evaporation is decreased by energy used for interception evaporation - Formula for evaporation based on LP - Outgoing fluxes are determined based on (value in previous timestep + inflow) and if this leads to negative storage, the outgoing fluxes are corrected to rato --> Eu is no longer taken into account for this correction - Qa u is determined from overflow from Sa --> incorporation of beta function - Fa is based on storage in Sa - Fa is decreased in case of frozen soil - Code for ini-file: 13 """ JarvisCoefficients.calcEp(self, k) self.PotEvaporation = self.EpHour self.FrDur[k] = pcr.min( self.FrDur[k] + pcr.ifthenelse( self.TempSurf > 0, self.ratFT[k] * self.TempSurf, self.TempSurf ) * self.dayDeg[k], 0, ) self.Ft = pcr.min( pcr.max( self.FrDur[k] / (self.FrDur1[k] - self.FrDur0[k]) - self.FrDur0[k] / (self.FrDur1[k] - self.FrDur0[k]), self.samin[k], ), 1, ) self.samax2 = self.samax[k] * pcr.scalar(self.catchArea) * self.Ft self.Qaadd = pcr.max(self.Sa_t[k] + self.Pe - self.samax2, 0) self.Sa[k] = self.Sa_t[k] + (self.Pe - self.Qaadd) self.SaN = pcr.min(self.Sa[k] / self.samax2, 1) self.SuN = self.Su[k] / self.sumax[k] self.Ea1 = pcr.max((self.PotEvaporation - self.Ei), 0) * pcr.min( self.Sa[k] / (self.samax2 * self.LP[k]), 1 ) self.Qa1 = (self.Pe - self.Qaadd) * (1 - (1 - self.SaN) ** self.beta[k]) self.Fa1 = pcr.ifthenelse( self.SaN > 0, self.Fmin[k] + (self.Fmax[k] - self.Fmin[k]) * e ** (-self.decF[k] * (1 - self.SaN)), 0, ) self.Sa[k] = self.Sa_t[k] + (self.Pe - self.Qaadd) - self.Qa1 - self.Fa1 - self.Ea1 self.Sa_diff = pcr.ifthenelse(self.Sa[k] < 0, self.Sa[k], 0) self.Qa = ( self.Qa1 + ( self.Qa1 / pcr.ifthenelse( self.Fa1 + self.Ea1 + self.Qa1 > 0, self.Fa1 + self.Ea1 + self.Qa1, 1 ) ) * self.Sa_diff ) self.Fa = ( self.Fa1 + ( self.Fa1 / pcr.ifthenelse( self.Fa1 + self.Ea1 + self.Qa1 > 0, self.Fa1 + self.Ea1 + self.Qa1, 1 ) ) * self.Sa_diff ) self.Ea = ( self.Ea1 + ( self.Ea1 / pcr.ifthenelse( self.Fa1 + self.Ea1 + self.Qa1 > 0, self.Fa1 + self.Ea1 + self.Qa1, 1 ) ) * self.Sa_diff ) self.Sa[k] = self.Sa_t[k] + (self.Pe - self.Qaadd) - self.Ea - self.Fa - self.Qa self.Sa[k] = pcr.ifthenelse(self.Sa[k] < 0, 0, self.Sa[k]) self.Sa_diff2 = pcr.ifthen(self.Sa[k] < 0, self.Sa[k]) self.wbSa_[k] = ( self.Pe - self.Ea - self.Qa - self.Qaadd - self.Fa - self.Sa[k] + self.Sa_t[k] ) self.Ea_[k] = self.Ea self.Qa_[k] = self.Qa + self.Qaadd self.Fa_[k] = self.Fa self.Ft_[k] = self.Ft
def readTopo(self, iniItems, optionDict): # a dictionary/section of options that will be used if optionDict == None: optionDict = iniItems._sections["landSurfaceOptions"] # maps of elevation attributes: topoParams = ["tanslope", "slopeLength", "orographyBeta"] if optionDict["topographyNC"] == str(None): for var in topoParams: input = configget(iniItems, "landSurfaceOptions", str(var), "None") vars(self)[var] = vos.readPCRmapClone( input, self.cloneMap, self.tmpDir, self.inputDir ) if var != "slopeLength": vars(self)[var] = pcr.cover(vars(self)[var], 0.0) else: topoPropertiesNC = vos.getFullPath( optionDict["topographyNC"], self.inputDir ) for var in topoParams: vars(self)[var] = vos.netcdf2PCRobjCloneWithoutTime( topoPropertiesNC, var, cloneMapFileName=self.cloneMap ) if var != "slopeLength": vars(self)[var] = pcr.cover(vars(self)[var], 0.0) # ~ self.tanslope = pcr.max(self.tanslope, 0.00001) # In principle, tanslope can be zero. Zero tanslope will provide zero TCL (no interflow) # covering slopeLength with its maximum value self.slopeLength = pcr.cover(self.slopeLength, pcr.mapmaximum(self.slopeLength)) # maps of relative elevation above flood plains dzRel = [ "dzRel0001", "dzRel0005", "dzRel0010", "dzRel0020", "dzRel0030", "dzRel0040", "dzRel0050", "dzRel0060", "dzRel0070", "dzRel0080", "dzRel0090", "dzRel0100", ] if optionDict["topographyNC"] == str(None): for i in range(0, len(dzRel)): var = dzRel[i] input = optionDict[str(var)] vars(self)[var] = vos.readPCRmapClone( input, self.cloneMap, self.tmpDir, self.inputDir ) vars(self)[var] = pcr.cover(vars(self)[var], 0.0) if i > 0: vars(self)[var] = pcr.max(vars(self)[var], vars(self)[dzRel[i - 1]]) else: for i in range(0, len(dzRel)): var = dzRel[i] vars(self)[var] = vos.netcdf2PCRobjCloneWithoutTime( topoPropertiesNC, var, cloneMapFileName=self.cloneMap ) vars(self)[var] = pcr.cover(vars(self)[var], 0.0) if i > 0: vars(self)[var] = pcr.max(vars(self)[var], vars(self)[dzRel[i - 1]])
pcr.windowaverage(fraction_reserved_recharge, 0.5)) fraction_reserved_recharge = pcr.cover(fraction_reserved_recharge, \ pcr.windowaverage(fraction_reserved_recharge, 0.5)) fraction_reserved_recharge = pcr.cover(fraction_reserved_recharge, \ pcr.windowaverage(fraction_reserved_recharge, 0.5)) fraction_reserved_recharge = pcr.cover(fraction_reserved_recharge, \ pcr.windowaverage(fraction_reserved_recharge, 0.5)) fraction_reserved_recharge = pcr.cover(fraction_reserved_recharge, \ pcr.windowaverage(fraction_reserved_recharge, 0.5)) fraction_reserved_recharge = pcr.cover(fraction_reserved_recharge, \ pcr.windowaverage(fraction_reserved_recharge, 0.5)) fraction_reserved_recharge = pcr.cover(fraction_reserved_recharge, \ pcr.windowaverage(fraction_reserved_recharge, 0.5)) fraction_reserved_recharge = pcr.cover(fraction_reserved_recharge, 0.1) # - set minimum value to 0.10 fraction_reserved_recharge = pcr.max(0.10, fraction_reserved_recharge) # - set maximum value to 0.75 fraction_reserved_recharge = pcr.min(0.75, fraction_reserved_recharge) # areal_groundwater_abstraction (unit: m/year) #~ groundwater_abstraction = pcr.cover(pcr.readmap("/nfsarchive/edwin-emergency-backup-DO-NOT-DELETE/rapid/edwin/05min_runs_results/2015_04_27/non_natural_2015_04_27/global/analysis/avg_values_1990_to_2010/totalGroundwaterAbstraction_annuaTot_output_1990to2010.map"), 0.0) groundwater_abstraction = pcr.scalar(0.0) for year in range(start_year, end_year + 1, 1): date_input_in_string = str(year) + "-12-31" netcdf_file = "/nfsarchive/edwin-emergency-backup-DO-NOT-DELETE/rapid/edwin/05min_runs_results/2015_04_27/non_natural_2015_04_27/global/netcdf/totalGroundwaterAbstraction_annuaTot_output_1981to2010.nc" variable_name = "total_groundwater_abstraction" groundwater_abstraction += vos.netcdf2PCRobjClone(ncFile = netcdf_file, varName = variable_name, dateInput = date_input_in_string,\ useDoy = None, cloneMapFileName = None,\ LatitudeLongitude = True,\ specificFillValue = None)
def main(): ### Read input arguments ##### parser = OptionParser() usage = "usage: %prog [options]" parser = OptionParser(usage=usage) parser.add_option('-q', '--quiet', dest='verbose', default=True, action='store_false', help='do not print status messages to stdout') parser.add_option('-i', '--ini', dest='inifile', default='hand_contour_inun.ini', nargs=1, help='ini configuration file') parser.add_option('-f', '--flood_map', nargs=1, dest='flood_map', help='Flood map file (NetCDF point time series file') parser.add_option('-v', '--flood_variable', nargs=1, dest='flood_variable', default='water_level', help='variable name of flood water level') parser.add_option('-b', '--bankfull_map', dest='bankfull_map', default='', help='Map containing bank full level (is subtracted from flood map, in NetCDF)') parser.add_option('-c', '--catchment', dest='catchment_strahler', default=7, type='int', help='Strahler order threshold >= are selected as catchment boundaries') parser.add_option('-t', '--time', dest='time', default='', help='time in YYYYMMDDHHMMSS, overrides time in NetCDF input if set') # parser.add_option('-s', '--hand_strahler', # dest='hand_strahler', default=7, type='int', # help='Strahler order threshold >= selected as riverine') parser.add_option('-m', '--max_strahler', dest = 'max_strahler', default=1000, type='int', help='Maximum Strahler order to loop over') parser.add_option('-d', '--destination', dest='dest_path', default='inun', help='Destination path') parser.add_option('-H', '--hand_file_prefix', dest='hand_file_prefix', default='', help='optional HAND file prefix of already generated HAND files') parser.add_option('-n', '--neg_HAND', dest='neg_HAND', default=0, type='int', help='if set to 1, allow for negative HAND values in HAND maps') (options, args) = parser.parse_args() if not os.path.exists(options.inifile): print 'path to ini file cannot be found' sys.exit(1) options.dest_path = os.path.abspath(options.dest_path) if not(os.path.isdir(options.dest_path)): os.makedirs(options.dest_path) # set up the logger flood_name = os.path.split(options.flood_map)[1].split('.')[0] # case_name = 'inun_{:s}_hand_{:02d}_catch_{:02d}'.format(flood_name, options.hand_strahler, options.catchment_strahler) case_name = 'inun_{:s}_catch_{:02d}'.format(flood_name, options.catchment_strahler) logfilename = os.path.join(options.dest_path, 'hand_contour_inun.log') logger, ch = inun_lib.setlogger(logfilename, 'HAND_INUN', options.verbose) logger.info('$Id: $') logger.info('Flood map: {:s}'.format(options.flood_map)) logger.info('Bank full map: {:s}'.format(options.bankfull_map)) logger.info('Destination path: {:s}'.format(options.dest_path)) # read out ini file ### READ CONFIG FILE # open config-file config = inun_lib.open_conf(options.inifile) # read settings options.dem_file = inun_lib.configget(config, 'HighResMaps', 'dem_file', True) options.ldd_file = inun_lib.configget(config, 'HighResMaps', 'ldd_file', True) options.stream_file = inun_lib.configget(config, 'HighResMaps', 'stream_file', True) options.riv_length_fact_file = inun_lib.configget(config, 'wflowResMaps', 'riv_length_fact_file', True) options.ldd_wflow = inun_lib.configget(config, 'wflowResMaps', 'ldd_wflow', True) options.riv_width_file = inun_lib.configget(config, 'wflowResMaps', 'riv_width_file', True) options.file_format = inun_lib.configget(config, 'file_settings', 'file_format', 0, datatype='int') options.out_format = inun_lib.configget(config, 'file_settings', 'out_format', 0, datatype='int') options.latlon = inun_lib.configget(config, 'file_settings', 'latlon', 0, datatype='int') options.x_tile = inun_lib.configget(config, 'tiling', 'x_tile', 10000, datatype='int') options.y_tile = inun_lib.configget(config, 'tiling', 'y_tile', 10000, datatype='int') options.x_overlap = inun_lib.configget(config, 'tiling', 'x_overlap', 1000, datatype='int') options.y_overlap = inun_lib.configget(config, 'tiling', 'y_overlap', 1000, datatype='int') options.iterations = inun_lib.configget(config, 'inundation', 'iterations', 20, datatype='int') options.initial_level = inun_lib.configget(config, 'inundation', 'initial_level', 32., datatype='float') options.flood_volume_type = inun_lib.configget(config, 'inundation', 'flood_volume_type', 0, datatype='int') # options.area_multiplier = inun_lib.configget(config, 'inundation', # 'area_multiplier', 1., datatype='float') logger.info('DEM file: {:s}'.format(options.dem_file)) logger.info('LDD file: {:s}'.format(options.ldd_file)) logger.info('Columns per tile: {:d}'.format(options.x_tile)) logger.info('Rows per tile: {:d}'.format(options.y_tile)) logger.info('Columns overlap: {:d}'.format(options.x_overlap)) logger.info('Rows overlap: {:d}'.format(options.y_overlap)) metadata_global = {} # add metadata from the section [metadata] meta_keys = config.options('metadata_global') for key in meta_keys: metadata_global[key] = config.get('metadata_global', key) # add a number of metadata variables that are mandatory metadata_global['config_file'] = os.path.abspath(options.inifile) metadata_var = {} metadata_var['units'] = 'm' metadata_var['standard_name'] = 'water_surface_height_above_reference_datum' metadata_var['long_name'] = 'flooding' metadata_var['comment'] = 'water_surface_reference_datum_altitude is given in file {:s}'.format(options.dem_file) if not os.path.exists(options.dem_file): logger.error('path to dem file {:s} cannot be found'.format(options.dem_file)) sys.exit(1) if not os.path.exists(options.ldd_file): logger.error('path to ldd file {:s} cannot be found'.format(options.ldd_file)) sys.exit(1) # Read extent from a GDAL compatible file try: extent = inun_lib.get_gdal_extent(options.dem_file) except: msg = 'Input file {:s} not a gdal compatible file'.format(options.dem_file) inun_lib.close_with_error(logger, ch, msg) sys.exit(1) try: x, y = inun_lib.get_gdal_axes(options.dem_file, logging=logger) srs = inun_lib.get_gdal_projection(options.dem_file, logging=logger) except: msg = 'Input file {:s} not a gdal compatible file'.format(options.dem_file) inun_lib.close_with_error(logger, ch, msg) sys.exit(1) # read history from flood file if options.file_format == 0: a = nc.Dataset(options.flood_map, 'r') metadata_global['history'] = 'Created by: $Id: $, boundary conditions from {:s},\nhistory: {:s}'.format(os.path.abspath(options.flood_map), a.history) a.close() else: metadata_global['history'] = 'Created by: $Id: $, boundary conditions from {:s},\nhistory: {:s}'.format(os.path.abspath(options.flood_map), 'PCRaster file, no history') # first write subcatch maps and hand maps ############### TODO ###### # setup a HAND file for each strahler order max_s = inun_lib.define_max_strahler(options.stream_file, logging=logger) stream_max = np.minimum(max_s, options.max_strahler) for hand_strahler in range(options.catchment_strahler, stream_max + 1, 1): dem_name = os.path.split(options.dem_file)[1].split('.')[0] if os.path.isfile('{:s}_{:02d}.tif'.format(options.hand_file_prefix, hand_strahler)): hand_file = '{:s}_{:02d}.tif'.format(options.hand_file_prefix, hand_strahler) else: logger.info('No HAND files with HAND prefix were found, checking {:s}_hand_strahler_{:02d}.tif'.format(dem_name, hand_strahler)) hand_file = os.path.join(options.dest_path, '{:s}_hand_strahler_{:02d}.tif'.format(dem_name, hand_strahler)) if not(os.path.isfile(hand_file)): # hand file does not exist yet! Generate it, otherwise skip! logger.info('HAND file {:s} not found, start setting up...please wait...'.format(hand_file)) hand_file_tmp = os.path.join(options.dest_path, '{:s}_hand_strahler_{:02d}.tif.tmp'.format(dem_name, hand_strahler)) ds_hand, band_hand = inun_lib.prepare_gdal(hand_file_tmp, x, y, logging=logger, srs=srs) # band_hand = ds_hand.GetRasterBand(1) # Open terrain data for reading ds_dem, rasterband_dem = inun_lib.get_gdal_rasterband(options.dem_file) ds_ldd, rasterband_ldd = inun_lib.get_gdal_rasterband(options.ldd_file) ds_stream, rasterband_stream = inun_lib.get_gdal_rasterband(options.stream_file) n = 0 for x_loop in range(0, len(x), options.x_tile): x_start = np.maximum(x_loop, 0) x_end = np.minimum(x_loop + options.x_tile, len(x)) # determine actual overlap for cutting for y_loop in range(0, len(y), options.y_tile): x_overlap_min = x_start - np.maximum(x_start - options.x_overlap, 0) x_overlap_max = np.minimum(x_end + options.x_overlap, len(x)) - x_end n += 1 # print('tile {:001d}:'.format(n)) y_start = np.maximum(y_loop, 0) y_end = np.minimum(y_loop + options.y_tile, len(y)) y_overlap_min = y_start - np.maximum(y_start - options.y_overlap, 0) y_overlap_max = np.minimum(y_end + options.y_overlap, len(y)) - y_end # cut out DEM logger.debug('Computing HAND for xmin: {:d} xmax: {:d} ymin {:d} ymax {:d}'.format(x_start, x_end,y_start, y_end)) terrain = rasterband_dem.ReadAsArray(x_start - x_overlap_min, y_start - y_overlap_min, (x_end + x_overlap_max) - (x_start - x_overlap_min), (y_end + y_overlap_max) - (y_start - y_overlap_min) ) drainage = rasterband_ldd.ReadAsArray(x_start - x_overlap_min, y_start - y_overlap_min, (x_end + x_overlap_max) - (x_start - x_overlap_min), (y_end + y_overlap_max) - (y_start - y_overlap_min) ) stream = rasterband_stream.ReadAsArray(x_start - x_overlap_min, y_start - y_overlap_min, (x_end + x_overlap_max) - (x_start - x_overlap_min), (y_end + y_overlap_max) - (y_start - y_overlap_min) ) # write to temporary file terrain_temp_file = os.path.join(options.dest_path, 'terrain_temp.map') drainage_temp_file = os.path.join(options.dest_path, 'drainage_temp.map') stream_temp_file = os.path.join(options.dest_path, 'stream_temp.map') if rasterband_dem.GetNoDataValue() is not None: inun_lib.gdal_writemap(terrain_temp_file, 'PCRaster', np.arange(0, terrain.shape[1]), np.arange(0, terrain.shape[0]), terrain, rasterband_dem.GetNoDataValue(), gdal_type=gdal.GDT_Float32, logging=logger) else: # in case no nodata value is found logger.warning('No nodata value found in {:s}. assuming -9999'.format(options.dem_file)) inun_lib.gdal_writemap(terrain_temp_file, 'PCRaster', np.arange(0, terrain.shape[1]), np.arange(0, terrain.shape[0]), terrain, -9999., gdal_type=gdal.GDT_Float32, logging=logger) inun_lib.gdal_writemap(drainage_temp_file, 'PCRaster', np.arange(0, terrain.shape[1]), np.arange(0, terrain.shape[0]), drainage, rasterband_ldd.GetNoDataValue(), gdal_type=gdal.GDT_Int32, logging=logger) inun_lib.gdal_writemap(stream_temp_file, 'PCRaster', np.arange(0, terrain.shape[1]), np.arange(0, terrain.shape[0]), stream, rasterband_ldd.GetNoDataValue(), gdal_type=gdal.GDT_Int32, logging=logger) # read as pcr objects pcr.setclone(terrain_temp_file) terrain_pcr = pcr.readmap(terrain_temp_file) drainage_pcr = pcr.lddrepair(pcr.ldd(pcr.readmap(drainage_temp_file))) # convert to ldd type map stream_pcr = pcr.scalar(pcr.readmap(stream_temp_file)) # convert to ldd type map #check if the highest stream order of the tile is below the hand_strahler # if the highest stream order of the tile is smaller than hand_strahler, than DEM values are taken instead of HAND values. max_stream_tile = inun_lib.define_max_strahler(stream_temp_file, logging=logger) if max_stream_tile < hand_strahler: hand_pcr = terrain_pcr logger.info('For this tile, DEM values are used instead of HAND because there is no stream order larger than {:02d}'.format(hand_strahler)) else: # compute streams stream_ge, subcatch = inun_lib.subcatch_stream(drainage_pcr, hand_strahler, stream=stream_pcr) # generate streams # compute basins stream_ge_dummy, subcatch = inun_lib.subcatch_stream(drainage_pcr, options.catchment_strahler, stream=stream_pcr) # generate streams basin = pcr.boolean(subcatch) hand_pcr, dist_pcr = inun_lib.derive_HAND(terrain_pcr, drainage_pcr, 3000, rivers=pcr.boolean(stream_ge), basin=basin, neg_HAND=options.neg_HAND) # convert to numpy hand = pcr.pcr2numpy(hand_pcr, -9999.) # cut relevant part if y_overlap_max == 0: y_overlap_max = -hand.shape[0] if x_overlap_max == 0: x_overlap_max = -hand.shape[1] hand_cut = hand[0+y_overlap_min:-y_overlap_max, 0+x_overlap_min:-x_overlap_max] band_hand.WriteArray(hand_cut, x_start, y_start) os.unlink(terrain_temp_file) os.unlink(drainage_temp_file) os.unlink(stream_temp_file) band_hand.FlushCache() ds_dem = None ds_ldd = None ds_stream = None band_hand.SetNoDataValue(-9999.) ds_hand = None logger.info('Finalizing {:s}'.format(hand_file)) # rename temporary file to final hand file os.rename(hand_file_tmp, hand_file) else: logger.info('HAND file {:s} already exists...skipping...'.format(hand_file)) ##################################################################################### # HAND file has now been prepared, moving to flood mapping part # ##################################################################################### # set the clone pcr.setclone(options.ldd_wflow) # read wflow ldd as pcraster object ldd_pcr = pcr.readmap(options.ldd_wflow) xax, yax, riv_width, fill_value = inun_lib.gdal_readmap(options.riv_width_file, 'GTiff', logging=logger) # determine cell length in meters using ldd_pcr as clone (if latlon=True, values are converted to m2 x_res, y_res, reallength_wflow = pcrut.detRealCellLength(pcr.scalar(ldd_pcr), not(bool(options.latlon))) cell_surface_wflow = pcr.pcr2numpy(x_res * y_res, 0) if options.flood_volume_type == 0: # load the staticmaps needed to estimate volumes across all # xax, yax, riv_length, fill_value = inun_lib.gdal_readmap(options.riv_length_file, 'GTiff', logging=logger) # riv_length = np.ma.masked_where(riv_length==fill_value, riv_length) xax, yax, riv_width, fill_value = inun_lib.gdal_readmap(options.riv_width_file, 'GTiff', logging=logger) riv_width[riv_width == fill_value] = 0 # read river length factor file (multiplier) xax, yax, riv_length_fact, fill_value = inun_lib.gdal_readmap(options.riv_length_fact_file, 'GTiff', logging=logger) riv_length_fact = np.ma.masked_where(riv_length_fact==fill_value, riv_length_fact) drain_length = wflow_lib.detdrainlength(ldd_pcr, x_res, y_res) # compute river length in each cell riv_length = pcr.pcr2numpy(drain_length, 0) * riv_length_fact # riv_length_pcr = pcr.numpy2pcr(pcr.Scalar, riv_length, 0) flood_folder = os.path.join(options.dest_path, case_name) flood_vol_map = os.path.join(flood_folder, '{:s}_vol.tif'.format(os.path.split(options.flood_map)[1].split('.')[0])) if not(os.path.isdir(flood_folder)): os.makedirs(flood_folder) if options.out_format == 0: inun_file_tmp = os.path.join(flood_folder, '{:s}.tif.tmp'.format(case_name)) inun_file = os.path.join(flood_folder, '{:s}.tif'.format(case_name)) else: inun_file_tmp = os.path.join(flood_folder, '{:s}.nc.tmp'.format(case_name)) inun_file = os.path.join(flood_folder, '{:s}.nc'.format(case_name)) hand_temp_file = os.path.join(flood_folder, 'hand_temp.map') drainage_temp_file = os.path.join(flood_folder, 'drainage_temp.map') stream_temp_file = os.path.join(flood_folder, 'stream_temp.map') flood_vol_temp_file = os.path.join(flood_folder, 'flood_warp_temp.tif') # load the data with river levels and compute the volumes if options.file_format == 0: # assume we need the maximum value in a NetCDF time series grid logger.info('Reading flood from {:s} NetCDF file'.format(options.flood_map)) a = nc.Dataset(options.flood_map, 'r') if options.latlon == 0: xax = a.variables['x'][:] yax = a.variables['y'][:] else: xax = a.variables['lon'][:] yax = a.variables['lat'][:] if options.time == '': time_list = nc.num2date(a.variables['time'][:], units = a.variables['time'].units, calendar=a.variables['time'].calendar) time = [time_list[len(time_list)/2]] else: time = [dt.datetime.strptime(options.time, '%Y%m%d%H%M%S')] flood_series = a.variables[options.flood_variable][:] flood_data = flood_series.max(axis=0) if np.ma.is_masked(flood_data): flood = flood_data.data flood[flood_data.mask] = 0 if yax[-1] > yax[0]: yax = np.flipud(yax) flood = np.flipud(flood) a.close() elif options.file_format == 1: logger.info('Reading flood from {:s} PCRaster file'.format(options.flood_map)) xax, yax, flood, flood_fill_value = inun_lib.gdal_readmap(options.flood_map, 'PCRaster', logging=logger) flood = np.ma.masked_equal(flood, flood_fill_value) if options.time == '': options.time = '20000101000000' time = [dt.datetime.strptime(options.time, '%Y%m%d%H%M%S')] flood[flood==flood_fill_value] = 0. # load the bankfull depths if options.bankfull_map == '': bankfull = np.zeros(flood.shape) else: if options.file_format == 0: logger.info('Reading bankfull from {:s} NetCDF file'.format(options.bankfull_map)) a = nc.Dataset(options.bankfull_map, 'r') xax = a.variables['x'][:] yax = a.variables['y'][:] bankfull_series = a.variables[options.flood_variable][:] bankfull_data = bankfull_series.max(axis=0) if np.ma.is_masked(bankfull_data): bankfull = bankfull_data.data bankfull[bankfull_data.mask] = 0 if yax[-1] > yax[0]: yax = np.flipud(yax) bankfull = np.flipud(bankfull) a.close() elif options.file_format == 1: logger.info('Reading bankfull from {:s} PCRaster file'.format(options.bankfull_map)) xax, yax, bankfull, bankfull_fill_value = inun_lib.gdal_readmap(options.bankfull_map, 'PCRaster', logging=logger) bankfull = np.ma.masked_equal(bankfull, bankfull_fill_value) # flood = bankfull*2 # res_x = 2000 # res_y = 2000 # subtract the bankfull water level to get flood levels (above bankfull) flood_vol = np.maximum(flood-bankfull, 0) if options.flood_volume_type == 0: flood_vol_m = riv_length*riv_width*flood_vol/cell_surface_wflow # volume expressed in meters water disc flood_vol_m_pcr = pcr.numpy2pcr(pcr.Scalar, flood_vol_m, 0) else: flood_vol_m = flood_vol/cell_surface_wflow flood_vol_m_data = flood_vol_m.data flood_vol_m_data[flood_vol_m.mask] = -999. logger.info('Saving water layer map to {:s}'.format(flood_vol_map)) # write to a tiff file inun_lib.gdal_writemap(flood_vol_map, 'GTiff', xax, yax, np.maximum(flood_vol_m_data, 0), -999., logging=logger) # this is placed later in the hand loop # ds_hand, rasterband_hand = inun_lib.get_gdal_rasterband(hand_file) ds_ldd, rasterband_ldd = inun_lib.get_gdal_rasterband(options.ldd_file) ds_stream, rasterband_stream = inun_lib.get_gdal_rasterband(options.stream_file) logger.info('Preparing flood map in {:s} ...please wait...'.format(inun_file)) if options.out_format == 0: ds_inun, band_inun = inun_lib.prepare_gdal(inun_file_tmp, x, y, logging=logger, srs=srs) # band_inun = ds_inun.GetRasterBand(1) else: ds_inun, band_inun = inun_lib.prepare_nc(inun_file_tmp, time, x, np.flipud(y), metadata=metadata_global, metadata_var=metadata_var, logging=logger) # loop over all the tiles n = 0 for x_loop in range(0, len(x), options.x_tile): x_start = np.maximum(x_loop, 0) x_end = np.minimum(x_loop + options.x_tile, len(x)) # determine actual overlap for cutting for y_loop in range(0, len(y), options.y_tile): x_overlap_min = x_start - np.maximum(x_start - options.x_overlap, 0) x_overlap_max = np.minimum(x_end + options.x_overlap, len(x)) - x_end n += 1 # print('tile {:001d}:'.format(n)) y_start = np.maximum(y_loop, 0) y_end = np.minimum(y_loop + options.y_tile, len(y)) y_overlap_min = y_start - np.maximum(y_start - options.y_overlap, 0) y_overlap_max = np.minimum(y_end + options.y_overlap, len(y)) - y_end x_tile_ax = x[x_start - x_overlap_min:x_end + x_overlap_max] y_tile_ax = y[y_start - y_overlap_min:y_end + y_overlap_max] # cut out DEM logger.debug('handling xmin: {:d} xmax: {:d} ymin {:d} ymax {:d}'.format(x_start, x_end, y_start, y_end)) drainage = rasterband_ldd.ReadAsArray(x_start - x_overlap_min, y_start - y_overlap_min, (x_end + x_overlap_max) - (x_start - x_overlap_min), (y_end + y_overlap_max) - (y_start - y_overlap_min) ) stream = rasterband_stream.ReadAsArray(x_start - x_overlap_min, y_start - y_overlap_min, (x_end + x_overlap_max) - (x_start - x_overlap_min), (y_end + y_overlap_max) - (y_start - y_overlap_min) ) # stream_max = np.minimum(stream.max(), options.max_strahler) inun_lib.gdal_writemap(drainage_temp_file, 'PCRaster', x_tile_ax, y_tile_ax, drainage, rasterband_ldd.GetNoDataValue(), gdal_type=gdal.GDT_Int32, logging=logger) inun_lib.gdal_writemap(stream_temp_file, 'PCRaster', x_tile_ax, y_tile_ax, stream, rasterband_stream.GetNoDataValue(), gdal_type=gdal.GDT_Int32, logging=logger) # read as pcr objects pcr.setclone(stream_temp_file) drainage_pcr = pcr.lddrepair(pcr.ldd(pcr.readmap(drainage_temp_file))) # convert to ldd type map stream_pcr = pcr.scalar(pcr.readmap(stream_temp_file)) # convert to ldd type map # warp of flood volume to inundation resolution inun_lib.gdal_warp(flood_vol_map, stream_temp_file, flood_vol_temp_file, gdal_interp=gdalconst.GRA_NearestNeighbour) # , x_tile_ax, y_tile_ax, flood_meter, fill_value = inun_lib.gdal_readmap(flood_vol_temp_file, 'GTiff', logging=logger) # make sure that the option unittrue is on !! (if unitcell was is used in another function) x_res_tile, y_res_tile, reallength = pcrut.detRealCellLength(pcr.scalar(stream_pcr), not(bool(options.latlon))) cell_surface_tile = pcr.pcr2numpy(x_res_tile * y_res_tile, 0) # convert meter depth to volume [m3] flood_vol = pcr.numpy2pcr(pcr.Scalar, flood_meter*cell_surface_tile, fill_value) # first prepare a basin map, belonging to the lowest order we are looking at inundation_pcr = pcr.scalar(stream_pcr) * 0 for hand_strahler in range(options.catchment_strahler, stream_max + 1, 1): # hand_temp_file = os.path.join(flood_folder, 'hand_temp.map') if os.path.isfile(os.path.join(options.dest_path, '{:s}_hand_strahler_{:02d}.tif'.format(dem_name, hand_strahler))): hand_file = os.path.join(options.dest_path, '{:s}_hand_strahler_{:02d}.tif'.format(dem_name, hand_strahler)) else: hand_file = '{:s}_{:02d}.tif'.format(options.hand_file_prefix, hand_strahler) ds_hand, rasterband_hand = inun_lib.get_gdal_rasterband(hand_file) hand = rasterband_hand.ReadAsArray(x_start - x_overlap_min, y_start - y_overlap_min, (x_end + x_overlap_max) - (x_start - x_overlap_min), (y_end + y_overlap_max) - (y_start - y_overlap_min) ) print('len x-ax: {:d} len y-ax {:d} x-shape {:d} y-shape {:d}'.format(len(x_tile_ax), len(y_tile_ax), hand.shape[1], hand.shape[0])) inun_lib.gdal_writemap(hand_temp_file, 'PCRaster', x_tile_ax, y_tile_ax, hand, rasterband_hand.GetNoDataValue(), gdal_type=gdal.GDT_Float32, logging=logger) hand_pcr = pcr.readmap(hand_temp_file) stream_ge_hand, subcatch_hand = inun_lib.subcatch_stream(drainage_pcr, options.catchment_strahler, stream=stream_pcr) # stream_ge_hand, subcatch_hand = inun_lib.subcatch_stream(drainage_pcr, hand_strahler, stream=stream_pcr) stream_ge, subcatch = inun_lib.subcatch_stream(drainage_pcr, options.catchment_strahler, stream=stream_pcr, basin=pcr.boolean(pcr.cover(subcatch_hand, 0)), assign_existing=True, min_strahler=hand_strahler, max_strahler=hand_strahler) # generate subcatchments, only within basin for HAND flood_vol_strahler = pcr.ifthenelse(pcr.boolean(pcr.cover(subcatch, 0)), flood_vol, 0) # mask the flood volume map with the created subcatch map for strahler order = hand_strahler inundation_pcr_step = inun_lib.volume_spread(drainage_pcr, hand_pcr, pcr.subcatchment(drainage_pcr, subcatch), # to make sure backwater effects can occur from higher order rivers to lower order rivers flood_vol_strahler, volume_thres=0., iterations=options.iterations, cell_surface=pcr.numpy2pcr(pcr.Scalar, cell_surface_tile, -9999), logging=logger, order=hand_strahler, neg_HAND=options.neg_HAND) # 1166400000. # use maximum value of inundation_pcr_step and new inundation for higher strahler order inundation_pcr = pcr.max(inundation_pcr, inundation_pcr_step) inundation = pcr.pcr2numpy(inundation_pcr, -9999.) # cut relevant part if y_overlap_max == 0: y_overlap_max = -inundation.shape[0] if x_overlap_max == 0: x_overlap_max = -inundation.shape[1] inundation_cut = inundation[0+y_overlap_min:-y_overlap_max, 0+x_overlap_min:-x_overlap_max] # inundation_cut if options.out_format == 0: band_inun.WriteArray(inundation_cut, x_start, y_start) band_inun.FlushCache() else: # with netCDF, data is up-side-down. inun_lib.write_tile_nc(band_inun, inundation_cut, x_start, y_start) # clean up os.unlink(flood_vol_temp_file) os.unlink(drainage_temp_file) os.unlink(hand_temp_file) os.unlink(stream_temp_file) #also remove temp stream file from output folder # if n == 35: # band_inun.SetNoDataValue(-9999.) # ds_inun = None # sys.exit(0) # os.unlink(flood_vol_map) logger.info('Finalizing {:s}'.format(inun_file)) # add the metadata to the file and band # band_inun.SetNoDataValue(-9999.) # ds_inun.SetMetadata(metadata_global) # band_inun.SetMetadata(metadata_var) if options.out_format == 0: ds_inun = None ds_hand = None else: ds_inun.close() ds_ldd = None # rename temporary file to final hand file if os.path.isfile(inun_file): # remove an old result if available os.unlink(inun_file) os.rename(inun_file_tmp, inun_file) logger.info('Done! Thank you for using hand_contour_inun.py') logger, ch = inun_lib.closeLogger(logger, ch) del logger, ch sys.exit(0)
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) transfer_to_downstream = pcr.cover(\ pcr.ifthen(pcr.scalar(water_body_outlet) > 0., lake_reservoir_overbank_volume * 0.50), 0.0) transfer_to_downstream = pcr.upstream(ldd_map_low_resolution, transfer_to_downstream) transfer_to_downstream = pcr.upstream(ldd_map_low_resolution, transfer_to_downstream) transfer_to_downstream = pcr.upstream(ldd_map_low_resolution, transfer_to_downstream) extreme_value_map = transfer_to_downstream + \ pcr.ifthenelse(pcr.cover(pcr.scalar(water_body_id), 0.0) > 0.00, 0.00, extreme_value_map) # # the remaining overbank volume (50%) will be distributed to the shores lake_reservoir_overbank_volume = lake_reservoir_overbank_volume * 0.50 land_area = cell_area * pcr.max(0.0, 1.0 - fracwat) land_area_average = pcr.areaaverage(land_area, water_body_id)
logger.info(msg) return_period_historical = glofris.get_return_period_gumbel(p_zero["historical"], location["historical"], scale["historical"], extreme_values["including_bias"][return_period]) extreme_values['return_period_historical'][return_period] = return_period_historical #~ pcr.report(return_period_historical, "return_period_historical.map") #~ cmd = "aguila " + "return_period_historical.map" #~ os.system(cmd) # bias corrected extreme values msg = "Calculate the bias corrected extreme values: Using the return period based on the historical gumbel fit/parameters and the gumbel fit/parameters of the baseline run." logger.info(msg) # extreme_value_map = glofris.inverse_gumbel(p_zero["baseline"], location["baseline"], scale["baseline"], return_period_historical) # # - make sure that we have positive extreme values - this is not necessary, but to make sure extreme_value_map = pcr.max(extreme_value_map, 0.0) # # - make sure that extreme value maps increasing over return period - this is not necessary, but to make sure if i_return_period > 0: extreme_value_map = pcr.max(previous_return_period_map, extreme_value_map) previous_return_period_map = extreme_value_map # # - saving extreme values in the dictionary extreme_values["bias_corrected"][return_period] = extreme_value_map # time bounds in a netcdf file lowerTimeBound = datetime.datetime(str_year, 1, 1, 0) upperTimeBound = datetime.datetime(end_year, 12, 31, 0) timeBounds = [lowerTimeBound, upperTimeBound] # reporting/saving extreme values in netcdf and pcraster files for bias_type in ['including_bias', 'bias_corrected']:
def dynamic(self): # re-calculate current model time using current pcraster timestep value self.modelTime.update(self.currentTimeStep()) # for variables other than temperature and maximum temperature, just read them directly if self.output['variable_name'] != "temperature" and self.output['variable_name'] != "maximum_temperature": pcraster_map_file_name = pcr.framework.frameworkBase.generateNameT(self.pcraster_file_name,\ self.modelTime.timeStepPCR) pcr_map_values = vos.readPCRmapClone(v = pcraster_map_file_name,\ cloneMapFileName = self.cloneMapFileName,\ tmpDir = self.tmpDir,\ absolutePath = None, isLddMap = False,\ cover = None,\ isNomMap = False,\ inputEPSG = self.inputEPSG,\ outputEPSG = self.outputEPSG,\ method = self.resample_method) # for temperature and maximum temperature, we have to make sure that maximum temperature is higher than minimum temperature if self.output['variable_name'] == "temperature" or self.output['variable_name'] == "maximum_temperature": min_map_file_name = pcr.framework.frameworkBase.generateNameT(self.pcraster_files['directory']+"/tn", self.modelTime.timeStepPCR) max_map_file_name = pcr.framework.frameworkBase.generateNameT(self.pcraster_files['directory']+"/tx", self.modelTime.timeStepPCR) min_map_values = vos.readPCRmapClone(v = min_map_file_name,\ cloneMapFileName = self.cloneMapFileName,\ tmpDir = self.tmpDir,\ absolutePath = None, isLddMap = False,\ cover = None,\ isNomMap = False,\ inputEPSG = self.inputEPSG,\ outputEPSG = self.outputEPSG,\ method = self.resample_method) max_map_values = vos.readPCRmapClone(v = max_map_file_name,\ cloneMapFileName = self.cloneMapFileName,\ tmpDir = self.tmpDir,\ absolutePath = None, isLddMap = False,\ cover = None,\ isNomMap = False,\ inputEPSG = self.inputEPSG,\ outputEPSG = self.outputEPSG,\ method = self.resample_method) # make sure that maximum values are higher than minimum values max_map_values = pcr.max(min_map_values, max_map_values) if self.output['variable_name'] == "temperature": pcr_map_values = 0.50*(min_map_values + \ max_map_values) if self.output['variable_name'] == "maximum_temperature": pcr_map_values = pcr.max(min_map_values, max_map_values) # for precipitation, converting the unit from mm.day-1 to m.day-1 if self.output['variable_name'] == "precipitation": pcr_map_values *= 0.001 # reporting timeStamp = datetime.datetime(self.modelTime.year,\ self.modelTime.month,\ self.modelTime.day,0) self.netcdf_report.data2NetCDF(self.output['file_name'],\ self.output['variable_name'],\ pcr.pcr2numpy(pcr_map_values,vos.MV),\ timeStamp)
# variable name variable_name = str(return_period) + "_of_" + varDict.netcdf_short_name[var_name] msg = "Writing " + str(variable_name) logger.info(msg) # read from pcraster files # inundation_file_name = output_directory + "/global/maps/" + "inun_" + str(return_period) + "_of_flood_inundation_volume_catch_" + strahler_order_option + ".tif.map" if map_type_name == "channel_storage.map": inundation_file_name = output_directory + "/global/maps/" + "inun_" + str(return_period) + "_of_channel_storage_catch_" + strahler_order_option + ".tif.map" # inundation_map = pcr.readmap(inundation_file_name) inundation_map = pcr.cover(inundation_map, 0.0) # # - make sure that we have positive extreme values - this is not necessary, but to make sure inundation_map = pcr.max(inundation_map, 0.0) # # - make sure that extreme value maps increasing over return period - this is not necessary, but to make sure if i_return_period > 0: inundation_map = pcr.max(previous_return_period_map, inundation_map) previous_return_period_map = inundation_map # using values in the landmask only and masking out permanent water bodies inundation_map = pcr.ifthen(landmask_used, inundation_map) inundation_map = pcr.ifthen(non_permanent_water_bodies, inundation_map) # report in pcraster maps pcr.report(inundation_map, inundation_file_name + ".masked_out.map") # write to netcdf files netcdf_report.data_to_netcdf(file_name, variable_name, pcr.pcr2numpy(inundation_map, vos.MV), timeBounds, timeStamp = None, posCnt = 0)
channel_storage = vos.netcdf2PCRobjClone(input_files['file_name']['channelStorage'], \ "channel_storage", time_index_in_netcdf_file,\ useDoy = "Yes", \ cloneMapFileName = clone_map_file,\ LatitudeLongitude = True,\ specificFillValue = None) channel_storage = pcr.ifthen(landmask, pcr.cover(channel_storage, 0.0)) # read fraction_of_surface_water (dimensionless) fraction_of_surface_water = vos.netcdf2PCRobjClone(input_files['file_name']['dynamicFracWat'], \ "fraction_of_surface_water", time_index_in_netcdf_file,\ useDoy = "Yes", \ cloneMapFileName = clone_map_file,\ LatitudeLongitude = True,\ specificFillValue = None) fraction_of_surface_water = pcr.ifthen(landmask, pcr.cover(fraction_of_surface_water, 0.0)) # calculate surface water level surface_water_level = channel_storage / (pcr.max(fraction_of_surface_water, minimum_fraction_of_surface_water) * cell_area) # convert it to arrays surface_water_level = pcr.pcr2numpy(surface_water_level, vos.MV) # save it to netcdf file ncFileName = netcdf_file[var_name]['file_name'] msg = "Saving to the netcdf file: " + str(netcdf_file[var_name]['file_name']) logger.info(msg) time_stamp_used = datetime.datetime(i_year, 12, 31, 0) netcdf_report.data2NetCDF(ncFileName, varDict.netcdf_short_name[var_name], surface_water_level, time_stamp_used)