def find_outlet(ldd): """ Tries to find the outlet of the largest catchment in the Ldd Input: - Ldd Output: - outlet map (single point in the map) """ largest = pcr.mapmaximum(pcr.catchmenttotal(pcr.spatial(pcr.scalar(1.0)), ldd)) outlet = pcr.ifthen( pcr.catchmenttotal(1.0, ldd) == largest, pcr.spatial(pcr.scalar(1.0)) ) return outlet
def dynamic(self): # re-calculate current model time using current pcraster timestep value self.modelTime.update(self.currentTimeStep()) # processing done only at the last day of the month if self.modelTime.isLastDayOfYear(): logger.info("Reading runoff for time %s", self.modelTime.currTime) annual_input_file = self.input_file %(str(self.modelTime.currTime.year), \ str(self.modelTime.currTime.year)) self.cell_value = vos.netcdf2PCRobjClone(annual_input_file, "automatic", \ str(self.modelTime.fulldate), \ useDoy = None, \ cloneMapFileName = self.clonemap_file_name, \ LatitudeLongitude = True) self.cell_value = pcr.cover(self.total_runoff, 0.0) logger.info("Calculating basin value for time %s", self.modelTime.currTime) self.basin_value = pcr.catchmenttotal( self.total_runoff * self.cell_area, self.ldd_network) / self.basin_area # reporting # - time stamp for reporting timeStamp = datetime.datetime(self.modelTime.year,\ self.modelTime.month,\ self.modelTime.day,\ 0) logger.info("Reporting for time %s", self.modelTime.currTime) self.netcdf_report.data2NetCDF(self.output_file, \ "total_flow", \ pcr.pcr2numpy(self.total_flow, vos.MV), \ timeStamp)
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 additional_post_processing(self): # In this method/function, users can add their own post-processing. # consumption for and return flow from non irrigation water demand (unit: m/day) ## TODO self.nonIrrWaterConsumption = self._model.routing.nonIrrWaterConsumption ## TODO self.nonIrrReturnFlow = self._model.routing.nonIrrReturnFlow # accumulated runoff (m3/s) along the drainage network - not including local changes in water bodies if "accuRunoff" in self.variables_for_report: self.accuRunoff = pcr.catchmenttotal( self.runoff * self._model.routing.cellArea, self._model.routing.lddMap) / vos.secondsPerDay() # accumulated baseflow (m3) along the drainage network if "accuBaseflow" in self.variables_for_report: self.accuBaseflow = pcr.catchmenttotal( self.baseflow * self._model.routing.cellArea, self._model.routing.lddMap) # local changes in water bodies (i.e. abstraction, return flow, evaporation, bed exchange), excluding runoff self.local_water_body_flux = self._model.routing.local_input_to_surface_water / self._model.routing.cellArea - self.runoff # total runoff (m) from local land surface runoff and local changes in water bodies self.totalRunoff = self.runoff + self.local_water_body_flux # actually this is equal to self._model.routing.local_input_to_surface_water / self._model.routing.cellArea # accumulated total runoff (m3) along the drainage network - not including local changes in water bodies if "accuTotalRunoff" in self.variables_for_report: self.accuTotalRunoff = pcr.catchmenttotal( self.totalRunoff * self._model.routing.cellArea, self._model.routing.lddMap) / vos.secondsPerDay() # surfaceWaterStorage (unit: m) - negative values may be reported self.surfaceWaterStorage = self._model.routing.channelStorage / self._model.routing.cellArea # Stefanie's post processing: reporting lake and reservoir storage (unit: m3) self.waterBodyStorage = pcr.ifthen(self._model.routing.landmask, \ pcr.ifthen(\ pcr.scalar(self._model.routing.WaterBodies.waterBodyIds) > 0.,\ self._model.routing.WaterBodies.waterBodyStorage)) # Note: This value is after lake/reservoir outflow.
def getCatchmentMap(config, modLon, modLat, option="Reference options"): catchmentAreaMap = str(config.get(option, 'catchmentAreaMap')) cellAreaMap = str(config.get(option, 'cellAreaMap')) cellAreaConstant = str(config.get(option, 'cellAreaConstant')) routingMap = str(config.get(option, 'routingMap')) if os.path.exists(catchmentAreaMap): f = gdal.Open(catchmentAreaMap) catchmentArea = matchMaps(f, modLon, modLat) return catchmentArea elif os.path.exists(cellAreaMap) and os.path.exists(routingMap): pcr.setclone(routingMap) catchmentAcc = pcr.catchmenttotal(cellAreaMap, routingMap) catchmentArea = pcr.pcr2numpy(catchmentAcc, -9999.) return catchmentArea elif os.path.exists(cellAreaMap) and os.path.exists(routingMap): pcr.setclone(routingMap) catchmentAcc = pcr.catchmenttotal(pcr.scalar(cellAreaConstant), routingMap) catchmentArea = pcr.pcr2numpy(catchmentAcc, -9999.) return catchmentArea else: print "No valid catchment size and or routing map provided" return False
def getCatchmentMap(config, option="otherReference"): catchmentAreaMap = str(config.get(option, 'catchmentAreaMap')) cellAreaMap = str(config.get(option, 'cellAreaMap')) cellAreaConstant = str(config.get(option, 'cellAreaConstant')) routingMap = str(config.get(option, 'routingMap')) if os.path.exists(catchmentAreaMap): f = gdal.Open(catchmentAreaMap) catchmentArea = f.GetRasterBand(1).ReadAsArray() return catchmentArea elif os.path.exists(cellAreaMap) and os.path.exists(routingMap): pcr.setclone(routingMap) catchmentAcc = pcr.catchmenttotal(cellAreaMap, routingMap) catchmentArea = pcr.pcr2numpy(catchmentAcc, -9999.) return catchmentArea elif os.path.exists(cellAreaMap) and os.path.exists(routingMap): pcr.setclone(routingMap) catchmentAcc = pcr.catchmenttotal(pcr.scalar(cellAreaConstant), routingMap) catchmentArea = pcr.pcr2numpy(catchmentAcc, -9999.) return catchmentArea else: print "No valid catchment size and or routing map provided" return False
def budgetCheck(self, sample, timestep): # NOTE this is only valid if addition,subtraction and lateral flow are invoked EACH TIME STEP # NOTE this does not include amountOfMoistureThickNetAdded in case of regolith thickness change self.actualAdditionCum = self.actualAdditionCum + self.actualAdditionFlux * self.timeStepDuration self.actualAbstractionCum = self.actualAbstractionCum + self.actualAbstractionFlux * self.timeStepDuration self.upwardSeepageCum = self.upwardSeepageCum + self.upwardSeepageFlux * self.timeStepDuration self.lateralFlowFluxAmountCum = self.lateralFlowFluxAmountCum + self.lateralFlowFluxAmount self.increaseInSubsurfaceStorage = self.soilMoistureThick - self.initialSoilMoistureThick budget = pcr.catchmenttotal(self.actualAdditionCum - self.increaseInSubsurfaceStorage - self.actualAbstractionCum - self.upwardSeepageCum, self.ldd) \ - self.lateralFlowFluxAmountCum pcr.report(budget, pcrfw.generateNameST('B-sub', sample, timestep)) pcr.report(budget / self.lateralFlowFluxAmountCum, pcrfw.generateNameST('BR-sub', sample, timestep)) return self.increaseInSubsurfaceStorage, self.lateralFlowFluxAmountCum, self.actualAbstractionCum
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 dynamic(self): # re-calculate current model time using current pcraster timestep value self.modelTime.update(self.currentTimeStep()) # processing done only at the last day of the month if self.modelTime.isLastDayOfMonth(): logger.info("Reading runoff for time %s", self.modelTime.currTime) self.total_runoff = vos.netcdf2PCRobjClone(self.totat_runoff_input_file, "total_runoff",\ str(self.modelTime.fulldate), useDoy = None, cloneMapFileName = self.clonemap_file_name,\ LatitudeLongitude = True) self.total_runoff = pcr.cover(self.total_runoff, 0.0) logger.info("Calculating total inflow and internal inflow for time %s", self.modelTime.currTime) self.total_flow = pcr.catchmenttotal(self.total_runoff * self.cell_area, self.ldd_network) self.internal_flow = pcr.areatotal(self.total_runoff * self.cell_area, self.sub_catchment) # - convert values to m3/s number_of_days_in_a_month = self.modelTime.day self.total_flow = self.total_flow / (number_of_days_in_a_month * 24. * 3600.) self.internal_flow = self.internal_flow / (number_of_days_in_a_month * 24. * 3600.) # - limit the values to the landmask only self.total_flow = pcr.ifthen(self.landmask, self.total_flow) self.internal_flow = pcr.ifthen(self.landmask, self.internal_flow) logger.info("Extrapolating or time %s", self.modelTime.currTime) # Purpose: To avoid missing value data while being extracted by cdo command self.total_flow = pcr.cover(self.total_flow, pcr.windowmaximum(self.total_flow, 0.125)) self.internal_flow = pcr.cover(self.internal_flow, pcr.windowaverage(self.internal_flow, 0.125)) # reporting # - time stamp for reporting timeStamp = datetime.datetime(self.modelTime.year,\ self.modelTime.month,\ self.modelTime.day,\ 0) logger.info("Reporting for time %s", self.modelTime.currTime) self.netcdf_report.data2NetCDF(self.total_flow_output_file, \ "total_flow", \ pcr.pcr2numpy(self.total_flow, vos.MV), \ timeStamp) self.netcdf_report.data2NetCDF(self.internal_flow_output_file, \ "internal_flow", \ pcr.pcr2numpy(self.internal_flow, vos.MV), \ timeStamp)
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 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
output_files['tmp_folder'], None, False, None, True)) #~ pcr.aguila(basin_map) # - extend/extrapolate the basin basin_map = pcr.cover(basin_map, pcr.windowmajority(basin_map, 0.5)) basin_map = pcr.cover(basin_map, pcr.windowmajority(basin_map, 0.5)) basin_map = pcr.cover(basin_map, pcr.windowmajority(basin_map, 0.5)) basin_map = pcr.cover(basin_map, pcr.windowmajority(basin_map, 1.0)) basin_map = pcr.cover(basin_map, pcr.windowmajority(basin_map, 1.5)) basin_map = pcr.ifthen(landmask, basin_map) #~ pcr.aguila(basin_map) msg = "Redefining the basin map (so that it is consistent with the ldd map used in PCR-GLOBWB):" logger.info(msg) # - calculate the upstream area of every pixel: upstream_area = pcr.catchmenttotal(cell_area, ldd) # - calculate the catchment area of every basin: upstream_area_maximum = pcr.areamaximum(upstream_area, basin_map) # - identify the outlet of every basin (in order to rederive the basin so that it is consistent with the ldd) outlet = pcr.nominal( pcr.uniqueid( pcr.ifthen(upstream_area == upstream_area_maximum, pcr.boolean(1.0)))) # - ignoring outlets with small upstream areas threshold = 50. * 1000. * 1000. # unit: m2 outlet = pcr.ifthen(upstream_area_maximum > threshold, outlet) #~ pcr.aguila(outlet) outlet = pcr.cover(outlet, pcr.nominal(0.0)) # - recalculate the basin basin_map = pcr.nominal(pcr.subcatchment(ldd, outlet)) basin_map = pcr.clump(basin_map) basin_map = pcr.ifthen(landmask, basin_map)
def dynamic(self): self.counter += 1 print( str(self.curdate.day) + '-' + str(self.curdate.month) + '-' + str(self.curdate.year) + ' t = ' + str(self.counter)) #-Snow and rain fraction settings for non-glacier part of model cell SnowFrac = pcr.ifthenelse(self.SnowStore > 0, pcr.scalar(1 - self.GlacFrac), 0) RainFrac = pcr.ifthenelse(self.SnowStore == 0, pcr.scalar(1 - self.GlacFrac), 0) #-Read the precipitation time-series if self.precNetcdfFLAG == 1: #-read forcing by netcdf input Precip = self.netcdf2PCraster.netcdf2pcrDynamic(self, pcr, 'Prec') else: #-read forcing by map input Precip = pcr.readmap(pcrm.generateNameT(self.Prec, self.counter)) PrecipTot = Precip #-Report Precip self.reporting.reporting(self, pcr, 'TotPrec', Precip) self.reporting.reporting(self, pcr, 'TotPrecF', Precip * (1 - self.GlacFrac)) #-Temperature and determine reference evapotranspiration if self.tempNetcdfFLAG == 1: #-read forcing by netcdf input Temp = self.netcdf2PCraster.netcdf2pcrDynamic(self, pcr, 'Temp') else: #-read forcing by map input Temp = pcr.readmap(pcrm.generateNameT(self.Tair, self.counter)) if self.ETREF_FLAG == 0: if self.TminNetcdfFLAG == 1: #-read forcing by netcdf input TempMin = self.netcdf2PCraster.netcdf2pcrDynamic( self, pcr, 'Tmin') else: #-read forcing by map input TempMin = pcr.readmap( pcrm.generateNameT(self.Tmin, self.counter)) if self.TmaxNetcdfFLAG == 1: #-read forcing by netcdf input TempMax = self.netcdf2PCraster.netcdf2pcrDynamic( self, pcr, 'Tmax') else: #-read forcing by map input TempMax = pcr.readmap( pcrm.generateNameT(self.Tmax, self.counter)) ETref = self.Hargreaves.Hargreaves( pcr, self.Hargreaves.extrarad(self, pcr), Temp, TempMax, TempMin) else: ETref = pcr.readmap(pcrm.generateNameT(self.ETref, self.counter)) self.reporting.reporting(self, pcr, 'TotETref', ETref) self.reporting.reporting(self, pcr, 'TotETrefF', ETref * (1 - self.GlacFrac)) #-Interception and effective precipitation if self.DynVegFLAG == 1: #-read dynamic processes dynamic vegetation Precip = self.dynamic_veg.dynamic(self, pcr, pcrm, np, Precip, ETref) elif self.KcStatFLAG == 0: #-Try to read the KC map series try: self.Kc = pcr.readmap( pcrm.generateNameT(self.Kcmaps, self.counter)) self.KcOld = self.Kc except: self.Kc = self.KcOld #-report mm effective precipitation for sub-basin averages if self.mm_rep_FLAG == 1 and self.Prec_mm_FLAG == 1 and ( self.RoutFLAG == 1 or self.ResFLAG == 1 or self.LakeFLAG == 1): self.PrecSubBasinTSS.sample( pcr.catchmenttotal(Precip * (1 - self.GlacFrac), self.FlowDir) / pcr.catchmenttotal(1, self.FlowDir)) #-Snow, rain, and glacier calculations for glacier fraction of cell if self.GlacFLAG: #-read dynamic processes glacier Rain_GLAC, Snow_GLAC, ActSnowMelt_GLAC, SnowR_GLAC, GlacMelt, GlacPerc, self.GlacR = self.glacier.dynamic( self, pcr, pd, Temp, Precip) #-If glacier module is not used, then else: Rain_GLAC = 0 Snow_GLAC = 0 ActSnowMelt_GLAC = 0 self.TotalSnowStore_GLAC = 0 SnowR_GLAC = 0 self.GlacR = 0 GlacMelt = 0 GlacPerc = 0 # Calculate snow and rain for non-glacier part of cell if self.SnowFLAG == 1: #-read dynamic processes snow Rain, self.SnowR, OldTotalSnowStore = self.snow.dynamic( self, pcr, Temp, Precip, Snow_GLAC, ActSnowMelt_GLAC, SnowFrac, RainFrac, SnowR_GLAC) else: Rain = Precip self.SnowR = 0 OldTotalSnowStore = 0 self.TotalSnowStore = 0 #-Report Rain self.reporting.reporting(self, pcr, 'TotRain', Rain) self.reporting.reporting(self, pcr, 'TotRainF', Rain * (1 - self.GlacFrac) + Rain_GLAC) # for entire cell #-Potential evapotranspiration ETpot = self.ET.ETpot(ETref, self.Kc) if self.ETOpenWaterFLAG == 1: self.ETOpenWater = self.ET.ETpot(ETref, self.kcOpenWater) #-Report ETpot self.reporting.reporting(self, pcr, 'TotETpot', ETpot) self.reporting.reporting(self, pcr, 'TotETpotF', ETpot * RainFrac) #-Rootzone calculations self.RootWater = self.RootWater + self.CapRise #-Calculate rootzone runoff tempvar = self.rootzone.RootRunoff(self, pcr, RainFrac, Rain) #-Rootzone runoff RootRunoff = tempvar[0] #-Infiltration Infil = tempvar[1] #-Report infiltration self.reporting.reporting(self, pcr, 'Infil', Infil) #-Updated rootwater content self.RootWater = pcr.ifthenelse(RainFrac > 0, self.RootWater + Infil, self.RootWater) #-Actual evapotranspiration if self.PlantWaterStressFLAG == 1: etreddry = self.ET.ks(self, pcr, ETpot) else: etreddry = pcr.max( pcr.min((self.RootWater - self.RootDry) / (self.RootWilt - self.RootDry), 1), 0) self.reporting.reporting(self, pcr, 'PlantStress', 1 - etreddry) ETact = self.ET.ETact(pcr, ETpot, self.RootWater, self.RootSat, etreddry, RainFrac) #-Report the actual evapotranspiration self.reporting.reporting( self, pcr, 'TotETact', ETact * (1 - self.openWaterFrac) + self.ETOpenWater * self.openWaterFrac) #-Actual evapotranspiration, corrected for rain fraction ActETact = ETact * RainFrac #-Report the actual evapotranspiration, corrected for rain fraction self.reporting.reporting(self, pcr, 'TotETactF', ActETact) if self.mm_rep_FLAG == 1 and self.ETa_mm_FLAG == 1 and ( self.RoutFLAG == 1 or self.ResFLAG == 1 or self.LakeFLAG == 1): self.ETaSubBasinTSS.sample( pcr.catchmenttotal(ActETact, self.FlowDir) / pcr.catchmenttotal(1, self.FlowDir)) #-Update rootwater content self.RootWater = pcr.max(self.RootWater - ETact, 0) #-Calculate drainage temp_RootDrain = self.rootzone.RootDrainage( pcr, self.RootWater, self.RootDrain, self.RootField, self.RootSat, self.RootDrainVel, self.RootTT) #-Calculate percolation temp_rootperc = self.rootzone.RootPercolation(pcr, self.RootWater, self.SubWater, self.RootField, self.RootTT, self.SubSat) #-Total sum of water able to leave the soil RootOut = temp_RootDrain + temp_rootperc #-Calculate new values for drainage and percolation (to be used when RootOut > RootExcess) newdrain, newperc = self.rootzone.CalcFrac(pcr, self.RootWater, self.RootField, temp_RootDrain, temp_rootperc) #-Determine whether the new values need to be used rootexcess = pcr.max(self.RootWater - self.RootField, 0) self.RootDrain = pcr.ifthenelse(RootOut > rootexcess, newdrain, temp_RootDrain) rootperc = pcr.ifthenelse(RootOut > rootexcess, newperc, temp_rootperc) #-Update the RootWater content # Roottemp = self.RootWater self.RootWater = self.RootWater - (self.RootDrain + rootperc) #-Report rootzone percolation, corrected for fraction self.reporting.reporting(self, pcr, 'TotRootPF', rootperc * (1 - self.GlacFrac)) #-Report rootwater content self.reporting.reporting(self, pcr, 'StorRootW', self.RootWater * (1 - self.openWaterFrac)) #-Sub soil calculations self.SubWater = self.SubWater + rootperc if self.GroundFLAG == 0: if self.SeepStatFLAG == 0: try: self.SeePage = pcr.readmap( pcrm.generateNameT(self.Seepmaps, self.counter)) self.SeepOld = self.SeePage except: self.SeePage = self.SeepOld #-Report seepage self.reporting.reporting(self, pcr, 'TotSeepF', pcr.scalar(self.SeePage)) self.SubWater = pcr.min(pcr.max(self.SubWater - self.SeePage, 0), self.SubSat) if self.mm_rep_FLAG == 1 and self.Seep_mm_FLAG == 1 and ( self.RoutFLAG == 1 or self.ResFLAG == 1 or self.LakeFLAG == 1): self.SeepSubBasinTSS.sample( pcr.catchmenttotal(self.SeePage, self.FlowDir) / pcr.catchmenttotal(1, self.FlowDir)) #-Capillary rise self.CapRise = self.subzone.CapilRise(pcr, self.SubField, self.SubWater, self.CapRiseMax, self.RootWater, self.RootSat, self.RootField) #-Report capillary rise, corrected for fraction self.reporting.reporting(self, pcr, 'TotCapRF', self.CapRise * (1 - self.GlacFrac)) #-Update sub soil water content self.SubWater = self.SubWater - self.CapRise if self.GroundFLAG == 1: # sub percolation will be calculated instead of subdrainage subperc = self.subzone.SubPercolation(pcr, self.SubWater, self.SubField, self.SubTT, self.Gw, self.GwSat) ActSubPerc = subperc * (1 - self.GlacFrac) #-Report the subzone percolation, corrected for the fraction self.reporting.reporting(self, pcr, 'TotSubPF', ActSubPerc) #-Update sub soil water content self.SubWater = self.SubWater - subperc else: # sub drainage will be calculated instead of sub percolation self.SubDrain = self.subzone.SubDrainage(pcr, self.SubWater, self.SubField, self.SubSat, self.SubDrainVel, self.SubDrain, self.SubTT) #-Report drainage from subzone self.reporting.reporting(self, pcr, 'TotSubDF', self.SubDrain) #-Update sub soil water content self.SubWater = self.SubWater - self.SubDrain #-Report rootwater content self.reporting.reporting(self, pcr, 'StorSubW', self.SubWater * (1 - self.openWaterFrac)) #-Changes in soil water storage OldSoilWater = self.SoilWater self.SoilWater = (self.RootWater + self.SubWater) * (1 - self.GlacFrac) #-Rootzone runoff self.RootRR = RootRunoff * RainFrac * (1 - self.openWaterFrac) #-Report rootzone runoff, corrected for fraction self.reporting.reporting(self, pcr, 'TotRootRF', self.RootRR) #-Rootzone drainage self.RootDR = self.RootDrain * (1 - self.GlacFrac) * ( 1 - self.openWaterFrac) #-Report rootzone drainage, corrected for fraction self.reporting.reporting(self, pcr, 'TotRootDF', self.RootDR) #-Rain runoff self.RainR = self.RootRR + self.RootDR #-Report rain runoff self.reporting.reporting(self, pcr, 'TotRainRF', self.RainR) #-Groundwater calculations if self.GroundFLAG == 1: #-read dynamic processes groundwater self.groundwater.dynamic(self, pcr, ActSubPerc, GlacPerc) else: #-Use drainage from subsoil as baseflow self.BaseR = self.SubDrain #-Groundwater level as scaled between min and max measured gwl SoilAct = self.RootWater + self.SubWater SoilRel = (SoilAct - self.SoilMin) / ( self.SoilMax - self.SoilMin ) # scale between 0 (dry) and 1 (wet) GWL = self.GWL_base - (SoilRel - 0.5) * self.GWL_base #-Report groundwater self.reporting.reporting(self, pcr, 'GWL', GWL) #-Report Total runoff TotR = self.BaseR + self.RainR + self.SnowR + self.GlacR self.reporting.reporting(self, pcr, 'TotRF', TotR) #-Routing for lake and/or reservoir modules if self.LakeFLAG == 1 or self.ResFLAG == 1: #-read dynamic processes advanced routing Q = self.advanced_routing.dynamic(self, pcr, pcrm, config, TotR, self.ETOpenWater, PrecipTot) #-Normal routing module elif self.RoutFLAG == 1: self.routing.dynamic(self, pcr, TotR) if self.GlacFLAG: #-read dynamic reporting processes glacier self.glacier.dynamic_reporting(self, pcr, pd, np) #-Water balance if self.GlacFLAG and self.GlacRetreat == 1: GlacTable_MODid = self.GlacTable.loc[:, ['FRAC_GLAC', 'ICE_DEPTH']] GlacTable_MODid['ICE_DEPTH'] = GlacTable_MODid[ 'ICE_DEPTH'] * GlacTable_MODid['FRAC_GLAC'] GlacTable_MODid = GlacTable_MODid.groupby( GlacTable_MODid.index).sum() GlacTable_MODid.fillna(0., inplace=True) #-Report pcraster map of glacier depth iceDepth = pcr.numpy.zeros(self.ModelID_1d.shape) iceDepth[self.GlacierKeys] = GlacTable_MODid['ICE_DEPTH'] iceDepth = iceDepth.reshape(self.ModelID.shape) iceDepth = pcr.numpy2pcr(pcr.Scalar, iceDepth, self.MV) iceDepth = pcr.ifthen( self.clone, iceDepth) #-only use values where clone is True iceDepth = iceDepth * 1000 # in mm #-change in storage dS = ((self.RootWater - self.oldRootWater) + (self.SubWater - self.oldSubWater)) * (1-self.GlacFrac) + (self.Gw - self.oldGw) + \ (self.TotalSnowStore-OldTotalSnowStore) + (iceDepth - self.oldIceDepth) #-set old state variables for glacier self.oldIceDepth = iceDepth iceDepth = None del iceDepth GlacTable_MODid = None del GlacTable_MODid elif self.GroundFLAG: #-change in storage dS = ((self.RootWater - self.oldRootWater) + (self.SubWater - self.oldSubWater)) * (1-self.GlacFrac) + (self.Gw - self.oldGw) + \ (self.TotalSnowStore-OldTotalSnowStore) # set old state variables for groundwater self.oldGw = self.Gw else: #-change in storage dS = ((self.RootWater - self.oldRootWater) + (self.SubWater - self.oldSubWater)) * (1 - self.GlacFrac) + ( self.TotalSnowStore - OldTotalSnowStore) #-water balance per time step if self.GroundFLAG: waterbalance = Precip - ActETact - self.BaseR - self.RainR - self.SnowR - self.GlacR - dS else: waterbalance = Precip - ActETact - self.BaseR - self.RainR - self.SnowR - dS - self.SeePage self.reporting.reporting(self, pcr, 'wbal', waterbalance) #-total water balance self.waterbalanceTot = self.waterbalanceTot + waterbalance #-report water balance and accumulated water balance if self.wbal_TSS_FLAG and (self.RoutFLAG == 1 or self.ResFLAG == 1 or self.LakeFLAG == 1): self.wbalTSS.sample( pcr.catchmenttotal(waterbalance, self.FlowDir) / pcr.catchmenttotal(1., self.FlowDir)) self.wbalTotTSS.sample( pcr.catchmenttotal(self.waterbalanceTot, self.FlowDir) / pcr.catchmenttotal(1., self.FlowDir)) # set old state variables self.oldRootWater = self.RootWater self.oldSubWater = self.SubWater waterbalance = None del waterbalance dS = None del dS #-End of water balance calculations #-Sediment yield if self.SedFLAG == 1: #-determine runoff in mm per day if self.RoutFLAG == 1 or self.ResFLAG == 1 or self.LakeFLAG == 1: Runoff = (Q * 3600 * 24) / pcr.cellarea() * 1000 else: Runoff = TotR #-MUSLE if self.SedModel == 1: #-read dynamic processes musle self.musle.dynamic(self, pcr, Runoff) #-sediment transport if self.SedTransFLAG == 1: #-read dynamic sediment transport processes musle self.sediment_transport.dynamic_musle(self, pcr) #-Modified Morgan-Morgan-Finney model if self.SedModel == 2: #-determine soil erosion in transport (G) G = self.mmf.dynamic(self, pcr, Precip, Runoff) #-sediment transport if self.SedTransFLAG == 1: #-read dynamic sediment transport processes mmf self.sediment_transport.dynamic_mmf( self, pcr, Runoff, np, G) #-update current date self.curdate = self.curdate + self.datetime.timedelta(days=1)
def checkBudgets(self, currentSampleNumber, currentTimeStep): increaseInPrecipitationStore = 0.0 - self.d_exchangevariables.cumulativePrecipitation pcr.report( increaseInPrecipitationStore, pcrfw.generateNameST('incP', currentSampleNumber, currentTimeStep)) increaseInInterceptionStore = self.d_interceptionuptomaxstore.budgetCheck( currentSampleNumber, currentTimeStep) pcr.report( increaseInInterceptionStore, pcrfw.generateNameST('incI', currentSampleNumber, currentTimeStep)) increaseInSurfaceStore = self.d_surfaceStore.budgetCheck( currentSampleNumber, currentTimeStep) pcr.report( increaseInSurfaceStore, pcrfw.generateNameST('incS', currentSampleNumber, currentTimeStep)) increaseInSurfaceStoreQM = pcr.catchmenttotal( increaseInSurfaceStore, self.ldd) * pcr.cellarea() pcr.report( increaseInSurfaceStoreQM, pcrfw.generateNameST('testb', currentSampleNumber, currentTimeStep)) # let op: infiltration store is directly passed to subsurface store, thus is not a real store increaseInInfiltrationStore = self.d_infiltrationgreenandampt.budgetCheck( currentSampleNumber, currentTimeStep) increaseInSubSurfaceWaterStore, lateralFlowInSubsurfaceStore, abstractionFromSubSurfaceWaterStore = \ self.d_subsurfaceWaterOneLayer.budgetCheck(currentSampleNumber, currentTimeStep) increaseInSubSurfaceStoreQM = pcr.catchmenttotal( increaseInSubSurfaceWaterStore, self.ldd) * pcr.cellarea() increaseInRunoffStoreCubicMetresInUpstreamArea = self.d_runoffAccuthreshold.budgetCheck( ) totalIncreaseInStoresCubicMetresInUpstreamArea = 0.0 stores = [ increaseInPrecipitationStore, increaseInInterceptionStore, increaseInSurfaceStore, increaseInSubSurfaceWaterStore ] for store in stores: increaseInStoreCubicMetresInUpstreamArea = pcr.catchmenttotal( store, self.ldd) * pcr.cellarea() totalIncreaseInStoresCubicMetresInUpstreamArea = totalIncreaseInStoresCubicMetresInUpstreamArea + \ increaseInStoreCubicMetresInUpstreamArea pcr.report( totalIncreaseInStoresCubicMetresInUpstreamArea, pcrfw.generateNameST('inSt', currentSampleNumber, currentTimeStep)) pcr.report( increaseInRunoffStoreCubicMetresInUpstreamArea, pcrfw.generateNameST('inRu', currentSampleNumber, currentTimeStep)) pcr.report( pcr.catchmenttotal(self.d_exchangevariables.upwardSeepageFlux, self.ldd) * pcr.cellarea(), pcrfw.generateNameST('inSe', currentSampleNumber, currentTimeStep)) # total budget is total increase in stores plus the upward seepage flux for each ts that is passed to the next # timestep and thus not taken into account in the current timestep budgets budget = totalIncreaseInStoresCubicMetresInUpstreamArea + increaseInRunoffStoreCubicMetresInUpstreamArea + \ lateralFlowInSubsurfaceStore * pcr.cellarea() + pcr.catchmenttotal(abstractionFromSubSurfaceWaterStore, self.ldd) * pcr.cellarea() + \ pcr.catchmenttotal(self.d_exchangevariables.upwardSeepageFlux, self.ldd) * pcr.cellarea() pcr.report( budget, pcrfw.generateNameST('B-tot', currentSampleNumber, currentTimeStep)) budgetRel = budget / increaseInRunoffStoreCubicMetresInUpstreamArea pcr.report( budgetRel, pcrfw.generateNameST('B-rel', currentSampleNumber, currentTimeStep))
def getParameterFiles(self,currTimeStep,cellArea,ldd,\ initial_condition_dictionary = None,\ currTimeStepInDateTimeFormat = False): # parameters for Water Bodies: fracWat # waterBodyIds # waterBodyOut # waterBodyArea # waterBodyTyp # waterBodyCap # cell surface area (m2) and ldd self.cellArea = cellArea ldd = pcr.ifthen(self.landmask, ldd) # date used for accessing/extracting water body information if currTimeStepInDateTimeFormat: date_used = currTimeStep year_used = currTimeStep.year else: date_used = currTimeStep.fulldate year_used = currTimeStep.year if self.onlyNaturalWaterBodies == True: date_used = self.dateForNaturalCondition year_used = self.dateForNaturalCondition[0:4] # fracWat = fraction of surface water bodies (dimensionless) self.fracWat = pcr.scalar(0.0) if self.useNetCDF: self.fracWat = vos.netcdf2PCRobjClone(self.ncFileInp,'fracWaterInp', \ date_used, useDoy = 'yearly',\ cloneMapFileName = self.cloneMap) else: self.fracWat = vos.readPCRmapClone(\ self.fracWaterInp+str(year_used)+".map", self.cloneMap,self.tmpDir,self.inputDir) self.fracWat = pcr.cover(self.fracWat, 0.0) self.fracWat = pcr.max(0.0, self.fracWat) self.fracWat = pcr.min(1.0, self.fracWat) self.waterBodyIds = pcr.nominal(0) # waterBody ids self.waterBodyOut = pcr.boolean(0) # waterBody outlets self.waterBodyArea = pcr.scalar(0.) # waterBody surface areas # water body ids if self.useNetCDF: self.waterBodyIds = vos.netcdf2PCRobjClone(self.ncFileInp,'waterBodyIds', \ date_used, useDoy = 'yearly',\ cloneMapFileName = self.cloneMap) else: self.waterBodyIds = vos.readPCRmapClone(\ self.waterBodyIdsInp+str(year_used)+".map",\ self.cloneMap,self.tmpDir,self.inputDir,False,None,True) # self.waterBodyIds = pcr.ifthen(\ pcr.scalar(self.waterBodyIds) > 0.,\ pcr.nominal(self.waterBodyIds)) # water body outlets (correcting outlet positions) wbCatchment = pcr.catchmenttotal(pcr.scalar(1), ldd) self.waterBodyOut = pcr.ifthen(wbCatchment ==\ pcr.areamaximum(wbCatchment, \ self.waterBodyIds),\ self.waterBodyIds) # = outlet ids # This may give more than two outlets, particularly if there are more than one cells that have largest upstream areas # - make sure that there is only one outlet for each water body self.waterBodyOut = pcr.ifthen(\ pcr.areaorder(pcr.scalar(self.waterBodyOut), \ self.waterBodyOut) == 1., self.waterBodyOut) self.waterBodyOut = pcr.ifthen(\ pcr.scalar(self.waterBodyIds) > 0.,\ self.waterBodyOut) # TODO: Please also consider endorheic lakes! # correcting water body ids self.waterBodyIds = pcr.ifthen(\ pcr.scalar(self.waterBodyIds) > 0.,\ pcr.subcatchment(ldd,self.waterBodyOut)) # boolean map for water body outlets: self.waterBodyOut = pcr.ifthen(\ pcr.scalar(self.waterBodyOut) > 0.,\ pcr.boolean(1)) # reservoir surface area (m2): if self.useNetCDF: resSfArea = 1000. * 1000. * \ vos.netcdf2PCRobjClone(self.ncFileInp,'resSfAreaInp', \ date_used, useDoy = 'yearly',\ cloneMapFileName = self.cloneMap) else: resSfArea = 1000. * 1000. * vos.readPCRmapClone( self.resSfAreaInp+str(year_used)+".map",\ self.cloneMap,self.tmpDir,self.inputDir) resSfArea = pcr.areaaverage(resSfArea, self.waterBodyIds) resSfArea = pcr.cover(resSfArea, 0.) # water body surface area (m2): (lakes and reservoirs) self.waterBodyArea = pcr.max(pcr.areatotal(\ pcr.cover(\ self.fracWat*self.cellArea, 0.0), self.waterBodyIds), pcr.areaaverage(\ pcr.cover(resSfArea, 0.0) , self.waterBodyIds)) self.waterBodyArea = pcr.ifthen(self.waterBodyArea > 0.,\ self.waterBodyArea) # correcting water body ids and outlets (exclude all water bodies with surfaceArea = 0) self.waterBodyIds = pcr.ifthen(self.waterBodyArea > 0., self.waterBodyIds) self.waterBodyOut = pcr.ifthen(pcr.boolean(self.waterBodyIds), self.waterBodyOut) # water body types: # - 2 = reservoirs (regulated discharge) # - 1 = lakes (weirFormula) # - 0 = non lakes or reservoirs (e.g. wetland) self.waterBodyTyp = pcr.nominal(0) if self.useNetCDF: self.waterBodyTyp = vos.netcdf2PCRobjClone(self.ncFileInp,'waterBodyTyp', \ date_used, useDoy = 'yearly',\ cloneMapFileName = self.cloneMap) else: self.waterBodyTyp = vos.readPCRmapClone( self.waterBodyTypInp+str(year_used)+".map",\ self.cloneMap,self.tmpDir,self.inputDir,False,None,True) # excluding wetlands (waterBodyTyp = 0) in all functions related to lakes/reservoirs # self.waterBodyTyp = pcr.ifthen(\ pcr.scalar(self.waterBodyTyp) > 0,\ pcr.nominal(self.waterBodyTyp)) self.waterBodyTyp = pcr.ifthen(\ pcr.scalar(self.waterBodyIds) > 0,\ pcr.nominal(self.waterBodyTyp)) self.waterBodyTyp = pcr.areamajority(self.waterBodyTyp,\ self.waterBodyIds) # choose only one type: either lake or reservoir self.waterBodyTyp = pcr.ifthen(\ pcr.scalar(self.waterBodyTyp) > 0,\ pcr.nominal(self.waterBodyTyp)) self.waterBodyTyp = pcr.ifthen(pcr.boolean(self.waterBodyIds), self.waterBodyTyp) # correcting lakes and reservoirs ids and outlets self.waterBodyIds = pcr.ifthen( pcr.scalar(self.waterBodyTyp) > 0, self.waterBodyIds) self.waterBodyOut = pcr.ifthen( pcr.scalar(self.waterBodyIds) > 0, self.waterBodyOut) # reservoir maximum capacity (m3): self.resMaxCap = pcr.scalar(0.0) self.waterBodyCap = pcr.scalar(0.0) if self.useNetCDF: self.resMaxCap = 1000. * 1000. * \ vos.netcdf2PCRobjClone(self.ncFileInp,'resMaxCapInp', \ date_used, useDoy = 'yearly',\ cloneMapFileName = self.cloneMap) else: self.resMaxCap = 1000. * 1000. * vos.readPCRmapClone(\ self.resMaxCapInp+str(year_used)+".map", \ self.cloneMap,self.tmpDir,self.inputDir) self.resMaxCap = pcr.ifthen(self.resMaxCap > 0,\ self.resMaxCap) self.resMaxCap = pcr.areaaverage(self.resMaxCap,\ self.waterBodyIds) # water body capacity (m3): (lakes and reservoirs) self.waterBodyCap = pcr.cover( self.resMaxCap, 0.0) # Note: Most of lakes have capacities > 0. self.waterBodyCap = pcr.ifthen(pcr.boolean(self.waterBodyIds), self.waterBodyCap) # correcting water body types: # Reservoirs that have zero capacities will be assumed as lakes. self.waterBodyTyp = \ pcr.ifthen(pcr.scalar(self.waterBodyTyp) > 0.,\ self.waterBodyTyp) self.waterBodyTyp = pcr.ifthenelse(self.waterBodyCap > 0.,\ self.waterBodyTyp,\ pcr.ifthenelse(pcr.scalar(self.waterBodyTyp) == 2,\ pcr.nominal(1),\ self.waterBodyTyp)) # final corrections: self.waterBodyTyp = pcr.ifthen(self.waterBodyArea > 0.,\ self.waterBodyTyp) # make sure that all lakes and/or reservoirs have surface areas self.waterBodyTyp = \ pcr.ifthen(pcr.scalar(self.waterBodyTyp) > 0.,\ self.waterBodyTyp) # make sure that only types 1 and 2 will be considered in lake/reservoir functions self.waterBodyIds = pcr.ifthen(pcr.scalar(self.waterBodyTyp) > 0.,\ self.waterBodyIds) # make sure that all lakes and/or reservoirs have ids self.waterBodyOut = pcr.ifthen(pcr.scalar(self.waterBodyIds) > 0.,\ self.waterBodyOut) # make sure that all lakes and/or reservoirs have outlets # for a natural run (self.onlyNaturalWaterBodies == True) # which uses only the year 1900, assume all reservoirs are lakes if self.onlyNaturalWaterBodies == True and date_used == self.dateForNaturalCondition: logger.info( "Using only natural water bodies identified in the year 1900. All reservoirs in 1900 are assumed as lakes." ) self.waterBodyTyp = \ pcr.ifthen(pcr.scalar(self.waterBodyTyp) > 0.,\ pcr.nominal(1)) # check that all lakes and/or reservoirs have types, ids, surface areas and outlets: test = pcr.defined(self.waterBodyTyp) & pcr.defined(self.waterBodyArea) &\ pcr.defined(self.waterBodyIds) & pcr.boolean(pcr.areamaximum(pcr.scalar(self.waterBodyOut), self.waterBodyIds)) a, b, c = vos.getMinMaxMean( pcr.cover(pcr.scalar(test), 1.0) - pcr.scalar(1.0)) threshold = 1e-3 if abs(a) > threshold or abs(b) > threshold: logger.warning( "Missing information in some lakes and/or reservoirs.") # at the beginning of simulation period (timeStepPCR = 1) # - we have to define/get the initial conditions # if initial_condition_dictionary != None and currTimeStep.timeStepPCR == 1: self.getICs(initial_condition_dictionary) # For each new reservoir (introduced at the beginning of the year) # initiating storage, average inflow and outflow # PS: THIS IS NOT NEEDED FOR OFFLINE MODFLOW RUN! # try: self.waterBodyStorage = pcr.cover(self.waterBodyStorage, 0.0) self.avgInflow = pcr.cover(self.avgInflow, 0.0) self.avgOutflow = pcr.cover(self.avgOutflow, 0.0) self.waterBodyStorage = pcr.ifthen(self.landmask, self.waterBodyStorage) self.avgInflow = pcr.ifthen(self.landmask, self.avgInflow) self.avgOutflow = pcr.ifthen(self.landmask, self.avgOutflow) except: # PS: FOR OFFLINE MODFLOW RUN! pass # TODO: Remove try and except # cropping only in the landmask region: self.fracWat = pcr.ifthen(self.landmask, self.fracWat) self.waterBodyIds = pcr.ifthen(self.landmask, self.waterBodyIds) self.waterBodyOut = pcr.ifthen(self.landmask, self.waterBodyOut) self.waterBodyArea = pcr.ifthen(self.landmask, self.waterBodyArea) self.waterBodyTyp = pcr.ifthen(self.landmask, self.waterBodyTyp) self.waterBodyCap = pcr.ifthen(self.landmask, self.waterBodyCap)
def additional_post_processing(self): # In this method/function, users can add their own post-processing. # consumption for and return flow from non irrigation water demand (unit: m/day) self.nonIrrWaterConsumption = self._model.routing.nonIrrWaterConsumption self.nonIrrReturnFlow = self._model.routing.nonIrrReturnFlow # accumulated runoff (m3/s) along the drainage network - not including local changes in water bodies if "accuRunoff" in self.variables_for_report: self.accuRunoff = pcr.catchmenttotal( self.runoff * self._model.routing.cellArea, self._model.routing.lddMap) / vos.secondsPerDay() # accumulated baseflow (m3) along the drainage network if "accuBaseflow" in self.variables_for_report: self.accuBaseflow = pcr.catchmenttotal( self.baseflow * self._model.routing.cellArea, self._model.routing.lddMap) # local changes in water bodies (i.e. abstraction, return flow, evaporation, bed exchange), excluding runoff self.local_water_body_flux = self._model.routing.local_input_to_surface_water / \ self._model.routing.cellArea - self.runoff # total runoff (m) from local land surface runoff and local changes in water bodies # actually this is equal to self._model.routing.local_input_to_surface_water / self._model.routing.cellArea self.totalRunoff = self.runoff + self.local_water_body_flux # accumulated total runoff (m3) along the drainage network - not including local changes in water bodies if "accuTotalRunoff" in self.variables_for_report: self.accuTotalRunoff = pcr.catchmenttotal( self.totalRunoff * self._model.routing.cellArea, self._model.routing.lddMap) / vos.secondsPerDay() # fossil groundwater storage self.storGroundwaterFossil = self._model.groundwater.storGroundwaterFossil # total groundwater storage: (non fossil and fossil) self.storGroundwaterTotal = self._model.groundwater.storGroundwater + \ self._model.groundwater.storGroundwaterFossil # total active storage thickness (m) for the entire water column - not including fossil groundwater (unmetDemand) # - including: interception, snow, soil and non fossil groundwater self.totalActiveStorageThickness = pcr.ifthen( self._model.routing.landmask, self._model.routing.channelStorage / self._model.routing.cellArea + self._model.landSurface.totalSto + self._model.groundwater.storGroundwater) # total water storage thickness (m) for the entire water column: # - including: interception, snow, soil, non fossil groundwater and fossil groundwater (unmetDemand) # - this is usually used for GRACE comparison self.totalWaterStorageThickness = self.totalActiveStorageThickness + \ self._model.groundwater.storGroundwaterFossil # surfaceWaterStorage (unit: m) - negative values may be reported self.surfaceWaterStorage = self._model.routing.channelStorage / \ self._model.routing.cellArea # Menno's post proccessing: fractions of water sources (allocated for) satisfying water demand in each cell self.fracSurfaceWaterAllocation = pcr.ifthen( self._model.routing.landmask, vos.getValDivZero( self._model.landSurface.allocSurfaceWaterAbstract, self.totalGrossDemand, vos.smallNumber)) self.fracSurfaceWaterAllocation = pcr.ifthenelse( self.totalGrossDemand < vos.smallNumber, 1.0, self.fracSurfaceWaterAllocation) # self.fracNonFossilGroundwaterAllocation = pcr.ifthen( self._model.routing.landmask, vos.getValDivZero( self._model.groundwater.allocNonFossilGroundwater, self.totalGrossDemand, vos.smallNumber)) self.fracNonFossilGroundwaterAllocation = pcr.ifthenelse( self.totalGrossDemand < vos.smallNumber, 0.0, self.fracNonFossilGroundwaterAllocation) # self.fracOtherWaterSourceAllocation = pcr.ifthen( self._model.routing.landmask, vos.getValDivZero(self._model.groundwater.unmetDemand, self.totalGrossDemand, vos.smallNumber)) self.totalFracWaterSourceAllocation = self.fracSurfaceWaterAllocation + \ self.fracNonFossilGroundwaterAllocation + \ self.fracOtherWaterSourceAllocation # Stefanie's post processing: reporting lake and reservoir storage (unit: m3) self.waterBodyStorage = pcr.ifthen( self._model.routing.landmask, pcr.ifthen( pcr.scalar(self._model.routing.WaterBodies.waterBodyIds) > 0., self._model.routing.WaterBodies.waterBodyStorage) ) # Note: This value is after lake/reservoir outflow. # # snowMelt (m/day) self.snowMelt = self._model.landSurface.snowMelt # soil moisture state from (approximately) the first 5 cm soil if self._model.landSurface.numberOfSoilLayers == 3: self.storUppSurface = self._model.landSurface.storUpp000005 # unit: m self.satDegUppSurface = self._model.landSurface.satDegUpp000005 # unit: percentage # reporting water balance from the land surface part (excluding surface water bodies) self.land_surface_water_balance = self._model.waterBalance # evaporation from irrigation areas (m/day) - values are average over the entire cell area if self._model.landSurface.includeIrrigation: self.evaporation_from_irrigation = self._model.landSurface.landCoverObj['irrPaddy'].actualET * \ self._model.landSurface.landCoverObj['irrPaddy'].fracVegCover + \ self._model.landSurface.landCoverObj['irrNonPaddy'].actualET * \ self._model.landSurface.landCoverObj['irrNonPaddy'].fracVegCover
def dynamic(self): ##################### # * dynamic section # ##################### #-evaluation of the current date: return current month and the time step used #-reading in fluxes over land and water area for current time step [m/d] # and read in reservoir demand and surface water extraction [m3] try: self.landSurfaceQ = clippedRead.get( pcrm.generateNameT(landSurfaceQFileName, self.currentTimeStep())) except: pass try: self.potWaterSurfaceQ = clippedRead.get( pcrm.generateNameT(waterSurfaceQFileName, self.currentTimeStep())) except: pass #-surface water extraction and reservoir demand currently set to zero, should # be computed automatically and updated to reservoirs self.potSurfaceWaterExtraction = pcr.spatial(pcr.scalar(0.)) #self.waterBodies.demand= #self.reservoirDemandTSS.assignID(self.waterBodies.ID,self.currentTimeStep(),0.)*self.timeSec #-initialization of cumulative values of actual water extractions self.actWaterSurfaceQ = pcr.spatial(pcr.scalar(0.)) self.actSurfaceWaterExtraction = pcr.spatial(pcr.scalar(0.)) #-definition of sub-loop for routing scheme - explicit scheme has to satisfy Courant condition timeLimit= pcr.cellvalue(pcr.mapminimum((pcr.cover(pcr.ifthen(self.waterBodies.distribution == 0,\ self.channelLength/self.flowVelocity),\ self.timeSec/self.nrIterDefault)*self.timeSec/self.nrIterDefault)**0.5),1)[0] nrIter = int(self.timeSec / timeLimit) nrIter = min(nrIter, int(self.timeSec / 300.)) while float(self.timeSec / nrIter) % 1 <> 0: nrIter += 1 deltaTime = self.timeSec / nrIter #-sub-loop for current time step if self.currentDate.day == 1 or nrIter >= 24: print '\n*\tprocessing %s, currently using %d substeps of %d seconds\n' % \ (self.currentDate.date(),nrIter,deltaTime) #-update discharge and storage for nrICur in range(nrIter): #-initializing discharge for the current sub-timestep and fill in values # for channels and at outlets of waterbodies # * channels * estQ= pcr.ifthenelse((self.actualStorage > 0.) & (self.waterBodies.distribution == 0) ,\ (self.wettedArea/self.alphaQ)**(1./self.betaQ),0.) #estQ= pcr.ifthenelse((self.actualStorage > 0.) & (self.waterBodies.distribution == 0) ,\ #0.5*(self.Q+(self.wettedArea/self.alphaQ)**(1./self.betaQ)),0.) #estQ= pcr.min(estQ,self.actualStorage/deltaTime) self.report(estQ, 'results/qest') self.Q = pcr.spatial(pcr.scalar(0.)) self.Q= pcr.ifthenelse(self.waterBodies.distribution == 0,\ pcr.kinematic(self.channelLDD,estQ,0.,self.alphaQ,\ self.betaQ,1,deltaTime,self.channelLength),self.Q) # * water bodies * self.waterBodies.dischargeUpdate() self.Q = self.waterBodies.returnMapValue(self.Q, self.waterBodies.actualQ) #-fluxes and resulting change in storage: first the local fluxes are evaluated # and aggregated over the water bodies where applicable; this includes the specific runoff [m/day/m2] # from input and the estimated extraction from surface water as volume per day [m3/day]; # specific runoff from the land surface is always positive whereas the fluxes over the water surface # are potential, including discharge, and are adjusted to match the availabe storage; to this end, # surface water storage and fluxes over water bodies are totalized and assigned to the outlet; # discharge is updated in a separate step, after vertical fluxes are compared to the actual storage deltaActualStorage= ((self.landFraction*self.landSurfaceQ+\ self.waterFraction*self.potWaterSurfaceQ)*self.cellArea-\ self.potSurfaceWaterExtraction)*float(self.duration)/nrIter deltaActualStorage= pcr.ifthenelse(self.waterBodies.distribution != 0,\ pcr.ifthenelse(self.waterBodies.location != 0,\ pcr.areatotal(deltaActualStorage,self.waterBodies.distribution),0),\ deltaActualStorage) adjustmentRatio= pcr.ifthenelse(deltaActualStorage < 0.,\ pcr.min(1.,-self.actualStorage/deltaActualStorage),1.) self.actWaterSurfaceQ += adjustmentRatio * self.potWaterSurfaceQ self.actSurfaceWaterExtraction += adjustmentRatio * self.actSurfaceWaterExtraction deltaActualStorage *= adjustmentRatio #-local water balance check if testLocalWaterBalance: differenceActualStorage = self.actualStorage differenceActualStorage += deltaActualStorage #-overall water balance check: net input self.cumulativeDeltaStorage += pcr.catchmenttotal( deltaActualStorage, self.LDD) #-update storage first with local changes, then balance discharge with storage and update storage # with lateral flow and return value to water bodies self.actualStorage += deltaActualStorage self.actualStorage = pcr.max(0., self.actualStorage) self.Q = pcr.min(self.Q, self.actualStorage / deltaTime) deltaActualStorage = (-self.Q + pcr.upstream(self.LDD, self.Q)) * deltaTime deltaActualStorage= pcr.ifthenelse(self.waterBodies.distribution != 0,\ pcr.ifthenelse(self.waterBodies.location != 0,\ pcr.areatotal(deltaActualStorage,self.waterBodies.distribution),0),\ deltaActualStorage) self.actualStorage += deltaActualStorage self.actualStorage = pcr.max(0., self.actualStorage) self.waterBodies.actualStorage = self.waterBodies.retrieveMapValue( self.actualStorage) #-flooded fraction returned floodedFraction,floodedDepth,\ self.wettedArea,self.alphaQ= self.kinAlphaComposite(self.actualStorage,self.floodplainMask) self.wettedArea= self.waterBodies.returnMapValue(self.wettedArea,\ self.waterBodies.channelWidth+2.*self.waterBodies.updateWaterHeight()) self.waterFraction= pcr.ifthenelse(self.waterBodies.distribution == 0,\ pcr.max(self.waterFractionMask,floodedFraction),self.waterFractionMask) self.landFraction = pcr.max(0., 1. - self.waterFraction) self.flowVelocity = pcr.ifthenelse(self.wettedArea > 0, self.Q / self.wettedArea, 0.) #-local water balance check if testLocalWaterBalance: differenceActualStorage += deltaActualStorage differenceActualStorage -= self.actualStorage totalDifference = pcr.cellvalue( pcr.maptotal(differenceActualStorage), 1)[0] minimumDifference = pcr.cellvalue( pcr.mapminimum(differenceActualStorage), 1)[0] maximumDifference = pcr.cellvalue( pcr.mapmaximum(differenceActualStorage), 1)[0] if abs(totalDifference) > 1.e-3: print 'water balance error: total %e; min %e; max %e' %\ (totalDifference,minimumDifference,maximumDifference) if reportLocalWaterBalance: pcr.report(differenceActualStorage, 'mbe_%s.map' % self.currentDate.date()) #-overall water balance check: updating cumulative discharge and total storage [m3] self.totalDischarge += self.Q * deltaTime self.totalStorage = pcr.catchmenttotal(self.actualStorage, self.LDD) #-check on occurrence of last day and report mass balance if self.currentDate == self.endDate: #-report initial maps pcr.report(self.Q, self.QIniMap) pcr.report(self.actualStorage, self.actualStorageIniMap) #-return relative and absolute water balance error per cell and # as total at basin outlets self.totalDischarge= pcr.ifthen((self.waterBodies.distribution == 0) | \ (self.waterBodies.location != 0),self.totalDischarge) self.cumulativeDeltaStorage= pcr.ifthen((self.waterBodies.distribution == 0) | \ (self.waterBodies.location != 0),self.cumulativeDeltaStorage) massBalanceError= self.totalStorage+self.totalDischarge-\ self.cumulativeDeltaStorage relMassBalanceError = 1. + pcr.ifthenelse( self.cumulativeDeltaStorage <> 0., massBalanceError / self.cumulativeDeltaStorage, 0.) totalMassBalanceError= pcr.cellvalue(pcr.maptotal(pcr.ifthen(self.basinOutlet,\ massBalanceError)),1)[0] totalCumulativeDeltaStorage= pcr.cellvalue(pcr.maptotal(pcr.ifthen(self.basinOutlet,\ self.cumulativeDeltaStorage)),1)[0] if totalCumulativeDeltaStorage > 0: totalRelativeMassBalanceError = 1. + totalMassBalanceError / totalCumulativeDeltaStorage else: totalRelativeMassBalanceError = 1. #-report maps and echo value pcr.report(massBalanceError, mbeFileName) pcr.report(relMassBalanceError, mbrFileName) print '\n*\ttotal global mass balance error [m3]: %8.3g' % totalMassBalanceError print '\n*\trelative global mass balance error [-]: %5.3f' % totalRelativeMassBalanceError #-echo to screen: total mass balance error and completion of run print '\trun completed' #-end of day: return states and fluxes #-get surface water attributes? if getSurfaceWaterAttributes: #-compute the following secondary variables: # surface water area [m2]: area given dynamic surface water fraction # residence time [days]: volume over discharge, assigned -1 in case discharge is zero # surface water depth [m], weighed by channel and floodplain volume surfaceWaterArea = self.waterFraction * self.cellArea surfaceWaterArea= pcr.ifthenelse(self.waterBodies.distribution != 0,\ pcr.ifthenelse(self.waterBodies.location != 0,\ pcr.areatotal(surfaceWaterArea,self.waterBodies.distribution),0),\ surfaceWaterArea) surfaceWaterResidenceTime = pcr.ifthenelse( self.Q > 0., self.actualStorage / (self.Q * self.timeSec), -1) surfaceWaterDepth= pcr.ifthenelse(self.actualStorage > 0.,\ pcr.max(0.,self.actualStorage-self.channelStorageCapacity)**2/\ (self.actualStorage*surfaceWaterArea),0.) surfaceWaterDepth+= pcr.ifthenelse(self.actualStorage > 0.,\ pcr.min(self.channelStorageCapacity,self.actualStorage)**2/(self.waterFractionMask*\ self.cellArea*self.actualStorage),0.) #-reports: values at outlet of lakes or reservoirs are assigned to their full extent self.report(pcr.ifthenelse(self.waterBodies.distribution != 0,\ pcr.areamaximum(surfaceWaterArea,self.waterBodies.distribution),surfaceWaterArea),\ surfaceWaterAreaFileName) self.report(pcr.ifthenelse(self.waterBodies.distribution != 0,\ pcr.areamaximum(surfaceWaterResidenceTime,self.waterBodies.distribution),surfaceWaterResidenceTime),\ surfaceWaterResidenceTimeFileName) self.report(pcr.ifthenelse(self.waterBodies.distribution != 0,\ pcr.areamaximum(surfaceWaterDepth,self.waterBodies.distribution),surfaceWaterDepth),\ surfaceWaterDepthFileName) #-reports on standard output: values at outlet of lakes or reservoirs are assigned to their full extent self.report( pcr.ifthenelse( self.waterBodies.distribution != 0, pcr.areamaximum(self.flowVelocity, self.waterBodies.distribution), self.flowVelocity), flowVelocityFileName) self.report( pcr.ifthenelse( self.waterBodies.distribution != 0, pcr.areamaximum(self.Q, self.waterBodies.distribution), self.Q), QFileName) self.report(pcr.ifthenelse(self.waterBodies.distribution == 0,\ floodedFraction,0.),floodedFractionFileName) self.report(pcr.ifthenelse(self.waterBodies.distribution == 0,\ floodedDepth,0.),floodedDepthFileName) self.report(self.actualStorage, actualStorageFileName) #-update date for time step and report relevant daily output self.currentDate = self.currentDate + datetime.timedelta(self.duration)
def subcatch_order_b( ldd, oorder, sizelimit=0, fill=False, fillcomplete=False, stoporder=0 ): """ Determines subcatchments using the catchment order This version tries to keep the number op upstream/downstream catchment the small by first dederivingatchment connected to the major river(the order) given, and fill up from there. Input: - ldd - oorder - order to use - sizelimit - smallest catchments to include, default is all (sizelimit=0) in number of cells - if fill is set to True the higer order catchment are filled also - if fillcomplete is set to True the whole ldd is filled with catchments. :returns sc, dif, nldd; Subcatchment, Points, subcatchldd """ # outl = find_outlet(ldd) # large = pcr.subcatchment(ldd,pcr.boolean(outl)) if stoporder == 0: stoporder = oorder stt = pcr.streamorder(ldd) sttd = pcr.downstream(ldd, stt) pts = pcr.ifthen((pcr.scalar(sttd) - pcr.scalar(stt)) > 0.0, sttd) maxorder = pcraster.framework.getCellValue(pcr.mapmaximum(stt), 1, 1) dif = pcr.uniqueid(pcr.boolean(pcr.ifthen(stt == pcr.ordinal(oorder), pts))) if fill: for order in range(oorder, maxorder): m_pts = pcr.ifthen((pcr.scalar(sttd) - pcr.scalar(order)) > 0.0, sttd) m_dif = pcr.uniqueid( pcr.boolean(pcr.ifthen(stt == pcr.ordinal(order), m_pts)) ) dif = pcr.uniqueid(pcr.boolean(pcr.cover(m_dif, dif))) for myorder in range(oorder - 1, stoporder, -1): sc = pcr.subcatchment(ldd, pcr.nominal(dif)) m_pts = pcr.ifthen((pcr.scalar(sttd) - pcr.scalar(stt)) > 0.0, sttd) m_dif = pcr.uniqueid( pcr.boolean(pcr.ifthen(stt == pcr.ordinal(myorder - 1), m_pts)) ) dif = pcr.uniqueid( pcr.boolean(pcr.cover(pcr.ifthen(pcr.scalar(sc) == 0, m_dif), dif)) ) if fillcomplete: sc = pcr.subcatchment(ldd, pcr.nominal(dif)) cs, m_dif, stt = subcatch_order_a(ldd, stoporder) dif = pcr.uniqueid( pcr.boolean( pcr.cover( pcr.ifthen(pcr.scalar(sc) == 0, pcr.ordinal(m_dif)), pcr.ordinal(dif), ) ) ) scsize = pcr.catchmenttotal(1, ldd) dif = pcr.ordinal(pcr.uniqueid(pcr.boolean(pcr.ifthen(scsize >= sizelimit, dif)))) sc = pcr.subcatchment(ldd, dif) # Make pit ldd nldd = pcr.lddrepair(pcr.ifthenelse(pcr.cover(dif, 0) > 0, 5, ldd)) return sc, dif, nldd
def getParameterFiles(self, date_given, cellArea, ldd): # parameters for Water Bodies: fracWat # waterBodyIds # waterBodyOut # waterBodyArea # waterBodyTyp # waterBodyCap # cell surface area (m2) and ldd self.cellArea = cellArea ldd = pcr.ifthen(self.landmask, ldd) # date and year used for accessing/extracting water body information date_used = date_given if self.onlyNaturalWaterBodies == True: date_used = self.dateForNaturalCondition year_used = date_used[0:4] # fracWat = fraction of surface water bodies (dimensionless) self.fracWat = pcr.scalar(0.0) if self.useNetCDF: self.fracWat = vos.netcdf2PCRobjClone(self.ncFileInp,'fracWaterInp', \ date_used, useDoy = 'yearly',\ cloneMapFileName = self.cloneMap) self.fracWat = pcr.cover(self.fracWat, 0.0) self.fracWat = pcr.max(0.0, self.fracWat) self.fracWat = pcr.min(1.0, self.fracWat) self.waterBodyIds = pcr.nominal(0) # waterBody ids self.waterBodyOut = pcr.boolean(0) # waterBody outlets self.waterBodyArea = pcr.scalar(0.) # waterBody surface areas # water body ids if self.useNetCDF: self.waterBodyIds = vos.netcdf2PCRobjClone(self.ncFileInp,'waterBodyIds', \ date_used, useDoy = 'yearly',\ cloneMapFileName = self.cloneMap) self.waterBodyIds = pcr.ifthen(\ pcr.scalar(self.waterBodyIds) > 0.,\ pcr.nominal(self.waterBodyIds)) # water body outlets (correcting outlet positions) wbCatchment = pcr.catchmenttotal(pcr.scalar(1), ldd) self.waterBodyOut = pcr.ifthen(wbCatchment ==\ pcr.areamaximum(wbCatchment, \ self.waterBodyIds),\ self.waterBodyIds) # = outlet ids self.waterBodyOut = pcr.ifthen(\ pcr.scalar(self.waterBodyIds) > 0.,\ self.waterBodyOut) # TODO: Please also consider endorheic lakes! # correcting water body ids self.waterBodyIds = pcr.ifthen(\ pcr.scalar(self.waterBodyIds) > 0.,\ pcr.subcatchment(ldd,self.waterBodyOut)) # boolean map for water body outlets: self.waterBodyOut = pcr.ifthen(\ pcr.scalar(self.waterBodyOut) > 0.,\ pcr.boolean(1)) # reservoir surface area (m2): if self.useNetCDF: resSfArea = 1000. * 1000. * \ vos.netcdf2PCRobjClone(self.ncFileInp,'resSfAreaInp', \ date_used, useDoy = 'yearly',\ cloneMapFileName = self.cloneMap) resSfArea = pcr.areaaverage(resSfArea, self.waterBodyIds) resSfArea = pcr.cover(resSfArea, 0.) # water body surface area (m2): (lakes and reservoirs) self.waterBodyArea = pcr.max(pcr.areatotal(\ pcr.cover(\ self.fracWat*self.cellArea, 0.0), self.waterBodyIds), pcr.areaaverage(\ pcr.cover(resSfArea, 0.0) , self.waterBodyIds)) self.waterBodyArea = pcr.ifthen(self.waterBodyArea > 0.,\ self.waterBodyArea) # correcting water body ids and outlets (exclude all water bodies with surfaceArea = 0) self.waterBodyIds = pcr.ifthen(self.waterBodyArea > 0., self.waterBodyIds) self.waterBodyOut = pcr.ifthen(pcr.boolean(self.waterBodyIds), self.waterBodyOut) # water body types: # - 2 = reservoirs (regulated discharge) # - 1 = lakes (weirFormula) # - 0 = non lakes or reservoirs (e.g. wetland) self.waterBodyTyp = pcr.nominal(0) if self.useNetCDF: self.waterBodyTyp = vos.netcdf2PCRobjClone(self.ncFileInp,'waterBodyTyp', \ date_used, useDoy = 'yearly',\ cloneMapFileName = self.cloneMap) # excluding wetlands (waterBodyTyp = 0) in all functions related to lakes/reservoirs # self.waterBodyTyp = pcr.ifthen(\ pcr.scalar(self.waterBodyTyp) > 0,\ pcr.nominal(self.waterBodyTyp)) self.waterBodyTyp = pcr.ifthen(\ pcr.scalar(self.waterBodyIds) > 0,\ pcr.nominal(self.waterBodyTyp)) self.waterBodyTyp = pcr.areamajority(self.waterBodyTyp,\ self.waterBodyIds) # choose only one type: either lake or reservoir self.waterBodyTyp = pcr.ifthen(\ pcr.scalar(self.waterBodyTyp) > 0,\ pcr.nominal(self.waterBodyTyp)) self.waterBodyTyp = pcr.ifthen(pcr.boolean(self.waterBodyIds), self.waterBodyTyp) # correcting lakes and reservoirs ids and outlets self.waterBodyIds = pcr.ifthen( pcr.scalar(self.waterBodyTyp) > 0, self.waterBodyIds) self.waterBodyOut = pcr.ifthen( pcr.scalar(self.waterBodyIds) > 0, self.waterBodyOut) # reservoir maximum capacity (m3): self.resMaxCap = pcr.scalar(0.0) self.waterBodyCap = pcr.scalar(0.0) if self.useNetCDF: self.resMaxCap = 1000. * 1000. * \ vos.netcdf2PCRobjClone(self.ncFileInp,'resMaxCapInp', \ date_used, useDoy = 'yearly',\ cloneMapFileName = self.cloneMap) self.resMaxCap = pcr.ifthen(self.resMaxCap > 0,\ self.resMaxCap) self.resMaxCap = pcr.areaaverage(self.resMaxCap,\ self.waterBodyIds) # water body capacity (m3): (lakes and reservoirs) self.waterBodyCap = pcr.cover( self.resMaxCap, 0.0) # Note: Most of lakes have capacities > 0. self.waterBodyCap = pcr.ifthen(pcr.boolean(self.waterBodyIds), self.waterBodyCap) # correcting water body types: # Reservoirs that have zero capacities will be assumed as lakes. self.waterBodyTyp = \ pcr.ifthen(pcr.scalar(self.waterBodyTyp) > 0.,\ self.waterBodyTyp) self.waterBodyTyp = pcr.ifthenelse(self.waterBodyCap > 0.,\ self.waterBodyTyp,\ pcr.ifthenelse(pcr.scalar(self.waterBodyTyp) == 2,\ pcr.nominal(1),\ self.waterBodyTyp)) # final corrections: self.waterBodyTyp = pcr.ifthen(self.waterBodyArea > 0.,\ self.waterBodyTyp) # make sure that all lakes and/or reservoirs have surface areas self.waterBodyTyp = \ pcr.ifthen(pcr.scalar(self.waterBodyTyp) > 0.,\ self.waterBodyTyp) # make sure that only types 1 and 2 will be considered in lake/reservoir functions self.waterBodyIds = pcr.ifthen(pcr.scalar(self.waterBodyTyp) > 0.,\ self.waterBodyIds) # make sure that all lakes and/or reservoirs have ids self.waterBodyOut = pcr.ifthen(pcr.scalar(self.waterBodyIds) > 0.,\ self.waterBodyOut) # make sure that all lakes and/or reservoirs have outlets # for a natural run (self.onlyNaturalWaterBodies == True) # which uses only the year 1900, assume all reservoirs are lakes if self.onlyNaturalWaterBodies == True and date_used == self.dateForNaturalCondition: logger.info( "Using only natural water bodies identified in the year 1900. All reservoirs in 1900 are assumed as lakes." ) self.waterBodyTyp = \ pcr.ifthen(pcr.scalar(self.waterBodyTyp) > 0.,\ pcr.nominal(1)) # check that all lakes and/or reservoirs have types, ids, surface areas and outlets: test = pcr.defined(self.waterBodyTyp) & pcr.defined(self.waterBodyArea) &\ pcr.defined(self.waterBodyIds) & pcr.boolean(pcr.areamaximum(pcr.scalar(self.waterBodyOut), self.waterBodyIds)) a, b, c = vos.getMinMaxMean( pcr.cover(pcr.scalar(test), 1.0) - pcr.scalar(1.0)) threshold = 1e-3 if abs(a) > threshold or abs(b) > threshold: logger.warning( "Missing information in some lakes and/or reservoirs.") # cropping only in the landmask region: self.fracWat = pcr.ifthen(self.landmask, self.fracWat) self.waterBodyIds = pcr.ifthen(self.landmask, self.waterBodyIds) self.waterBodyOut = pcr.ifthen(self.landmask, self.waterBodyOut) self.waterBodyArea = pcr.ifthen(self.landmask, self.waterBodyArea) self.waterBodyTyp = pcr.ifthen(self.landmask, self.waterBodyTyp) self.waterBodyCap = pcr.ifthen(self.landmask, self.waterBodyCap)
def evaluateAllModelResults(self,globalCloneMapFileName,\ catchmentClassFileName,\ lddMapFileName,\ cellAreaMapFileName,\ pcrglobwb_output,\ analysisOutputDir="",\ tmpDir = "/dev/shm/edwin_grdc_"): # output directory for all analyses for all stations analysisOutputDir = str(analysisOutputDir) self.chartOutputDir = analysisOutputDir+"/chart/" self.tableOutputDir = analysisOutputDir+"/table/" # if analysisOutputDir == "": self.chartOutputDir = "chart/" if analysisOutputDir == "": self.tableOutputDir = "table/" # # make the chart and table directories: os.system('rm -r '+self.chartOutputDir+"*") os.system('rm -r '+self.tableOutputDir+"*") os.makedirs(self.chartOutputDir) os.makedirs(self.tableOutputDir) # cloneMap for all pcraster operations pcr.setclone(globalCloneMapFileName) cloneMap = pcr.boolean(1) self.cell_size_in_arc_degree = vos.getMapAttributesALL(globalCloneMapFileName)['cellsize'] lddMap = pcr.lddrepair(pcr.readmap(lddMapFileName)) cellArea = pcr.scalar(pcr.readmap(cellAreaMapFileName)) # The landMaskClass map contains the nominal classes for all landmask regions. landMaskClass = pcr.nominal(cloneMap) # default: if catchmentClassFileName is not given if catchmentClassFileName != None: landMaskClass = pcr.nominal(pcr.readmap(catchmentClassFileName)) # model catchment areas and cordinates catchmentAreaAll = pcr.catchmenttotal(cellArea, lddMap) / (1000*1000) # unit: km2 xCoordinate = pcr.xcoordinate(cloneMap) yCoordinate = pcr.ycoordinate(cloneMap) print "Jaaaaaa" for id in self.list_of_grdc_ids: logger.info("Evaluating simulated discharge to the grdc observation at "+str(self.attributeGRDC["id_from_grdc"][str(id)])+".") # identify model pixel self.identifyModelPixel(tmpDir,catchmentAreaAll,landMaskClass,xCoordinate,yCoordinate,str(id)) # evaluate model results to GRDC data self.evaluateModelResultsToGRDC(str(id),pcrglobwb_output,catchmentClassFileName,tmpDir) # write the summary to a table summary_file = analysisOutputDir+"summary.txt" # logger.info("Writing the summary for all stations to the file: "+str(summary_file)+".") # # prepare the file: summary_file_handle = open(summary_file,"w") # # write the header summary_file_handle.write( ";".join(self.grdc_dict_keys)+"\n") # # write the content for id in self.list_of_grdc_ids: rowLine = "" for key in self.grdc_dict_keys: rowLine += str(self.attributeGRDC[key][str(id)]) + ";" rowLine = rowLine[0:-1] + "\n" summary_file_handle.write(rowLine) summary_file_handle.close()
def main(): #-initialization # MVs MV= -999. # minimum catchment size to process catchmentSizeLimit= 0.0 # period of interest, start and end year startYear= 1961 endYear= 2010 # maps cloneMapFileName= '/data/hydroworld/PCRGLOBWB20/input30min/global/Global_CloneMap_30min.map' lddFileName= '/data/hydroworld/PCRGLOBWB20/input30min/routing/lddsound_30min.map' cellAreaFileName= '/data/hydroworld/PCRGLOBWB20/input30min/routing/cellarea30min.map' # set clone pcr.setclone(cloneMapFileName) # output outputPath= '/scratch/rens/reservedrecharge' percentileMapFileName= os.path.join(outputPath,'q%03d_cumsec.map') textFileName= os.path.join(outputPath,'groundwater_environmentalflow_%d.txt') fractionReservedRechargeMapFileName= os.path.join(outputPath,'fraction_reserved_recharge%d.map') fractionMinimumReservedRechargeMapFileName= os.path.join(outputPath,'minimum_fraction_reserved_recharge%d.map') # input inputPath= '/nfsarchive/edwin-emergency-backup-DO-NOT-DELETE/rapid/edwin/05min_runs_results/2015_04_27/non_natural_2015_04_27/global/netcdf/' # define data to be read from netCDF files ncData= {} variableName= 'totalRunoff' ncData[variableName]= {} ncData[variableName]['fileName']= os.path.join(inputPath,'totalRunoff_monthTot_output.nc') ncData[variableName]['fileRoot']= os.path.join(outputPath,'qloc') ncData[variableName]['annualAverage']= pcr.scalar(0) variableName= 'gwRecharge' ncData[variableName]= {} ncData[variableName]['fileName']= os.path.join(inputPath,'gwRecharge_monthTot_output.nc') ncData[variableName]['fileRoot']= os.path.join(outputPath,'gwrec') ncData[variableName]['annualAverage']= pcr.scalar(0) variableName= 'discharge' ncData[variableName]= {} ncData[variableName]['fileName']= os.path.join(inputPath,'totalRunoff_monthTot_output.nc') ncData[variableName]['fileRoot']= os.path.join(outputPath,'qc') ncData[variableName]['annualAverage']= pcr.scalar(0) ncData[variableName]['mapStack']= np.array([]) # percents and environmental flow condition set as percentile percents= range(10,110,10) environmentalFlowPercent= 10 if environmentalFlowPercent not in percents: percents.append(environmentalFlowPercent) percents.sort() #-start # obtain attributes pcr.setclone(cloneMapFileName) cloneSpatialAttributes= spatialAttributes(cloneMapFileName) years= range(startYear,endYear+1) # output path if not os.path.isdir(outputPath): os.makedirs(outputPath) os.chdir(outputPath) # compute catchments ldd= pcr.readmap(lddFileName) cellArea= pcr.readmap(cellAreaFileName) catchments= pcr.catchment(ldd,pcr.pit(ldd)) fractionWater= pcr.scalar(0.0) # temporary! lakeMask= pcr.boolean(0) # temporary! pcr.report(catchments,os.path.join(outputPath,'catchments.map')) maximumCatchmentID= int(pcr.cellvalue(pcr.mapmaximum(pcr.scalar(catchments)),1)[0]) # iterate over years weight= float(len(years))**-1 for year in years: #-echo year print ' - processing year %d' % year #-process data startDate= datetime.datetime(year,1,1) endDate= datetime.datetime(year,12,31) timeSteps= endDate.toordinal()-startDate.toordinal()+1 dynamicIncrement= 1 for variableName in ncData.keys(): print ' extracting %s' % variableName, ncFileIn= ncData[variableName]['fileName'] #-process data pcrDataSet= pcrObject(variableName, ncData[variableName]['fileRoot'],\ ncFileIn,cloneSpatialAttributes, pcrVALUESCALE= pcr.Scalar, resamplingAllowed= True,\ dynamic= True, dynamicStart= startDate, dynamicEnd= endDate, dynamicIncrement= dynamicIncrement, ncDynamicDimension= 'time') pcrDataSet.initializeFileInfo() pcrDataSet.processFileInfo() for fileInfo in pcrDataSet.fileProcessInfo.values()[0]: tempFileName= fileInfo[1] variableField= pcr.readmap(tempFileName) variableField= pcr.ifthen(pcr.defined(ldd),pcr.cover(variableField,0)) if variableName == 'discharge': dayNumber= int(os.path.splitext(tempFileName)[1].strip('.')) date= datetime.date(year,1,1)+datetime.timedelta(dayNumber-1) numberDays= calendar.monthrange(year,date.month)[1] variableField= pcr.max(0,pcr.catchmenttotal(variableField*cellArea,ldd)/(numberDays*24*3600)) ncData[variableName]['annualAverage']+= weight*variableField if 'mapStack' in ncData[variableName].keys(): tempArray= pcr2numpy(variableField,MV) mask= tempArray != MV if ncData[variableName]['mapStack'].size != 0: ncData[variableName]['mapStack']= np.vstack((ncData[variableName]['mapStack'],tempArray[mask])) else: ncData[variableName]['mapStack']= tempArray[mask] coordinates= np.zeros((ncData[variableName]['mapStack'].size,2)) pcr.setglobaloption('unitcell') tempArray= pcr2numpy(pcr.ycoordinate(pcr.boolean(1))+0.5,MV) coordinates[:,0]= tempArray[mask] tempArray= pcr2numpy(pcr.xcoordinate(pcr.boolean(1))+0.5,MV) coordinates[:,1]= tempArray[mask] os.remove(tempFileName) # delete object pcrDataSet= None del pcrDataSet # close line on screen print # report annual averages key= 'annualAverage' ncData['discharge'][key]/= 12 for variableName in ncData.keys(): ncData[variableName][key]= pcr.max(0,ncData[variableName][key]) pcr.report(ncData[variableName][key],\ os.path.join(outputPath,'%s_%s.map' % (variableName,key))) # remove aux.xml for tempFileName in os.listdir(outputPath): if 'aux.xml' in tempFileName: os.remove(tempFileName) # sort data print 'sorting discharge data' variableName= 'discharge' key= 'mapStack' indices= np.zeros((ncData[variableName][key].shape),np.uint) for iCnt in xrange(ncData[variableName][key].shape[1]): indices[:,iCnt]= ncData[variableName][key][:,iCnt].argsort(kind= 'mergesort') ncData[variableName][key][:,iCnt]= ncData[variableName][key][:,iCnt][indices[:,iCnt]] # extract values for percentiles print 'returning maps' for percent in percents: percentile= 0.01*percent index0= min(ncData[variableName][key].shape[0]-1,int(percentile*ncData[variableName][key].shape[0])) index1= min(ncData[variableName][key].shape[0]-1,int(percentile*ncData[variableName][key].shape[0])+1) x0= float(index0)/ncData[variableName][key].shape[0] x1= float(index1)/ncData[variableName][key].shape[0] if x0 <> x1: y= ncData[variableName][key][index0,:]+(percentile-x0)*\ (ncData[variableName][key][index1,:]-ncData[variableName][key][index0,:])/(x1-x0) else: y= ncData[variableName][key][index0,:] # convert a slice of the stack into an array tempArray= np.ones((cloneSpatialAttributes.numberRows,cloneSpatialAttributes.numberCols))*MV for iCnt in xrange(coordinates.shape[0]): row= coordinates[iCnt,0]-1 col= coordinates[iCnt,1]-1 tempArray[row,col]= y[iCnt] variableField= numpy2pcr(pcr.Scalar,tempArray,MV) pcr.report(variableField,percentileMapFileName % percent) if percent == environmentalFlowPercent: ncData[variableName]['environmentalFlow']= variableField tempArray= None; variableField= None del tempArray, variableField # process environmental flow # initialize map of reserved recharge fraction fractionReservedRechargeMap= pcr.ifthen(ncData[variableName]['environmentalFlow'] < 0,pcr.scalar(0)) fractionMinimumReservedRechargeMap= pcr.ifthen(ncData[variableName]['environmentalFlow'] < 0,pcr.scalar(0)) textFile= open(textFileName % environmentalFlowPercent,'w') hStr= 'Environmental flow analysis per basin, resulting in a map of renewable, exploitable recharge, for the %d%s quantile of discharge\n' % (environmentalFlowPercent,'%') hStr+= 'Returns Q_%d/R, the fraction of reserved recharge needed to sustain fully the environental flow requirement defined as the %d percentile,\n' % (environmentalFlowPercent, environmentalFlowPercent) hStr+= 'and Q*_%d/R, a reduced fraction that takes the availability of surface water into account\n' % environmentalFlowPercent textFile.write(hStr) print hStr # create header to display on screen and write to file # reported are: 1: ID, 2: Area, 3: average discharge, 4: environmental flow, 5: average recharge, # 6: Q_%d/Q, 7: Q_%d/R_Avg, 8: R_Avg/Q_Avg, 9: Q*_%d/R_Avg hStr= '%6s,%15s,%15s,%15s,%15s,%15s,%15s,%15s,%15s\n' % \ ('ID','Area [km2]','Q_Avg [m3]','Q_%d [m3]' % environmentalFlowPercent ,'R_Avg [m3]','Q_%d/Q_Avg [-]' % environmentalFlowPercent,\ 'Q_%d/Q_Avg [-]' % environmentalFlowPercent,'R_Avg/Q_Avg [-]','Q*_%d/Q_Avg [-]' % environmentalFlowPercent) textFile.write(hStr) print hStr for catchment in xrange(1,maximumCatchmentID+1): # create catchment mask and check whether it does not coincide with a lake catchmentMask= catchments == catchment catchmentSize= pcr.cellvalue(pcr.maptotal(pcr.ifthen(catchmentMask,cellArea*1.e-6)),1)[0] #~ ##~ if pcr.cellvalue(pcr.maptotal(pcr.ifthen(catchmentMask,pcr.scalar(lakeMask))),1) <> \ #~ ##~ pcr.cellvalue(pcr.maptotal(pcr.ifthen(catchmentMask,pcr.scalar(catchmentMask))),1)[0] and \ #~ ##~ catchmentSize > catchmentSizeLimit: key= 'annualAverage' variableName= 'discharge' if bool(pcr.cellvalue(pcr.maptotal(pcr.ifthen((ldd == 5) & catchmentMask,\ pcr.scalar(ncData[variableName][key] > 0))),1)[0]) and catchmentSize >= catchmentSizeLimit: # valid catchment, process # all volumes are in m3 per year key= 'annualAverage' catchmentAverageDischarge= pcr.cellvalue(pcr.mapmaximum(pcr.ifthen(catchmentMask & (ldd == 5),\ ncData[variableName][key])),1)[0]*365.25*3600*24 variableName= 'gwRecharge' catchmentRecharge= pcr.cellvalue(pcr.maptotal(pcr.ifthen(catchmentMask,ncData[variableName][key]*\ (1.-fractionWater)*cellArea)),1)[0] variableName= 'totalRunoff' catchmentRunoff= pcr.cellvalue(pcr.maptotal(pcr.ifthen(catchmentMask,ncData[variableName][key]*\ cellArea)),1)[0] key= 'environmentalFlow' variableName= 'discharge' catchmentEnvironmentalFlow= pcr.cellvalue(pcr.mapmaximum(pcr.ifthen(catchmentMask & (ldd == 5),\ ncData[variableName][key])),1)[0]*365.25*3600*24 catchmentRunoff= max(catchmentRunoff,catchmentEnvironmentalFlow) if catchmentAverageDischarge > 0.: fractionEnvironmentalFlow= catchmentEnvironmentalFlow/catchmentAverageDischarge fractionGroundWaterContribution= catchmentRecharge/catchmentAverageDischarge else: fractionEnvironmentalFlow= 0. fractionGroundWaterContribution= 0. if catchmentRecharge > 0: fractionReservedRecharge= min(1,catchmentEnvironmentalFlow/catchmentRecharge) else: fractionReservedRecharge= 1.0 fractionMinimumReservedRecharge= (fractionReservedRecharge+fractionGroundWaterContribution-\ fractionReservedRecharge*fractionGroundWaterContribution)*fractionReservedRecharge #~ # echo to screen, and write to file and map wStr= '%6s,%15.1f,%15.6g,%15.6g,%15.6g,%15.6f,%15.6f,%15.6f,%15.6f\n' % \ (catchment,catchmentSize,catchmentAverageDischarge,catchmentEnvironmentalFlow,catchmentRecharge,\ fractionEnvironmentalFlow,fractionReservedRecharge,fractionGroundWaterContribution,fractionMinimumReservedRecharge) print wStr textFile.write(wStr) # update maps fractionReservedRechargeMap= pcr.ifthenelse(catchmentMask,\ pcr.scalar(fractionReservedRecharge),fractionReservedRechargeMap) fractionMinimumReservedRechargeMap= pcr.ifthenelse(catchmentMask,\ pcr.scalar(fractionMinimumReservedRecharge),fractionMinimumReservedRechargeMap) #-report map and close text file pcr.report(fractionReservedRechargeMap,fractionReservedRechargeMapFileName % environmentalFlowPercent) pcr.report(fractionMinimumReservedRechargeMap,fractionMinimumReservedRechargeMapFileName % environmentalFlowPercent) # close text file textFile.close() # finished print 'all done!'
def additional_post_processing(self): # In this method/function, users can add their own post-processing. # accumulated baseflow (m3/s) along the drainage network if "accuBaseflow" in self.variables_for_report: self.accuBaseflow = pcr.catchmenttotal( self.baseflow * self._model.routing.cellArea, self._model.routing.lddMap) / vos.secondsPerDay() # local changes in water bodies (i.e. abstraction, return flow, evaporation, bed exchange), excluding runoff self.local_water_body_flux = self._model.routing.local_input_to_surface_water / self._model.routing.cellArea - self.runoff # total runoff (m) from local land surface runoff and local changes in water bodies self.totalRunoff = self.runoff + self.local_water_body_flux # actually this is equal to self._model.routing.local_input_to_surface_water / self._model.routing.cellArea # water body evaporation (m) - from surface water fractions only self.waterBodyActEvaporation = self._model.routing.waterBodyEvaporation self.waterBodyPotEvaporation = self._model.routing.waterBodyPotEvap # self.fractionWaterBodyEvaporation = vos.getValDivZero(self.waterBodyActEvaporation,\ self.waterBodyPotEvaporation,\ vos.smallNumber) # land surface evaporation (m) self.actualET = self._model.landSurface.actualET # fossil groundwater storage self.storGroundwaterFossil = self._model.groundwater.storGroundwaterFossil # total groundwater storage: (non fossil and fossil) self.storGroundwaterTotal = self._model.groundwater.storGroundwater + \ self._model.groundwater.storGroundwaterFossil # total active storage thickness (m) for the entire water column - not including fossil groundwater # - including: interception, snow, soil and non fossil groundwater self.totalActiveStorageThickness = pcr.ifthen(\ self._model.routing.landmask, \ self._model.routing.channelStorage / self._model.routing.cellArea + \ self._model.landSurface.totalSto + \ self._model.groundwater.storGroundwater) # total water storage thickness (m) for the entire water column: # - including: interception, snow, soil, non fossil groundwater and fossil groundwater # - this is usually used for GRACE comparison self.totalWaterStorageThickness = self.totalActiveStorageThickness + \ self._model.groundwater.storGroundwaterFossil # surfaceWaterStorage (unit: m) - negative values may be reported self.surfaceWaterStorage = self._model.routing.channelStorage / self._model.routing.cellArea # Menno's post proccessing: fractions of water sources (allocated for) satisfying water demand in each cell self.fracSurfaceWaterAllocation = pcr.ifthen(self._model.routing.landmask, \ vos.getValDivZero(\ self._model.landSurface.allocSurfaceWaterAbstract, self.totalGrossDemand, vos.smallNumber)) self.fracSurfaceWaterAllocation = pcr.ifthenelse( self.totalGrossDemand < vos.smallNumber, 1.0, self.fracSurfaceWaterAllocation) # self.fracNonFossilGroundwaterAllocation = pcr.ifthen(self._model.routing.landmask, \ vos.getValDivZero(\ self._model.groundwater.allocNonFossilGroundwater, self.totalGrossDemand, vos.smallNumber)) # self.fracOtherWaterSourceAllocation = pcr.ifthen(self._model.routing.landmask, \ vos.getValDivZero(\ self._model.groundwater.unmetDemand, self.totalGrossDemand, vos.smallNumber)) # self.fracDesalinatedWaterAllocation = pcr.ifthen(self._model.routing.landmask, \ vos.getValDivZero(\ self._model.landSurface.desalinationAllocation, self.totalGrossDemand, vos.smallNumber)) # self.totalFracWaterSourceAllocation = self.fracSurfaceWaterAllocation + \ self.fracNonFossilGroundwaterAllocation + \ self.fracOtherWaterSourceAllocation + \ self.fracDesalinatedWaterAllocation # Stefanie's post processing: # - reporting lake and reservoir storage (unit: m3) self.waterBodyStorage = pcr.ifthen(self._model.routing.landmask, \ pcr.ifthen(\ pcr.scalar(self._model.routing.WaterBodies.waterBodyIds) > 0.,\ self._model.routing.WaterBodies.waterBodyStorage)) # Note: This value is after lake/reservoir outflow. # - snowMelt (m) self.snowMelt = self._model.landSurface.snowMelt # An example to report variables from certain land cover types # - evaporation from irrigation areas (m/day) - values are average over the entire cell area if self._model.landSurface.includeIrrigation: \ self.evaporation_from_irrigation = self._model.landSurface.landCoverObj['irrPaddy'].actualET * \ self._model.landSurface.landCoverObj['irrPaddy'].fracVegCover + \ self._model.landSurface.landCoverObj['irrNonPaddy'].actualET * \ self._model.landSurface.landCoverObj['irrNonPaddy'].fracVegCover # Total groundwater abstraction (m) (assuming otherWaterSourceAbstraction as fossil groundwater abstraction self.totalGroundwaterAbstraction = self.nonFossilGroundwaterAbstraction +\ self.fossilGroundwaterAbstraction # net liquid water passing to the soil self.net_liquid_water_to_soil = self._model.landSurface.netLqWaterToSoil # consumptive water use and return flow from non irrigation water demand (unit: m/day) self.nonIrrWaterConsumption = self._model.routing.nonIrrWaterConsumption self.nonIrrReturnFlow = self._model.routing.nonIrrReturnFlow # total potential water demand - not considering water availability self.totalPotentialMaximumGrossDemand = self._model.landSurface.totalPotentialMaximumGrossDemand
def dynamic(self): ##################### # * dynamic section # ##################### #-evaluation of the current date: return current month and the time step used #-reading in fluxes over land and water area for current time step [m/d] # and read in reservoir demand and surface water extraction [m3] try: self.landSurfaceQ= clippedRead.get(pcrm.generateNameT(landSurfaceQFileName,self.currentTimeStep())) except: pass try: self.potWaterSurfaceQ= clippedRead.get(pcrm.generateNameT(waterSurfaceQFileName,self.currentTimeStep())) except: pass #-surface water extraction and reservoir demand currently set to zero, should # be computed automatically and updated to reservoirs self.potSurfaceWaterExtraction= pcr.spatial(pcr.scalar(0.)) #self.waterBodies.demand= #self.reservoirDemandTSS.assignID(self.waterBodies.ID,self.currentTimeStep(),0.)*self.timeSec #-initialization of cumulative values of actual water extractions self.actWaterSurfaceQ= pcr.spatial(pcr.scalar(0.)) self.actSurfaceWaterExtraction= pcr.spatial(pcr.scalar(0.)) #-definition of sub-loop for routing scheme - explicit scheme has to satisfy Courant condition timeLimit= pcr.cellvalue(pcr.mapminimum((pcr.cover(pcr.ifthen(self.waterBodies.distribution == 0,\ self.channelLength/self.flowVelocity),\ self.timeSec/self.nrIterDefault)*self.timeSec/self.nrIterDefault)**0.5),1)[0] nrIter= int(self.timeSec/timeLimit) nrIter= min(nrIter,int(self.timeSec/300.)) while float(self.timeSec/nrIter) % 1 <> 0: nrIter+= 1 deltaTime= self.timeSec/nrIter #-sub-loop for current time step if self.currentDate.day == 1 or nrIter >= 24: print '\n*\tprocessing %s, currently using %d substeps of %d seconds\n' % \ (self.currentDate.date(),nrIter,deltaTime) #-update discharge and storage for nrICur in range(nrIter): #-initializing discharge for the current sub-timestep and fill in values # for channels and at outlets of waterbodies # * channels * estQ= pcr.ifthenelse((self.actualStorage > 0.) & (self.waterBodies.distribution == 0) ,\ (self.wettedArea/self.alphaQ)**(1./self.betaQ),0.) #estQ= pcr.ifthenelse((self.actualStorage > 0.) & (self.waterBodies.distribution == 0) ,\ #0.5*(self.Q+(self.wettedArea/self.alphaQ)**(1./self.betaQ)),0.) #estQ= pcr.min(estQ,self.actualStorage/deltaTime) self.report(estQ,'results/qest') self.Q= pcr.spatial(pcr.scalar(0.)) self.Q= pcr.ifthenelse(self.waterBodies.distribution == 0,\ pcr.kinematic(self.channelLDD,estQ,0.,self.alphaQ,\ self.betaQ,1,deltaTime,self.channelLength),self.Q) # * water bodies * self.waterBodies.dischargeUpdate() self.Q= self.waterBodies.returnMapValue(self.Q,self.waterBodies.actualQ) #-fluxes and resulting change in storage: first the local fluxes are evaluated # and aggregated over the water bodies where applicable; this includes the specific runoff [m/day/m2] # from input and the estimated extraction from surface water as volume per day [m3/day]; # specific runoff from the land surface is always positive whereas the fluxes over the water surface # are potential, including discharge, and are adjusted to match the availabe storage; to this end, # surface water storage and fluxes over water bodies are totalized and assigned to the outlet; # discharge is updated in a separate step, after vertical fluxes are compared to the actual storage deltaActualStorage= ((self.landFraction*self.landSurfaceQ+\ self.waterFraction*self.potWaterSurfaceQ)*self.cellArea-\ self.potSurfaceWaterExtraction)*float(self.duration)/nrIter deltaActualStorage= pcr.ifthenelse(self.waterBodies.distribution != 0,\ pcr.ifthenelse(self.waterBodies.location != 0,\ pcr.areatotal(deltaActualStorage,self.waterBodies.distribution),0),\ deltaActualStorage) adjustmentRatio= pcr.ifthenelse(deltaActualStorage < 0.,\ pcr.min(1.,-self.actualStorage/deltaActualStorage),1.) self.actWaterSurfaceQ+= adjustmentRatio*self.potWaterSurfaceQ self.actSurfaceWaterExtraction+= adjustmentRatio*self.actSurfaceWaterExtraction deltaActualStorage*= adjustmentRatio #-local water balance check if testLocalWaterBalance: differenceActualStorage= self.actualStorage differenceActualStorage+= deltaActualStorage #-overall water balance check: net input self.cumulativeDeltaStorage+= pcr.catchmenttotal(deltaActualStorage,self.LDD) #-update storage first with local changes, then balance discharge with storage and update storage # with lateral flow and return value to water bodies self.actualStorage+= deltaActualStorage self.actualStorage= pcr.max(0.,self.actualStorage) self.Q= pcr.min(self.Q,self.actualStorage/deltaTime) deltaActualStorage= (-self.Q+pcr.upstream(self.LDD,self.Q))*deltaTime deltaActualStorage= pcr.ifthenelse(self.waterBodies.distribution != 0,\ pcr.ifthenelse(self.waterBodies.location != 0,\ pcr.areatotal(deltaActualStorage,self.waterBodies.distribution),0),\ deltaActualStorage) self.actualStorage+= deltaActualStorage self.actualStorage= pcr.max(0.,self.actualStorage) self.waterBodies.actualStorage= self.waterBodies.retrieveMapValue(self.actualStorage) #-flooded fraction returned floodedFraction,floodedDepth,\ self.wettedArea,self.alphaQ= self.kinAlphaComposite(self.actualStorage,self.floodplainMask) self.wettedArea= self.waterBodies.returnMapValue(self.wettedArea,\ self.waterBodies.channelWidth+2.*self.waterBodies.updateWaterHeight()) self.waterFraction= pcr.ifthenelse(self.waterBodies.distribution == 0,\ pcr.max(self.waterFractionMask,floodedFraction),self.waterFractionMask) self.landFraction= pcr.max(0.,1.-self.waterFraction) self.flowVelocity= pcr.ifthenelse(self.wettedArea > 0,self.Q/self.wettedArea,0.) #-local water balance check if testLocalWaterBalance: differenceActualStorage+= deltaActualStorage differenceActualStorage-= self.actualStorage totalDifference= pcr.cellvalue(pcr.maptotal(differenceActualStorage),1)[0] minimumDifference= pcr.cellvalue(pcr.mapminimum(differenceActualStorage),1)[0] maximumDifference= pcr.cellvalue(pcr.mapmaximum(differenceActualStorage),1)[0] if abs(totalDifference) > 1.e-3: print 'water balance error: total %e; min %e; max %e' %\ (totalDifference,minimumDifference,maximumDifference) if reportLocalWaterBalance: pcr.report(differenceActualStorage,'mbe_%s.map' % self.currentDate.date()) #-overall water balance check: updating cumulative discharge and total storage [m3] self.totalDischarge+= self.Q*deltaTime self.totalStorage= pcr.catchmenttotal(self.actualStorage,self.LDD) #-check on occurrence of last day and report mass balance if self.currentDate == self.endDate: #-report initial maps pcr.report(self.Q,self.QIniMap) pcr.report(self.actualStorage,self.actualStorageIniMap) #-return relative and absolute water balance error per cell and # as total at basin outlets self.totalDischarge= pcr.ifthen((self.waterBodies.distribution == 0) | \ (self.waterBodies.location != 0),self.totalDischarge) self.cumulativeDeltaStorage= pcr.ifthen((self.waterBodies.distribution == 0) | \ (self.waterBodies.location != 0),self.cumulativeDeltaStorage) massBalanceError= self.totalStorage+self.totalDischarge-\ self.cumulativeDeltaStorage relMassBalanceError= 1.+pcr.ifthenelse(self.cumulativeDeltaStorage <> 0., massBalanceError/self.cumulativeDeltaStorage,0.) totalMassBalanceError= pcr.cellvalue(pcr.maptotal(pcr.ifthen(self.basinOutlet,\ massBalanceError)),1)[0] totalCumulativeDeltaStorage= pcr.cellvalue(pcr.maptotal(pcr.ifthen(self.basinOutlet,\ self.cumulativeDeltaStorage)),1)[0] if totalCumulativeDeltaStorage > 0: totalRelativeMassBalanceError= 1.+totalMassBalanceError/totalCumulativeDeltaStorage else: totalRelativeMassBalanceError= 1. #-report maps and echo value pcr.report(massBalanceError,mbeFileName) pcr.report(relMassBalanceError,mbrFileName) print '\n*\ttotal global mass balance error [m3]: %8.3g' % totalMassBalanceError print '\n*\trelative global mass balance error [-]: %5.3f' % totalRelativeMassBalanceError #-echo to screen: total mass balance error and completion of run print '\trun completed' #-end of day: return states and fluxes #-get surface water attributes? if getSurfaceWaterAttributes: #-compute the following secondary variables: # surface water area [m2]: area given dynamic surface water fraction # residence time [days]: volume over discharge, assigned -1 in case discharge is zero # surface water depth [m], weighed by channel and floodplain volume surfaceWaterArea= self.waterFraction*self.cellArea surfaceWaterArea= pcr.ifthenelse(self.waterBodies.distribution != 0,\ pcr.ifthenelse(self.waterBodies.location != 0,\ pcr.areatotal(surfaceWaterArea,self.waterBodies.distribution),0),\ surfaceWaterArea) surfaceWaterResidenceTime= pcr.ifthenelse(self.Q > 0.,self.actualStorage/(self.Q*self.timeSec),-1) surfaceWaterDepth= pcr.ifthenelse(self.actualStorage > 0.,\ pcr.max(0.,self.actualStorage-self.channelStorageCapacity)**2/\ (self.actualStorage*surfaceWaterArea),0.) surfaceWaterDepth+= pcr.ifthenelse(self.actualStorage > 0.,\ pcr.min(self.channelStorageCapacity,self.actualStorage)**2/(self.waterFractionMask*\ self.cellArea*self.actualStorage),0.) #-reports: values at outlet of lakes or reservoirs are assigned to their full extent self.report(pcr.ifthenelse(self.waterBodies.distribution != 0,\ pcr.areamaximum(surfaceWaterArea,self.waterBodies.distribution),surfaceWaterArea),\ surfaceWaterAreaFileName) self.report(pcr.ifthenelse(self.waterBodies.distribution != 0,\ pcr.areamaximum(surfaceWaterResidenceTime,self.waterBodies.distribution),surfaceWaterResidenceTime),\ surfaceWaterResidenceTimeFileName) self.report(pcr.ifthenelse(self.waterBodies.distribution != 0,\ pcr.areamaximum(surfaceWaterDepth,self.waterBodies.distribution),surfaceWaterDepth),\ surfaceWaterDepthFileName) #-reports on standard output: values at outlet of lakes or reservoirs are assigned to their full extent self.report(pcr.ifthenelse(self.waterBodies.distribution != 0, pcr.areamaximum(self.flowVelocity,self.waterBodies.distribution),self.flowVelocity),flowVelocityFileName) self.report(pcr.ifthenelse(self.waterBodies.distribution != 0, pcr.areamaximum(self.Q,self.waterBodies.distribution),self.Q),QFileName) self.report(pcr.ifthenelse(self.waterBodies.distribution == 0,\ floodedFraction,0.),floodedFractionFileName) self.report(pcr.ifthenelse(self.waterBodies.distribution == 0,\ floodedDepth,0.),floodedDepthFileName) self.report(self.actualStorage,actualStorageFileName) #-update date for time step and report relevant daily output self.currentDate= self.currentDate+datetime.timedelta(self.duration)
def dynamic(self): """ dynamic part of the output module """ # ************************************************************ # ***** WRITING RESULTS: TIME SERIES ************************* # ************************************************************ # xxx=catchmenttotal(self.var.SurfaceRunForest * self.var.PixelArea, self.var.Ldd) * self.var.InvUpArea # self.var.Tss['DisTS'].sample(xxx) # self.report(self.Precipitation,binding['TaMaps']) # if fast init than without time series settings = LisSettings.instance() option = settings.options binding = settings.binding flags = settings.flags report_time_serie_act = settings.report_timeseries report_maps_end = settings.report_maps_end report_maps_steps = settings.report_maps_steps report_maps_all = settings.report_maps_all if not (option['InitLisfloodwithoutSplit']): if flags['loud']: # print the discharge of the first output map loc try: print(" %10.2f" % self.var.Tss["DisTS"].firstout( decompress(self.var.ChanQAvg))) except: pass for tss in report_time_serie_act: # report time series what = 'self.var.' + report_time_serie_act[tss].output_var how = report_time_serie_act[tss].operation[0] if len( report_time_serie_act[tss].operation) else '' if how == 'mapmaximum': changed = compressArray(mapmaximum(decompress(eval(what)))) what = 'changed' if how == 'total': changed = compressArray( catchmenttotal( decompress(eval(what)) * self.var.PixelAreaPcr, self.var.Ldd) * self.var.InvUpArea) what = 'changed' self.var.Tss[tss].sample(decompress(eval(what))) # ************************************************************ # ***** WRITING RESULTS: MAPS ****************************** # ************************************************************ # started nicely but now it becomes way to complicated, I am not happy about the next part -> has to be chaged checkifdouble = [] # list to check if map is reported more than once monthly = False yearly = False # Report END maps for maps in report_maps_end.keys(): # report end map filename if settings.mc_set: # MonteCarlo model where = os.path.join(str(self.var.currentSampleNumber()), binding[maps].split("/")[-1]) else: where = binding.get(maps) if not where: continue what = 'self.var.' + report_maps_end[maps].output_var if where not in checkifdouble: checkifdouble.append(where) # checks if saved at same place, if no: add to list if self.var.currentTimeStep() == self.var.nrTimeSteps(): # final step: Write end maps # Get start date for reporting start step # (last step indeed) reportStartDate = inttodate(self.var.currentTimeStep() - 1, self.var.CalendarDayStart) # if suffix with '.' is part of the filename report with # suffix head, tail = os.path.split(where) if '.' in tail: if option['writeNetcdf']: # CM mod: write end map to netCDF file (single) # CM ########################## try: writenet(0, eval(what), where, self.var.DtDay, maps, report_maps_end[maps].output_var, report_maps_end[maps].unit, 'f4', reportStartDate, self.var.currentTimeStep(), self.var.currentTimeStep()) except Exception as e: print(str(e), 'END', what, where, self.var.DtDay, maps, report_maps_end[maps].output_var, report_maps_end[maps].unit, 'f4', reportStartDate, self.var.currentTimeStep(), self.var.currentTimeStep()) ################################ else: report(decompress(eval(what)), str(where)) else: if option['writeNetcdfStack']: try: writenet(0, eval(what), where, self.var.DtDay, maps, report_maps_end[maps].output_var, report_maps_end[maps].unit, 'f4', reportStartDate, self.var.currentTimeStep(), self.var.currentTimeStep()) except Exception as e: print(str(e), 'END', what, where, self.var.DtDay, maps, report_maps_end[maps].output_var, report_maps_end[maps].unit, 'f4', reportStartDate, self.var.currentTimeStep(), self.var.currentTimeStep()) ########################### else: self.var.report(decompress(eval(what)), str(where)) # Report REPORTSTEPS maps for maps in report_maps_steps.keys(): # report reportsteps maps if settings.mc_set: # MonteCarlo model where = os.path.join(str(self.var.currentSampleNumber()), binding[maps].split("/")[-1]) else: where = binding.get(maps) if not where: continue what = 'self.var.' + report_maps_steps[maps].output_var if not (where in checkifdouble): checkifdouble.append(where) # checks if saved at same place, if no: add to list if self.var.currentTimeStep() in self.var.ReportSteps: flagcdf = 1 # index flag for writing nedcdf = 1 (=steps) -> indicated if a netcdf is created or maps are appended frequency = "all" try: if report_maps_steps[maps].monthly: monthly = True flagcdf = 3 # set to monthly (step) flag frequency = "monthly" except: monthly = False try: if report_maps_steps[maps].yearly: yearly = True flagcdf = 4 # set to yearly (step) flag frequency = "annual" except: yearly = False if (monthly and self.var.monthend) or ( yearly and self.var.yearend) or not (monthly or yearly): # checks if a flag monthly or yearly exists if option['writeNetcdfStack']: # Get start date for reporting start step reportStartDate = inttodate( self.var.ReportSteps[0] - 1, self.var.CalendarDayStart) # get step number for first reporting step reportStepStart = 1 # get step number for last reporting step reportStepEnd = self.var.ReportSteps[ -1] - self.var.ReportSteps[0] + 1 cdfflags = CDFFlags.instance() try: writenet(cdfflags[flagcdf], eval(what), where, self.var.DtDay, maps, report_maps_steps[maps].output_var, report_maps_steps[maps].unit, 'f4', reportStartDate, reportStepStart, reportStepEnd, frequency) except Exception as e: print(" +----> ERR: {}".format(str(e))) print( "REP flag:{} - {} {} {} {} {} {} {} {} {} {}" .format(cdfflags[flagcdf], what, where, self.var.DtDay, maps, report_maps_steps[maps].output_var, report_maps_steps[maps].unit, 'f4', reportStartDate, reportStepStart, reportStepEnd)) else: self.var.report(decompress(eval(what)), str(where)) # Report ALL maps for maps in report_maps_all.keys(): # report maps for all timesteps if settings.mc_set: where = os.path.join(str(self.var.currentSampleNumber()), binding[maps].split("/")[-1]) else: where = binding.get(maps) if not where: continue what = 'self.var.' + report_maps_all[maps].output_var if where not in checkifdouble: checkifdouble.append(where) # checks if saved at same place, if no: add to list # index flag for writing nedcdf = 1 (=all) -> indicated if a netcdf is created or maps are appended # cannot check only if netcdf exists, because than an old netcdf will be used accidently flagcdf = 2 frequency = "all" try: if report_maps_all[maps].monthly: monthly = True flagcdf = 5 # set to monthly flag frequency = "monthly" except: monthly = False try: if report_maps_all[maps].yearly: yearly = True flagcdf = 6 # set to yearly flag frequency = "annual" except: yearly = False if (monthly and self.var.monthend) or ( yearly and self.var.yearend) or not (monthly or yearly): # checks if a flag monthly or yearly exists] if option['writeNetcdfStack']: #Get start date for reporting start step reportStartDate = inttodate( binding['StepStartInt'] - 1, self.var.CalendarDayStart) # CM: get step number for first reporting step which is always the first simulation step # CM: first simulation step referred to reportStartDate ##reportStepStart = int(binding['StepStart']) reportStepStart = 1 #get step number for last reporting step which is always the last simulation step #last simulation step referred to reportStartDate reportStepEnd = binding['StepEndInt'] - binding[ 'StepStartInt'] + 1 try: cdfflags = CDFFlags.instance() writenet(cdfflags[flagcdf], eval(what), where, self.var.DtDay, maps, report_maps_all[maps].output_var, report_maps_all[maps].unit, 'f4', reportStartDate, reportStepStart, reportStepEnd, frequency) except Exception as e: warnings.warn(LisfloodWarning(str(e))) print(str(e), "ALL", what, where, self.var.DtDay, maps, report_maps_all[maps].output_var, report_maps_all[maps].unit, 'f4', reportStartDate, reportStepStart, reportStepEnd) else: self.var.report(decompress(eval(what)), trimPCRasterOutputPath(where)) cdfflags = CDFFlags.instance() # set the falg to indicate if a netcdffile has to be created or is only appended # if reportstep than increase the counter if self.var.currentTimeStep() in self.var.ReportSteps: # FIXME magic numbers. replace indexes with descriptive keys cdfflags.inc(1) # globals.cdfFlag[1] += 1 if self.var.monthend: # globals.cdfFlag[3] += 1 cdfflags.inc(3) if self.var.yearend: # globals.cdfFlag[4] += 1 cdfflags.inc(4) # increase the counter for report all maps cdfflags.inc(2) # globals.cdfFlag[2] += 1 if self.var.monthend: # globals.cdfFlag[5] += 1 cdfflags.inc(5) if self.var.yearend: # globals.cdfFlag[6] += 1 cdfflags.inc(6)
reservoir_capacity = pcr.ifthen(landmask, \ pcr.cover(\ vos.readPCRmapClone(reservoir_capacity_file, \ clone_map_file, \ tmp_folder, \ None, False, None, False), 0.0)) * 1000. * 1000. water_body_id = vos.readPCRmapClone(water_body_id_file, \ clone_map_file, \ tmp_folder, \ None, False, None, True ) water_body_id = pcr.ifthen( pcr.scalar(water_body_id) > 0.00, water_body_id) water_body_id = pcr.ifthen(landmask, water_body_id) # # water body outlet wbCatchment = pcr.catchmenttotal(pcr.scalar(1), ldd_map_low_resolution) water_body_outlet = pcr.ifthen(wbCatchment ==\ pcr.areamaximum(wbCatchment, \ water_body_id),\ water_body_id) # = outlet ids # This may give more than two outlets, particularly if there are more than one cells that have largest upstream areas # - make sure that there is only one outlet for each water body water_body_outlet = pcr.ifthen(\ pcr.areaorder(pcr.scalar( water_body_outlet), \ water_body_outlet) == 1., water_body_outlet) water_body_outlet = pcr.ifthen(\ pcr.scalar(water_body_outlet) > 0., water_body_outlet) # calculate overbank volume from reservoirs (and lakes) lake_reservoir_volume = pcr.areatotal(extreme_value_map, water_body_id) lake_reservoir_overbank_volume = pcr.cover( pcr.max(0.0, lake_reservoir_volume - reservoir_capacity), 0.0)
def __init__(self, modelTime, input_file, output_file, variable_name, variable_unit): DynamicModel.__init__(self) self.modelTime = modelTime # netcdf input file - based on PCR-GLOBWB output self.input_file = "/projects/0/dfguu/users/edwin/pcr-globwb-aqueduct/historical/1951-2005/gfdl-esm2m/temperature_annuaAvg_output_%s-12-31_to_%s-12-31.nc" self.input_file = input_file # output file - in netcdf format self.output_file = output_folder + "/mekong/basin_temperature_annuaAvg_output.nc" self.output_file = output_file # output variable name and unit self.variable_name = variable_name self.variable_unit = variable_unit # preparing temporary directory self.temporary_directory = output_folder + "/tmp/" os.makedirs(self.temporary_directory) # clone and landmask maps logger.info("Set the clone and landmask maps.") self.clonemap_file_name = "/projects/0/dfguu/users/edwinhs/data/mekong_etc_clone/version_2018-10-22/final/clone_mekong.map" pcr.setclone(self.clonemap_file_name) landmask_file_name = "/projects/0/dfguu/users/edwinhs/data/mekong_etc_clone/version_2018-10-22/final/mask_mekong.map" self.landmask = vos.readPCRmapClone(landmask_file_name, \ self.clonemap_file_name, \ self.temporary_directory, \ None, False, None, True) # pcraster input files # - river network map and sub-catchment map ldd_file_name = "/projects/0/dfguu/data/hydroworld/PCRGLOBWB20/input5min/routing/lddsound_05min.map" # - cell area (unit: m2) cell_area_file_name = "/projects/0/dfguu/data/hydroworld/PCRGLOBWB20/input5min/routing/cellsize05min.correct.map" # loading pcraster input maps self.ldd_network = vos.readPCRmapClone(ldd_file_name, \ self.clonemap_file_name, \ self.temporary_directory, \ None, \ True) self.ldd_network = pcr.lddrepair(pcr.ldd(self.ldd_network)) self.ldd_network = pcr.lddrepair(self.ldd_network) self.cell_area = vos.readPCRmapClone(cell_area_file_name, \ self.clonemap_file_name, \ self.temporary_directory, \ None) # set/limit all input maps to the defined landmask self.ldd_network = pcr.ifthen(self.landmask, self.ldd_network) self.cell_area = pcr.ifthen(self.landmask, self.cell_area) # calculate basin/catchment area self.basin_area = pcr.catchmenttotal(self.cell_area, self.ldd_network) self.basin_area = pcr.ifthen(self.landmask, self.basin_area) # preparing an object for reporting netcdf files: self.netcdf_report = netcdf_writer.PCR2netCDF(self.clonemap_file_name) # preparing netcdf output files: self.netcdf_report.createNetCDF(self.output_file, \ self.variable_name, \ self.variable_unit)
def getParameterFiles( self, currTimeStep, cellArea, ldd, initial_condition_dictionary=None ): # parameters for Water Bodies: fracWat # waterBodyIds # waterBodyOut # waterBodyArea # waterBodyTyp # waterBodyCap # cell surface area (m2) and ldd self.cellArea = cellArea ldd = pcr.ifthen(self.landmask, ldd) # date used for accessing/extracting water body information date_used = currTimeStep.fulldate year_used = currTimeStep.year if self.onlyNaturalWaterBodies == True: date_used = self.dateForNaturalCondition year_used = self.dateForNaturalCondition[0:4] # fracWat = fraction of surface water bodies (dimensionless) self.fracWat = pcr.scalar(0.0) if self.useNetCDF: self.fracWat = vos.netcdf2PCRobjClone( self.ncFileInp, "fracWaterInp", date_used, useDoy="yearly", cloneMapFileName=self.cloneMap, ) else: self.fracWat = vos.readPCRmapClone( self.fracWaterInp + str(year_used) + ".map", self.cloneMap, self.tmpDir, self.inputDir, ) self.fracWat = pcr.cover(self.fracWat, 0.0) self.fracWat = pcr.max(0.0, self.fracWat) self.fracWat = pcr.min(1.0, self.fracWat) self.waterBodyIds = pcr.nominal(0) # waterBody ids self.waterBodyOut = pcr.boolean(0) # waterBody outlets self.waterBodyArea = pcr.scalar(0.0) # waterBody surface areas # water body ids if self.useNetCDF: self.waterBodyIds = vos.netcdf2PCRobjClone( self.ncFileInp, "waterBodyIds", date_used, useDoy="yearly", cloneMapFileName=self.cloneMap, ) else: self.waterBodyIds = vos.readPCRmapClone( self.waterBodyIdsInp + str(year_used) + ".map", self.cloneMap, self.tmpDir, self.inputDir, False, None, True, ) # self.waterBodyIds = pcr.ifthen( pcr.scalar(self.waterBodyIds) > 0.0, pcr.nominal(self.waterBodyIds) ) # water body outlets (correcting outlet positions) wbCatchment = pcr.catchmenttotal(pcr.scalar(1), ldd) self.waterBodyOut = pcr.ifthen( wbCatchment == pcr.areamaximum(wbCatchment, self.waterBodyIds), self.waterBodyIds, ) # = outlet ids self.waterBodyOut = pcr.ifthen( pcr.scalar(self.waterBodyIds) > 0.0, self.waterBodyOut ) # TODO: Please also consider endorheic lakes! # correcting water body ids self.waterBodyIds = pcr.ifthen( pcr.scalar(self.waterBodyIds) > 0.0, pcr.subcatchment(ldd, self.waterBodyOut), ) # boolean map for water body outlets: self.waterBodyOut = pcr.ifthen( pcr.scalar(self.waterBodyOut) > 0.0, pcr.boolean(1) ) # reservoir surface area (m2): if self.useNetCDF: resSfArea = ( 1000.0 * 1000.0 * vos.netcdf2PCRobjClone( self.ncFileInp, "resSfAreaInp", date_used, useDoy="yearly", cloneMapFileName=self.cloneMap, ) ) else: resSfArea = ( 1000.0 * 1000.0 * vos.readPCRmapClone( self.resSfAreaInp + str(year_used) + ".map", self.cloneMap, self.tmpDir, self.inputDir, ) ) resSfArea = pcr.areaaverage(resSfArea, self.waterBodyIds) resSfArea = pcr.cover(resSfArea, 0.0) # water body surface area (m2): (lakes and reservoirs) self.waterBodyArea = pcr.max( pcr.areatotal( pcr.cover(self.fracWat * self.cellArea, 0.0), self.waterBodyIds ), pcr.areaaverage(pcr.cover(resSfArea, 0.0), self.waterBodyIds), ) self.waterBodyArea = pcr.ifthen(self.waterBodyArea > 0.0, self.waterBodyArea) # correcting water body ids and outlets (exclude all water bodies with surfaceArea = 0) self.waterBodyIds = pcr.ifthen(self.waterBodyArea > 0.0, self.waterBodyIds) self.waterBodyOut = pcr.ifthen( pcr.boolean(self.waterBodyIds), self.waterBodyOut ) # water body types: # - 2 = reservoirs (regulated discharge) # - 1 = lakes (weirFormula) # - 0 = non lakes or reservoirs (e.g. wetland) self.waterBodyTyp = pcr.nominal(0) if self.useNetCDF: self.waterBodyTyp = vos.netcdf2PCRobjClone( self.ncFileInp, "waterBodyTyp", date_used, useDoy="yearly", cloneMapFileName=self.cloneMap, ) else: self.waterBodyTyp = vos.readPCRmapClone( self.waterBodyTypInp + str(year_used) + ".map", self.cloneMap, self.tmpDir, self.inputDir, False, None, True, ) # excluding wetlands (waterBodyTyp = 0) in all functions related to lakes/reservoirs # self.waterBodyTyp = pcr.ifthen( pcr.scalar(self.waterBodyTyp) > 0, pcr.nominal(self.waterBodyTyp) ) self.waterBodyTyp = pcr.ifthen( pcr.scalar(self.waterBodyIds) > 0, pcr.nominal(self.waterBodyTyp) ) self.waterBodyTyp = pcr.areamajority( self.waterBodyTyp, self.waterBodyIds ) # choose only one type: either lake or reservoir self.waterBodyTyp = pcr.ifthen( pcr.scalar(self.waterBodyTyp) > 0, pcr.nominal(self.waterBodyTyp) ) self.waterBodyTyp = pcr.ifthen( pcr.boolean(self.waterBodyIds), self.waterBodyTyp ) # correcting lakes and reservoirs ids and outlets self.waterBodyIds = pcr.ifthen( pcr.scalar(self.waterBodyTyp) > 0, self.waterBodyIds ) self.waterBodyOut = pcr.ifthen( pcr.scalar(self.waterBodyIds) > 0, self.waterBodyOut ) # reservoir maximum capacity (m3): self.resMaxCap = pcr.scalar(0.0) self.waterBodyCap = pcr.scalar(0.0) if self.useNetCDF: self.resMaxCap = ( 1000.0 * 1000.0 * vos.netcdf2PCRobjClone( self.ncFileInp, "resMaxCapInp", date_used, useDoy="yearly", cloneMapFileName=self.cloneMap, ) ) else: self.resMaxCap = ( 1000.0 * 1000.0 * vos.readPCRmapClone( self.resMaxCapInp + str(year_used) + ".map", self.cloneMap, self.tmpDir, self.inputDir, ) ) self.resMaxCap = pcr.ifthen(self.resMaxCap > 0, self.resMaxCap) self.resMaxCap = pcr.areaaverage(self.resMaxCap, self.waterBodyIds) # water body capacity (m3): (lakes and reservoirs) self.waterBodyCap = pcr.cover( self.resMaxCap, 0.0 ) # Note: Most of lakes have capacities > 0. self.waterBodyCap = pcr.ifthen( pcr.boolean(self.waterBodyIds), self.waterBodyCap ) # correcting water body types: # Reservoirs that have zero capacities will be assumed as lakes. self.waterBodyTyp = pcr.ifthen( pcr.scalar(self.waterBodyTyp) > 0.0, self.waterBodyTyp ) self.waterBodyTyp = pcr.ifthenelse( self.waterBodyCap > 0.0, self.waterBodyTyp, pcr.ifthenelse( pcr.scalar(self.waterBodyTyp) == 2, pcr.nominal(1), self.waterBodyTyp ), ) # final corrections: self.waterBodyTyp = pcr.ifthen( self.waterBodyArea > 0.0, self.waterBodyTyp ) # make sure that all lakes and/or reservoirs have surface areas self.waterBodyTyp = pcr.ifthen( pcr.scalar(self.waterBodyTyp) > 0.0, self.waterBodyTyp ) # make sure that only types 1 and 2 will be considered in lake/reservoir functions self.waterBodyIds = pcr.ifthen( pcr.scalar(self.waterBodyTyp) > 0.0, self.waterBodyIds ) # make sure that all lakes and/or reservoirs have ids self.waterBodyOut = pcr.ifthen( pcr.scalar(self.waterBodyIds) > 0.0, self.waterBodyOut ) # make sure that all lakes and/or reservoirs have outlets # for a natural run (self.onlyNaturalWaterBodies == True) # which uses only the year 1900, assume all reservoirs are lakes if ( self.onlyNaturalWaterBodies == True and date_used == self.dateForNaturalCondition ): logger.info( "Using only natural water bodies identified in the year 1900. All reservoirs in 1900 are assumed as lakes." ) self.waterBodyTyp = pcr.ifthen( pcr.scalar(self.waterBodyTyp) > 0.0, pcr.nominal(1) ) # check that all lakes and/or reservoirs have types, ids, surface areas and outlets: test = ( pcr.defined(self.waterBodyTyp) & pcr.defined(self.waterBodyArea) & pcr.defined(self.waterBodyIds) & pcr.boolean( pcr.areamaximum(pcr.scalar(self.waterBodyOut), self.waterBodyIds) ) ) a, b, c = vos.getMinMaxMean(pcr.cover(pcr.scalar(test), 1.0) - pcr.scalar(1.0)) threshold = 1e-3 if abs(a) > threshold or abs(b) > threshold: logger.warning("Missing information in some lakes and/or reservoirs.") # at the beginning of simulation period (timeStepPCR = 1) # - we have to define/get the initial conditions # if currTimeStep.timeStepPCR == 1: self.getICs(initial_condition_dictionary) # For each new reservoir (introduced at the beginning of the year) # initiating storage, average inflow and outflow # self.waterBodyStorage = pcr.cover(self.waterBodyStorage, 0.0) self.avgInflow = pcr.cover(self.avgInflow, 0.0) self.avgOutflow = pcr.cover(self.avgOutflow, 0.0) # cropping only in the landmask region: self.fracWat = pcr.ifthen(self.landmask, self.fracWat) self.waterBodyIds = pcr.ifthen(self.landmask, self.waterBodyIds) self.waterBodyOut = pcr.ifthen(self.landmask, self.waterBodyOut) self.waterBodyArea = pcr.ifthen(self.landmask, self.waterBodyArea) self.waterBodyTyp = pcr.ifthen(self.landmask, self.waterBodyTyp) self.waterBodyCap = pcr.ifthen(self.landmask, self.waterBodyCap) self.waterBodyStorage = pcr.ifthen(self.landmask, self.waterBodyStorage) self.avgInflow = pcr.ifthen(self.landmask, self.avgInflow) self.avgOutflow = pcr.ifthen(self.landmask, self.avgOutflow)
output_files['tmp_folder'], None, False, None, True)) #~ pcr.aguila(basin_map) # - extend/extrapolate the basin basin_map = pcr.cover(basin_map, pcr.windowmajority(basin_map, 0.5)) basin_map = pcr.cover(basin_map, pcr.windowmajority(basin_map, 0.5)) basin_map = pcr.cover(basin_map, pcr.windowmajority(basin_map, 0.5)) basin_map = pcr.cover(basin_map, pcr.windowmajority(basin_map, 1.0)) basin_map = pcr.cover(basin_map, pcr.windowmajority(basin_map, 1.5)) basin_map = pcr.ifthen(landmask, basin_map) #~ pcr.aguila(basin_map) msg = "Redefining the basin map (so that it is consistent with the ldd map used in PCR-GLOBWB):" logger.info(msg) # - calculate the upstream area of every pixel: upstream_area = pcr.catchmenttotal(cell_area, ldd) # - calculate the catchment area of every basin: upstream_area_maximum = pcr.areamaximum(upstream_area, basin_map) # - identify the outlet of every basin (in order to rederive the basin so that it is consistent with the ldd) outlet = pcr.nominal(pcr.uniqueid(pcr.ifthen(upstream_area == upstream_area_maximum, pcr.boolean(1.0)))) # - ignoring outlets with small upstream areas threshold = 50. * 1000. * 1000. # unit: m2 outlet = pcr.ifthen(upstream_area_maximum > threshold, outlet) #~ pcr.aguila(outlet) outlet = pcr.cover(outlet, pcr.nominal(0.0)) # - recalculate the basin basin_map = pcr.nominal(pcr.subcatchment(ldd, outlet)) basin_map = pcr.clump(basin_map) basin_map = pcr.ifthen(landmask, basin_map) pcr.report(basin_map , "basin_map.map") #~ pcr.aguila(basin_map)
None, False, None, False), 0.0)) reservoir_capacity = pcr.ifthen(landmask, \ pcr.cover(\ vos.readPCRmapClone(reservoir_capacity_file, \ clone_map_file, \ tmp_folder, \ None, False, None, False), 0.0)) * 1000. * 1000. water_body_id = vos.readPCRmapClone(water_body_id_file, \ clone_map_file, \ tmp_folder, \ None, False, None, True ) water_body_id = pcr.ifthen(pcr.scalar(water_body_id) > 0.00, water_body_id) water_body_id = pcr.ifthen( landmask, water_body_id) # # water body outlet wbCatchment = pcr.catchmenttotal(pcr.scalar(1), ldd_map_low_resolution) water_body_outlet = pcr.ifthen(wbCatchment ==\ pcr.areamaximum(wbCatchment, \ water_body_id),\ water_body_id) # = outlet ids # This may give more than two outlets, particularly if there are more than one cells that have largest upstream areas # - make sure that there is only one outlet for each water body water_body_outlet = pcr.ifthen(\ pcr.areaorder(pcr.scalar( water_body_outlet), \ water_body_outlet) == 1., water_body_outlet) water_body_outlet = pcr.ifthen(\ pcr.scalar(water_body_outlet) > 0., water_body_outlet) # calculate overbank volume from reservoirs (and lakes) lake_reservoir_volume = pcr.areatotal(extreme_value_map, water_body_id) lake_reservoir_overbank_volume = pcr.cover( pcr.max(0.0, lake_reservoir_volume - reservoir_capacity), 0.0)
def evaluateAllModelResults(self,globalCloneMapFileName,\ catchmentClassFileName,\ lddMapFileName,\ cellAreaMapFileName,\ pcrglobwb_output,\ analysisOutputDir="",\ tmpDir = None): # temporary directory if tmpDir == None: tmpDir = self.tmpDir+"/edwin_grdc_" # output directory for all analyses for all stations analysisOutputDir = str(analysisOutputDir) self.chartOutputDir = analysisOutputDir+"/chart/" self.tableOutputDir = analysisOutputDir+"/table/" # if analysisOutputDir == "": self.chartOutputDir = "chart/" if analysisOutputDir == "": self.tableOutputDir = "table/" # # make the chart and table directories: os.system('rm -r '+self.chartOutputDir+"*") os.system('rm -r '+self.tableOutputDir+"*") os.makedirs(self.chartOutputDir) os.makedirs(self.tableOutputDir) # cloneMap for all pcraster operations pcr.setclone(globalCloneMapFileName) cloneMap = pcr.boolean(1) self.cell_size_in_arc_degree = vos.getMapAttributesALL(globalCloneMapFileName)['cellsize'] lddMap = pcr.lddrepair(pcr.readmap(lddMapFileName)) cellArea = pcr.scalar(pcr.readmap(cellAreaMapFileName)) # The landMaskClass map contains the nominal classes for all landmask regions. landMaskClass = pcr.nominal(cloneMap) # default: if catchmentClassFileName is not given if catchmentClassFileName != None: landMaskClass = pcr.nominal(pcr.readmap(catchmentClassFileName)) # model catchment areas and cordinates catchmentAreaAll = pcr.catchmenttotal(cellArea, lddMap) / (1000*1000) # unit: km2 xCoordinate = pcr.xcoordinate(cloneMap) yCoordinate = pcr.ycoordinate(cloneMap) for id in self.list_of_grdc_ids: logger.info("Evaluating simulated discharge to the grdc observation at "+str(self.attributeGRDC["id_from_grdc"][str(id)])+".") # identify model pixel self.identifyModelPixel(tmpDir,catchmentAreaAll,landMaskClass,xCoordinate,yCoordinate,str(id)) # evaluate model results to GRDC data self.evaluateModelResultsToGRDC(str(id),pcrglobwb_output,catchmentClassFileName,tmpDir) # write the summary to a table summary_file = analysisOutputDir+"summary.txt" # logger.info("Writing the summary for all stations to the file: "+str(summary_file)+".") # # prepare the file: summary_file_handle = open(summary_file,"w") # # write the header summary_file_handle.write( ";".join(self.grdc_dict_keys)+"\n") # # write the content for id in self.list_of_grdc_ids: rowLine = "" for key in self.grdc_dict_keys: rowLine += str(self.attributeGRDC[key][str(id)]) + ";" rowLine = rowLine[0:-1] + "\n" summary_file_handle.write(rowLine) summary_file_handle.close()
#~ -rwxr-xr-x 1 sutan101 depfg 36M Nov 11 2019 cellsize05min.correct.map #~ -rw-r--r-- 1 sutan101 depfg 36M Nov 14 2019 cellsize05min_correct.nc #~ -rw-r--r-- 1 sutan101 depfg 36M Nov 14 2019 cellsize05min.correct.nc #~ -rw-r--r-- 1 sutan101 depfg 129 Nov 14 2019 hydroworld_source.txt #~ -rwxr-xr-x 1 sutan101 depfg 8.9M Nov 11 2019 lddsound_05min.map #~ -rw-r--r-- 1 sutan101 depfg 36M Nov 14 2019 lddsound_05min.nc #~ -rw-r--r-- 1 sutan101 depfg 36M Nov 14 2019 lddsound_05min_unmask.nc # calculate pcrglobwb catchment area # - reading input files ldd_file_name = "/scratch/depfg/sutan101/data/pcrglobwb2_input_release/version_2019_11_beta_extended/pcrglobwb2_input/global_05min/routing/ldd_and_cell_area/lddsound_05min.map" ldd = pcr.readmap(ldd_file_name) cell_area_file_name = "/scratch/depfg/sutan101/data/pcrglobwb2_input_release/version_2019_11_beta_extended/pcrglobwb2_input/global_05min/routing/ldd_and_cell_area/cellsize05min.correct.map" cellarea = pcr.readmap(cell_area_file_name) # - calculate pcrglobwb catchment area (km2) pcrglobwb_catchment_area_km2 = pcr.catchmenttotal(cellarea, ldd) / 1e6 # loop through the table for table_line in table_lines[1:len(table_lines) + 1]: #~ for table_line in table_lines[0:len(table_lines) + 1]: #~ for table_line in table_lines[1:3]: # select one line (representing each station) and save it to a tmp file tmp_file_name = "one_line.tmp" if os.path.exists(tmp_file_name): os.remove(tmp_file_name) one_line_txt_file = open(tmp_file_name, "w") one_line_txt_file.write(table_line) one_line_txt_file.close() # edwin_code.map: col2map --clone lddsound_05min.map -N -x 3 -y 2 -v 1 one_line_from_edwin_code_and_usgs_drain_area_km2.txt edwin_code.map cmd = "col2map --clone " + ldd_file_name + \