Example #1
0
    def getLakeOutflow(
        self, avgChannelDischarge, length_of_time_step=vos.secondsPerDay()
    ):

        # waterHeight (m): temporary variable, a function of storage:
        minWaterHeight = (
            0.001
        )  # (m) Rens used 0.001 m as the limit # this is to make sure there is always lake outflow,
        # but it will be still limited by available self.waterBodyStorage
        waterHeight = pcr.cover(
            pcr.max(
                minWaterHeight,
                (self.waterBodyStorage - pcr.cover(self.waterBodyCap, 0.0))
                / self.waterBodyArea,
            ),
            0.0,
        )

        # weirWidth (m) :
        # - estimated from avgOutflow (m3/s) using the bankfull discharge formula
        #
        avgOutflow = self.avgOutflow
        avgOutflow = pcr.ifthenelse(
            avgOutflow > 0.0,
            avgOutflow,
            pcr.max(avgChannelDischarge, self.avgInflow, 0.001),
        )  # This is needed when new lakes/reservoirs introduced (its avgOutflow is still zero).
        avgOutflow = pcr.areamaximum(avgOutflow, self.waterBodyIds)
        #
        bankfullWidth = pcr.cover(pcr.scalar(4.8) * ((avgOutflow) ** (0.5)), 0.0)
        weirWidthUsed = bankfullWidth
        weirWidthUsed = pcr.max(
            weirWidthUsed, self.minWeirWidth
        )  # TODO: minWeirWidth based on the GRanD database
        weirWidthUsed = pcr.cover(
            pcr.ifthen(pcr.scalar(self.waterBodyIds) > 0.0, weirWidthUsed), 0.0
        )

        # avgInflow <= lakeOutflow (weirFormula) <= waterBodyStorage
        lakeOutflowInM3PerSec = pcr.max(
            self.weirFormula(waterHeight, weirWidthUsed), self.avgInflow
        )  # unit: m3/s

        # estimate volume of water relased by lakes
        lakeOutflow = lakeOutflowInM3PerSec * length_of_time_step  # unit: m3
        lakeOutflow = pcr.min(self.waterBodyStorage, lakeOutflow)
        #
        lakeOutflow = pcr.ifthen(pcr.scalar(self.waterBodyIds) > 0.0, lakeOutflow)
        lakeOutflow = pcr.ifthen(pcr.scalar(self.waterBodyTyp) == 1, lakeOutflow)

        # TODO: Consider endorheic lake/basin. No outflow for endorheic lake/basin!

        return lakeOutflow
Example #2
0
    def getLakeOutflow(self,\
        avgChannelDischarge,length_of_time_step = vos.secondsPerDay()):

        # waterHeight (m): temporary variable, a function of storage:
        minWaterHeight = 0.001  # (m) Rens used 0.001 m as the limit # this is to make sure there is always lake outflow,
        # but it will be still limited by available self.waterBodyStorage
        waterHeight = pcr.cover(
                      pcr.max(minWaterHeight, \
                      (self.waterBodyStorage - \
                      pcr.cover(self.waterBodyCap, 0.0))/\
                      self.waterBodyArea),0.)

        # weirWidth (m) :
        # - estimated from avgOutflow (m3/s) using the bankfull discharge formula
        #
        avgOutflow = self.avgOutflow
        avgOutflow = pcr.ifthenelse(\
                     avgOutflow > 0.,\
                     avgOutflow,
                     pcr.max(avgChannelDischarge,self.avgInflow,0.001))            # This is needed when new lakes/reservoirs introduced (its avgOutflow is still zero).
        avgOutflow = pcr.areamaximum(avgOutflow, self.waterBodyIds)
        #
        bankfullWidth = pcr.cover(\
                        pcr.scalar(4.8) * \
                        ((avgOutflow)**(0.5)),0.)
        weirWidthUsed = bankfullWidth
        weirWidthUsed = pcr.max(
            weirWidthUsed, self.minWeirWidth
        )  # TODO: minWeirWidth based on the GRanD database
        weirWidthUsed = pcr.cover(
                        pcr.ifthen(\
                        pcr.scalar(self.waterBodyIds) > 0.,\
                        weirWidthUsed),0.0)

        # avgInflow <= lakeOutflow (weirFormula) <= waterBodyStorage
        lakeOutflowInM3PerSec = pcr.max(\
                                self.weirFormula(waterHeight,weirWidthUsed),\
                                self.avgInflow)                                    # unit: m3/s

        # estimate volume of water relased by lakes
        lakeOutflow = lakeOutflowInM3PerSec * length_of_time_step  # unit: m3
        lakeOutflow = pcr.min(self.waterBodyStorage, lakeOutflow)
        #
        lakeOutflow = pcr.ifthen(
            pcr.scalar(self.waterBodyIds) > 0., lakeOutflow)
        lakeOutflow = pcr.ifthen(
            pcr.scalar(self.waterBodyTyp) == 1, lakeOutflow)

        # TODO: Consider endorheic lake/basin. No outflow for endorheic lake/basin!

        return (lakeOutflow)
Example #3
0
    def premcloop(self):
        self.clone = pcr.boolean(cfg.cloneString)
        self.dem = pcr.scalar(cfg.dem)
        self.createInstancesPremcloop()

        # required for reporting as numpy
        self.locations = pcr.cover(pcr.nominal(cfg.locations), 0)
        pcr.report(self.locations, 'locats')

        self.forestNoForest = pcr.boolean(cfg.forestNoForest)
        idMap = pcr.uniqueid(self.clone)
        oneLocationPerArea = pcr.areamaximum(idMap,
                                             self.forestNoForest) == idMap
        self.locationsForParameters = pcr.cover(
            pcr.nominal(
                pcr.scalar(pcr.ifthen(oneLocationPerArea, self.forestNoForest))
                + 1), 0)
Example #4
0
def area_river_burnin(ldd, dem, order, Area):
    """
  Calculates the lowest values in as DEM for each erea in an area map for
  river of order *order*

  Input:
      - ldd
      - dem
      - order
      - Area map

  Output:
      - dem
  """
    strorder = pcr.streamorder(ldd)
    strordermax = pcr.areamaximum(strorder, Area)
    maxordcell = pcr.ifthen(strordermax > order, strordermax)
    riverdem = pcr.areaminimum(dem, Area)

    return pcr.ifthen(pcr.boolean(maxordcell), riverdem)
Example #5
0
def area_river_burnin(ldd, dem, order, Area):
    """
  Calculates the lowest values in as DEM for each erea in an area map for
  river of order *order*

  Input:
      - ldd
      - dem
      - order
      - Area map

  Output:
      - dem
  """
    strorder = pcr.streamorder(ldd)
    strordermax = pcr.areamaximum(strorder, Area)
    maxordcell = pcr.ifthen(strordermax > order, strordermax)
    riverdem = pcr.areaminimum(dem, Area)

    return pcr.ifthen(pcr.boolean(maxordcell), riverdem)
Example #6
0
def areastat(Var, Area):
    """
    Calculate several statistics of *Var* for each unique id in *Area*

    Input:
        - Var
        - Area

    Output:
        - Standard_Deviation,Average,Max,Min

    """
    Avg = pcr.areaaverage(Var, Area)
    Sq = (Var - Avg) ** 2
    N = pcr.areatotal(pcr.spatial(pcr.cellarea()), Area) / pcr.cellarea()
    Sd = (pcr.areatotal(Sq, Area) / N) ** 0.5
    Max = pcr.areamaximum(Var, Area)
    Min = pcr.areaminimum(Var, Area)

    return Sd, Avg, Max, Min
Example #7
0
def areastat(Var, Area):
    """
    Calculate several statistics of *Var* for each unique id in *Area*

    Input:
        - Var
        - Area

    Output:
        - Standard_Deviation,Average,Max,Min

    """
    Avg = pcr.areaaverage(Var, Area)
    Sq = (Var - Avg) ** 2
    N = pcr.areatotal(pcr.spatial(pcr.cellarea()), Area) / pcr.cellarea()
    Sd = (pcr.areatotal(Sq, Area) / N) ** 0.5
    Max = pcr.areamaximum(Var, Area)
    Min = pcr.areaminimum(Var, Area)

    return Sd, Avg, Max, Min
Example #8
0
def area_riverlength_factor(ldd, Area, Clength):
    """
    ceates correction factors for riverlength for
    the largest streamorder in each area

    Input:
        - ldd
        - Area
        - Clength (1d length of a cell (pcr.sqrt(Area))

    Output:
        - distance per area

    """
    strorder = pcr.streamorder(ldd)
    strordermax = pcr.areamaximum(strorder, Area)
    dist = pcr.downstreamdist(ldd)
    # count nr of strorder cells in each area
    nr = pcr.areatotal(pcr.ifthen(strorder == strordermax, dist), Area)
    # N = pcr.sqrt(pcr.areatotal(pcr.scalar(pcr.boolean(Area)),Area))
    N = Clength
    factor = nr / N

    return factor
Example #9
0
def area_riverlength_factor(ldd, Area, Clength):
    """
    ceates correction factors for riverlength for
    the largest streamorder in each area

    Input:
        - ldd
        - Area
        - Clength (1d length of a cell (pcr.sqrt(Area))

    Output:
        - distance per area

    """
    strorder = pcr.streamorder(ldd)
    strordermax = pcr.areamaximum(strorder, Area)
    dist = pcr.downstreamdist(ldd)
    # count nr of strorder cells in each area
    nr = pcr.areatotal(pcr.ifthen(strorder == strordermax, dist), Area)
    # N = pcr.sqrt(pcr.areatotal(pcr.scalar(pcr.boolean(Area)),Area))
    N = Clength
    factor = nr / N

    return factor
Example #10
0
    def set_river_package(self, discharge, currTimeStep):

        logger.info("Set the river package.")
        
        # - surface water river bed/bottom elevation and conductance 
        need_to_define_surface_water_bed = False
        if currTimeStep == None:
            # this is for a steady state simulation (no currTimeStep define)
            need_to_define_surface_water_bed = True
        else:    
            # only at the first month of the model simulation or the first month of the year
            if self.firstMonthOfSimulation or currTimeStep.month == 1:
                need_to_define_surface_water_bed = True
                self.firstMonthOfSimulation = False          # This part becomes False as we don't need it anymore. 

        if need_to_define_surface_water_bed:

            logger.info("Estimating the surface water bed elevation and surface water bed conductance.")
        
            #~ # - for lakes and resevoirs, alternative 1: make the bottom elevation deep --- Shall we do this? 
            #~ additional_depth = 500.
            #~ surface_water_bed_elevation = pcr.ifthen(pcr.scalar(self.WaterBodies.waterBodyIds) > 0.0, \
                                                     #~ self.dem_riverbed - additional_depth)
            #
            # - for lakes and resevoirs, estimate bed elevation from dem and bankfull depth
            surface_water_bed_elevation  = pcr.ifthen(pcr.scalar(self.WaterBodies.waterBodyIds) > 0.0, self.dem_average)
            surface_water_bed_elevation  = pcr.areaaverage(surface_water_bed_elevation, self.WaterBodies.waterBodyIds)
            surface_water_bed_elevation -= pcr.areamaximum(self.bankfull_depth, self.WaterBodies.waterBodyIds) 
            #
            surface_water_bed_elevation  = pcr.cover(surface_water_bed_elevation, self.dem_riverbed)
            #~ surface_water_bed_elevation = self.dem_riverbed # This is an alternative, if we do not want to introduce very deep bottom elevations of lakes and/or reservoirs.   
            #
            # rounding values for surface_water_bed_elevation
            self.surface_water_bed_elevation = pcr.roundup(surface_water_bed_elevation * 1000.)/1000.
            #
            # - river bed condutance (unit: m2/day)
            bed_surface_area = pcr.ifthen(pcr.scalar(self.WaterBodies.waterBodyIds) > 0.0, \
                                                     self.WaterBodies.fracWat * self.cellAreaMap)   # TODO: Incorporate the concept of dynamicFracWat # I have problem with the convergence if I use this one. 
            bed_surface_area = pcr.min(bed_surface_area,\
                               pcr.ifthen(pcr.scalar(self.WaterBodies.waterBodyIds) > 0.0, \
                                          pcr.areaaverage(self.bankfull_width * self.channelLength, self.WaterBodies.waterBodyIds)))
            bed_surface_area = pcr.cover(bed_surface_area, \
                                         self.bankfull_width * self.channelLength)
            #~ bed_surface_area = self.bankfull_width * self.channelLength
            bed_conductance = (1.0/self.bed_resistance) * bed_surface_area
            bed_conductance = pcr.ifthenelse(bed_conductance < 1e-20, 0.0, \
                                             bed_conductance) 
            self.bed_conductance = pcr.cover(bed_conductance, 0.0)
             

            logger.info("Estimating outlet widths of lakes and/or reservoirs.")
            # - 'channel width' for lakes and reservoirs 
            channel_width = pcr.areamaximum(self.bankfull_width, self.WaterBodies.waterBodyIds)
            self.channel_width = pcr.cover(channel_width, self.bankfull_width)
        

        logger.info("Estimating surface water elevation.")
        
        # - convert discharge value to surface water elevation (m)
        river_water_height = (self.channel_width**(-3/5)) * (discharge**(3/5)) * ((self.gradient)**(-3/10)) *(self.manningsN**(3/5))
        surface_water_elevation = self.dem_riverbed + \
                                  river_water_height
        #
        # - calculating water level (unit: m) above the flood plain   # TODO: Improve this concept (using Rens's latest innundation scheme) 
        #----------------------------------------------------------
        water_above_fpl  = pcr.max(0.0, surface_water_elevation - self.dem_floodplain)  # unit: m, water level above the floodplain (not distributed)
        water_above_fpl *= self.bankfull_depth * self.bankfull_width / self.cellAreaMap  # unit: m, water level above the floodplain (distributed within the cell)
        # TODO: Improve this concept using Rens's latest scheme
        #
        # - corrected surface water elevation
        surface_water_elevation = pcr.ifthenelse(surface_water_elevation > self.dem_floodplain, \
                                                                           self.dem_floodplain + water_above_fpl, \
                                                                           surface_water_elevation)
        # - surface water elevation for lakes and reservoirs:
        lake_reservoir_water_elevation = pcr.ifthen(self.WaterBodies.waterBodyOut, surface_water_elevation)
        lake_reservoir_water_elevation = pcr.areamaximum(lake_reservoir_water_elevation, self.WaterBodies.waterBodyIds)
        lake_reservoir_water_elevation = pcr.cover(lake_reservoir_water_elevation, \
                                         pcr.areaaverage(surface_water_elevation, self.WaterBodies.waterBodyIds))
        # - maximum and minimum values for lake_reservoir_water_elevation
        lake_reservoir_water_elevation = pcr.min(self.dem_floodplain, lake_reservoir_water_elevation)
        lake_reservoir_water_elevation = pcr.max(self.surface_water_bed_elevation, lake_reservoir_water_elevation)
        # - smoothing
        lake_reservoir_water_elevation = pcr.areaaverage(surface_water_elevation, self.WaterBodies.waterBodyIds)
        # 
        # - merge lake and reservoir water elevation
        surface_water_elevation = pcr.cover(lake_reservoir_water_elevation, surface_water_elevation)
        #
        # - covering the missing values and rounding
        surface_water_elevation = pcr.cover(surface_water_elevation, self.surface_water_bed_elevation)
        surface_water_elevation = pcr.rounddown(surface_water_elevation * 1000.)/1000.
        #
        # - make sure that HRIV >= RBOT ; no infiltration if HRIV = RBOT (and h < RBOT)  
        self.surface_water_elevation = pcr.max(surface_water_elevation, self.surface_water_bed_elevation)
        #
        # - pass the values to the RIV package 
        self.pcr_modflow.setRiver(self.surface_water_elevation, self.surface_water_bed_elevation, self.bed_conductance, 1)
Example #11
0
    def __init__(self):
        # Print model info
        print('The Spatial Processes in HYdrology (SPHY) model is')
        print(
            'developed and owned by FutureWater, Wageningen, The Netherlands')
        print('Version 3.0, released June 2019')
        print(' ')

        #-Missing value definition
        self.MV = -9999

        # Read the modules to be used
        self.GlacFLAG = config.getint('MODULES', 'GlacFLAG')
        self.SnowFLAG = config.getint('MODULES', 'SnowFLAG')
        self.RoutFLAG = config.getint('MODULES', 'RoutFLAG')
        self.ResFLAG = config.getint('MODULES', 'ResFLAG')
        self.LakeFLAG = config.getint('MODULES', 'LakeFLAG')
        self.DynVegFLAG = config.getint('MODULES', 'DynVegFLAG')
        self.GroundFLAG = config.getint('MODULES', 'GroundFLAG')
        self.SedFLAG = config.getint('MODULES', 'SedFLAG')
        self.SedTransFLAG = config.getint('MODULES', 'SedTransFLAG')

        # import the required modules
        import datetime, calendar, ET, rootzone, subzone
        import utilities.reporting as reporting
        import utilities.timecalc as timecalc
        import utilities.netcdf2PCraster as netcdf2PCraster
        from math import pi
        #-standard python modules
        self.datetime = datetime
        self.calendar = calendar
        self.pi = pi
        #-FW defined modules
        self.reporting = reporting
        self.timecalc = timecalc
        self.netcdf2PCraster = netcdf2PCraster
        self.ET = ET
        self.rootzone = rootzone
        self.subzone = subzone
        del datetime, calendar, pi, reporting, timecalc, ET, rootzone, subzone
        #-import additional modules if required
        if self.GlacFLAG == 1:
            self.SnowFLAG = 1
            self.GroundFLAG = 1

        #-read the input and output directories from the configuration file
        self.inpath = config.get('DIRS', 'inputdir')
        self.outpath = config.get('DIRS', 'outputdir')

        #-set the timing criteria
        sy = config.getint('TIMING', 'startyear')
        sm = config.getint('TIMING', 'startmonth')
        sd = config.getint('TIMING', 'startday')
        ey = config.getint('TIMING', 'endyear')
        em = config.getint('TIMING', 'endmonth')
        ed = config.getint('TIMING', 'endday')
        self.startdate = self.datetime.datetime(sy, sm, sd)
        self.enddate = self.datetime.datetime(ey, em, ed)
        self.dateAfterUpdate = self.startdate - self.datetime.timedelta(
            days=1
        )  #-only required for glacier retreat (create dummy value here to introduce the variable)

        #-set date input for reporting
        self.startYear = sy
        self.endYear = ey
        self.spinUpYears = config.getint('TIMING', 'spinupyears')
        self.simYears = self.endYear - self.startYear - self.spinUpYears + 1

        #-set the 2000 julian date number
        self.julian_date_2000 = 2451545
        #-read name of reporting table
        self.RepTab = config.get('REPORTING', 'RepTab')
        #-set the option to calculate the fluxes in mm for the upstream area
        self.mm_rep_FLAG = config.getint('REPORTING', 'mm_rep_FLAG')

        #-set the option to calculate the fluxes per component in mm for the upstream area
        pars = [
            'Prec', 'ETa', 'GMelt', 'QSNOW', 'QROOTR', 'QROOTD', 'QRAIN',
            'QGLAC', 'QBASE', 'QTOT', 'Seep'
        ]
        for i in pars:
            var = i + '_mm_FLAG'
            setattr(self, var, config.getint('REPORTING', var))

        #-set the option to calculate the timeseries of the water balance
        self.wbal_TSS_FLAG = config.getint('REPORTING', 'wbal_TSS_FLAG')

        #-setting clone map
        self.clonefile = self.inpath + config.get('GENERAL', 'mask')
        pcr.setclone(self.clonefile)
        self.clone = pcr.ifthen(pcr.readmap(self.clonefile), pcr.boolean(1))

        self.cellArea = pcr.cellvalue(pcr.cellarea(), 1)[0]

        #-read general maps
        self.DEM = pcr.readmap(self.inpath + config.get('GENERAL', 'dem'))
        self.Slope = pcr.readmap(self.inpath + config.get('GENERAL', 'Slope'))
        self.Locations = pcr.readmap(self.inpath +
                                     config.get('GENERAL', 'locations'))

        #-read soil calibration fractions
        self.RootFieldFrac = config.getfloat('SOIL_CAL', 'RootFieldFrac')
        self.RootSatFrac = config.getfloat('SOIL_CAL', 'RootSatFrac')
        self.RootDryFrac = config.getfloat('SOIL_CAL', 'RootDryFrac')
        self.RootWiltFrac = config.getfloat('SOIL_CAL', 'RootWiltFrac')
        self.RootKsatFrac = config.getfloat('SOIL_CAL', 'RootKsatFrac')

        #-read soil maps
        #-check for PedotransferFLAG
        self.PedotransferFLAG = config.getint('PEDOTRANSFER',
                                              'PedotransferFLAG')
        #-if pedotransfer functions are used read the sand, clay, organic matter and bulk density maps, otherwise read the soil hydraulic properties
        if self.PedotransferFLAG == 1:
            import utilities.pedotransfer
            self.pedotransfer = utilities.pedotransfer
            del utilities.pedotransfer

            #-read init processes pedotransfer
            self.pedotransfer.init(self, pcr, config, np)
        else:
            #self.Soil = pcr.readmap(self.inpath + config.get('SOIL','Soil'))
            self.RootFieldMap = pcr.readmap(self.inpath + config.get(
                'SOIL', 'RootFieldMap')) * self.RootFieldFrac
            self.RootSatMap = pcr.readmap(self.inpath + config.get(
                'SOIL', 'RootSatMap')) * self.RootSatFrac
            self.RootDryMap = pcr.readmap(self.inpath + config.get(
                'SOIL', 'RootDryMap')) * self.RootDryFrac
            self.RootWiltMap = pcr.readmap(self.inpath + config.get(
                'SOIL', 'RootWiltMap')) * self.RootWiltFrac
            self.RootKsat = pcr.readmap(self.inpath + config.get(
                'SOIL', 'RootKsat')) * self.RootKsatFrac
            self.SubSatMap = pcr.readmap(self.inpath +
                                         config.get('SOIL', 'SubSatMap'))
            self.SubFieldMap = pcr.readmap(self.inpath +
                                           config.get('SOIL', 'SubFieldMap'))
            self.SubKsat = pcr.readmap(self.inpath +
                                       config.get('SOIL', 'SubKsat'))
            self.RootDrainVel = self.RootKsat * self.Slope

        #-Read and set the soil parameters
        pars = ['CapRiseMax', 'RootDepthFlat', 'SubDepthFlat']
        for i in pars:
            try:
                setattr(self, i,
                        pcr.readmap(self.inpath + config.get('SOILPARS', i)))
            except:
                setattr(self, i, config.getfloat('SOILPARS', i))

        # groundwater storage as third storage layer. This is used instead of a fixed bottomflux
        if self.GroundFLAG == 1:
            import modules.groundwater
            self.groundwater = modules.groundwater
            del modules.groundwater

            #-read init processes groundwater
            self.groundwater.init(self, pcr, config)

        else:
            # if groundwater module is not used, read seepage and gwl_base
            self.SeepStatFLAG = config.getint('SOILPARS', 'SeepStatic')
            if self.SeepStatFLAG == 0:  # set the seepage map series
                self.Seepmaps = self.inpath + config.get('SOILPARS', 'SeePage')
            else:  #-set a static map or value for seepage
                try:
                    self.SeePage = pcr.readmap(
                        self.inpath + config.get('SOILPARS', 'SeePage'))
                except:
                    self.SeePage = config.getfloat('SOILPARS', 'SeePage')
            try:
                self.GWL_base = pcr.readmap(self.inpath +
                                            config.get('SOILPARS', 'GWL_base'))
            except:
                self.GWL_base = config.getfloat('SOILPARS', 'GWL_base')

            self.SubDrainVel = self.SubKsat * self.Slope

        #-calculate soil properties
        self.RootField = self.RootFieldMap * self.RootDepthFlat
        self.RootSat = self.RootSatMap * self.RootDepthFlat
        self.RootDry = self.RootDryMap * self.RootDepthFlat
        self.RootWilt = self.RootWiltMap * self.RootDepthFlat
        self.SubSat = self.SubSatMap * self.SubDepthFlat
        self.SubField = self.SubFieldMap * self.SubDepthFlat
        self.RootTT = pcr.max((self.RootSat - self.RootField) / self.RootKsat,
                              0.0001)
        self.SubTT = pcr.max((self.SubSat - self.SubField) / self.SubKsat,
                             0.0001)
        # soil max and soil min for scaling of gwl if groundwater module is not used
        if self.GroundFLAG == 0:
            self.SoilMax = self.RootSat + self.SubSat
            self.SoilMin = self.RootDry + self.SubField

        #-read land use map
        self.LandUse = pcr.readmap(self.inpath +
                                   config.get('LANDUSE', 'LandUse'))

        #-Use the dynamic vegetation module
        if self.DynVegFLAG == 1:
            #-import dynamic vegetation module
            import modules.dynamic_veg
            self.dynamic_veg = modules.dynamic_veg
            del modules.dynamic_veg

            #-read init processes dynamic vegetation
            self.dynamic_veg.init(self, pcr, config)
        #-read the crop coefficient table if the dynamic vegetation module is not used
        else:
            self.KcStatFLAG = config.getint('LANDUSE', 'KCstatic')
            if self.KcStatFLAG == 1:
                #-read land use map and kc table
                self.kc_table = self.inpath + config.get('LANDUSE', 'CropFac')
                self.Kc = pcr.lookupscalar(self.kc_table, self.LandUse)
            else:
                #-set the kc map series
                self.Kcmaps = self.inpath + config.get('LANDUSE', 'KC')

        #-read the p factor table if the plant water stress module is used
        self.PlantWaterStressFLAG = config.getint('PWS', 'PWS_FLAG')
        if self.PlantWaterStressFLAG == 1:
            PFactor = self.inpath + config.get('PWS', 'PFactor')
            self.PMap = pcr.lookupscalar(PFactor, self.LandUse)

        #-read and set glacier maps and parameters if glacier module is used
        if self.GlacFLAG:
            #-import glacier module
            import modules.glacier
            self.glacier = modules.glacier
            del modules.glacier

            #-read init processes glacier module
            self.glacier.init(self, pcr, config, pd, np, os)

        #-read and set snow maps and parameters if snow modules are used
        if self.SnowFLAG == 1:
            #-import snow module
            import modules.snow
            self.snow = modules.snow
            del modules.snow

            #-read init processes glacier module
            self.snow.init(self, pcr, config)

        #-read and set climate forcing and the calculation of etref

        #-read precipitation data
        #-read flag for precipitation forcing by netcdf
        self.precNetcdfFLAG = config.getint('CLIMATE', 'precNetcdfFLAG')
        if self.precNetcdfFLAG == 1:
            #-read configuration for forcing by netcdf
            self.netcdf2PCraster.getConfigNetcdf(self, config, 'Prec',
                                                 'CLIMATE')

            #-determine x,y-coordinates of netcdf file and model domain and indices of netcdf corresponding to model domain
            self.netcdf2PCraster.netcdf2pcrInit(self, pcr, 'Prec')
        else:
            #-read precipitation forcing folder
            self.Prec = self.inpath + config.get('CLIMATE', 'Prec')

        #-read precipitation data
        #-read flag for temperature forcing by netcdf
        self.tempNetcdfFLAG = config.getint('CLIMATE', 'tempNetcdfFLAG')
        if self.tempNetcdfFLAG == 1:
            #-read configuration for forcing by netcdf
            self.netcdf2PCraster.getConfigNetcdf(self, config, 'Temp',
                                                 'CLIMATE')

            #-determine x,y-coordinates of netcdf file and model domain and indices of netcdf corresponding to model domain
            self.netcdf2PCraster.netcdf2pcrInit(self, pcr, 'Temp')
        else:
            #-read temperature forcing folder
            self.Tair = self.inpath + config.get('CLIMATE', 'Tair')
        #-read flag for etref time series input
        self.ETREF_FLAG = config.getint('ETREF', 'ETREF_FLAG')
        #-determine the use of a given etref time-series or calculate etref using Hargreaves
        if self.ETREF_FLAG == 1:
            self.ETref = self.inpath + config.get('ETREF', 'ETref')
        else:
            self.Lat = pcr.readmap(self.inpath + config.get('ETREF', 'Lat'))
            #-read flag for minimum temperature forcing by netcdf
            self.TminNetcdfFLAG = config.getint('ETREF', 'TminNetcdfFLAG')
            if self.TminNetcdfFLAG == 1:
                #-read configuration for forcing by netcdf
                self.netcdf2PCraster.getConfigNetcdf(self, config, 'Tmin',
                                                     'ETREF')

                #-determine x,y-coordinates of netcdf file and model domain and indices of netcdf corresponding to model domain
                self.netcdf2PCraster.netcdf2pcrInit(self, pcr, 'Tmin')
            else:
                self.Tmin = self.inpath + config.get('ETREF', 'Tmin')
            #-read flag for maximum temperature forcing by netcdf
            self.TmaxNetcdfFLAG = config.getint('ETREF', 'TmaxNetcdfFLAG')
            if self.TmaxNetcdfFLAG == 1:
                #-read configuration for forcing by netcdf
                self.netcdf2PCraster.getConfigNetcdf(self, config, 'Tmax',
                                                     'ETREF')

                #-determine x,y-coordinates of netcdf file and model domain and indices of netcdf corresponding to model domain
                self.netcdf2PCraster.netcdf2pcrInit(self, pcr, 'Tmax')
            else:
                self.Tmax = self.inpath + config.get('ETREF', 'Tmax')
            self.Gsc = config.getfloat('ETREF', 'Gsc')
            import hargreaves
            self.Hargreaves = hargreaves
            del hargreaves

        #-read and set routing maps and parameters
        if self.RoutFLAG == 1:
            import modules.routing
            self.routing = modules.routing
            del modules.routing

            #-read init processes routing
            self.routing.init(self, pcr, config)

        #-read and set routing maps and parameters
        if self.ResFLAG == 1 or self.LakeFLAG == 1:
            #-import advanced routing module
            import modules.advanced_routing
            self.advanced_routing = modules.advanced_routing
            del modules.advanced_routing

            #-read init processes advanced routing
            self.advanced_routing.init(self, pcr, config)

        #-read lake maps and parameters if lake module is used
        if self.LakeFLAG == 1:
            #-import lakes module
            import modules.lakes
            self.lakes = modules.lakes
            del modules.lakes

            #-read init processes lakes
            self.lakes.init(self, pcr, config)

        #-read reservior maps and parameters if reservoir module is used
        if self.ResFLAG == 1:
            #-import reservoirs module
            import modules.reservoirs
            self.reservoirs = modules.reservoirs
            del modules.reservoirs

            #-read init processes reservoirs
            self.reservoirs.init(self, pcr, config)

        #-read flag for calculation of ET in reservoirs
        self.ETOpenWaterFLAG = config.getint('OPENWATER', 'ETOpenWaterFLAG')
        if self.ETOpenWaterFLAG == 1:
            #-read kc value for open water
            self.kcOpenWater = config.getfloat('OPENWATER', 'kcOpenWater')
            #-read openwater fraction map
            self.openWaterFrac = pcr.readmap(
                self.inpath + config.get('OPENWATER', 'openWaterFrac'))
            #-determine openwater map with values of each reservoir/lake in the extent of the openwater
            self.openWater = pcr.ifthenelse(self.openWaterFrac > 0,
                                            pcr.scalar(1), pcr.scalar(0))
            self.openWaterNominal = pcr.clump(pcr.nominal(self.openWater))
            self.openWaterNominal = pcr.nominal(
                pcr.areamaximum(pcr.scalar(self.ResID), self.openWaterNominal))
        else:
            #-set all cells to 0 for openwater fraction map
            self.openWaterFrac = self.DEM * 0
            self.openWater = 0
            self.ETOpenWater = 0

        #-read maps and parameters for infiltration excess
        self.InfilFLAG = config.getfloat('INFILTRATION', 'Infil_excess')
        if self.InfilFLAG == 1:
            self.K_eff = config.getfloat('INFILTRATION', 'K_eff')
            try:
                self.Alpha = config.getfloat('INFILTRATION', 'Alpha')
            except:
                self.Alpha = pcr.readmap(self.inpath +
                                         config.get('INFILTRATION', 'Alpha'))
            try:
                self.Labda_Infil = config.getfloat('INFILTRATION',
                                                   'Labda_infil')
            except:
                self.Labda_Infil = pcr.readmap(
                    self.inpath + config.get('INFILTRATION', 'Labda_infil'))
            try:
                self.paved_table = self.inpath + config.get(
                    'INFILTRATION', 'PavedFrac')
                self.pavedFrac = pcr.lookupscalar(self.paved_table,
                                                  self.LandUse)
            except:
                self.pavedFrac = 0

        #-read maps and parameters for soil erosion
        if self.SedFLAG == 1:
            #-read soil erosion model selector (1 for MUSLE, 2 for MMF)
            self.SedModel = config.getfloat('SEDIMENT', 'SedModel')

            #-read rock fraction map
            self.RockFrac = pcr.readmap(self.inpath +
                                        config.get('SEDIMENT', 'RockFrac'))

            #-read MUSLE input parameters
            if self.SedModel == 1:
                #-import musle module
                import modules.musle
                self.musle = modules.musle
                del modules.musle

                #-read init processes musle
                self.musle.init(self, pcr, config)

            #-read MMF input parameters
            if self.SedModel == 2:
                #-import mmf module
                import modules.mmf
                self.mmf = modules.mmf
                del modules.mmf

                #-read init processes mmf
                self.mmf.init(self, pcr, config)

            #-read input parameters for sediment transport
            if self.SedTransFLAG == 1:
                #-import sediment transport module
                import modules.sediment_transport
                self.sediment_transport = modules.sediment_transport
                del modules.sediment_transport

                #-read init processes sediment transport
                self.sediment_transport.init(self, pcr, config, csv, np)

        #-set the global option for radians
        pcr.setglobaloption('radians')
Example #12
0
    def getReservoirOutflow(self,\
        avgChannelDischarge,length_of_time_step,downstreamDemand):

        # avgOutflow (m3/s)
        avgOutflow = self.avgOutflow
        # The following is needed when new lakes/reservoirs introduced (its avgOutflow is still zero).
        #~ # - alternative 1
        #~ avgOutflow = pcr.ifthenelse(\
        #~ avgOutflow > 0.,\
        #~ avgOutflow,
        #~ pcr.max(avgChannelDischarge, self.avgInflow, 0.001))
        # - alternative 2
        avgOutflow = pcr.ifthenelse(\
                     avgOutflow > 0.,\
                     avgOutflow,
                     pcr.max(avgChannelDischarge, self.avgInflow))
        avgOutflow = pcr.ifthenelse(\
                     avgOutflow > 0.,\
                     avgOutflow, pcr.downstream(self.lddMap, avgOutflow))
        avgOutflow = pcr.areamaximum(avgOutflow, self.waterBodyIds)

        # calculate resvOutflow (m2/s) (based on reservoir storage and avgDischarge):
        # - using reductionFactor in such a way that:
        #   - if relativeCapacity < minResvrFrac : release is terminated
        #   - if relativeCapacity > maxResvrFrac : longterm average
        reductionFactor = \
         pcr.cover(\
         pcr.min(1.,
         pcr.max(0., \
          self.waterBodyStorage - self.minResvrFrac*self.waterBodyCap)/\
             (self.maxResvrFrac - self.minResvrFrac)*self.waterBodyCap),0.0)
        #
        resvOutflow = reductionFactor * avgOutflow * length_of_time_step  # unit: m3

        # maximum release <= average inflow (especially during dry condition)
        resvOutflow = pcr.max(0,
                              pcr.min(resvOutflow, self.avgInflow *
                                      length_of_time_step))  # unit: m3

        # downstream demand (m3/s)
        # reduce demand if storage < lower limit
        reductionFactor = vos.getValDivZero(
            downstreamDemand, self.minResvrFrac * self.waterBodyCap,
            vos.smallNumber)
        reductionFactor = pcr.cover(reductionFactor, 0.0)
        downstreamDemand = pcr.min(downstreamDemand,
                                   downstreamDemand * reductionFactor)
        # resvOutflow > downstreamDemand
        resvOutflow = pcr.max(resvOutflow, downstreamDemand *
                              length_of_time_step)  # unit: m3

        # floodOutflow: additional release if storage > upper limit
        ratioQBankfull = 2.3
        estmStorage = pcr.max(0., self.waterBodyStorage - resvOutflow)
        floodOutflow = \
           pcr.max(0.0, estmStorage - self.waterBodyCap) +\
           pcr.cover(\
           pcr.max(0.0, estmStorage - self.maxResvrFrac*\
                                      self.waterBodyCap)/\
              ((1.-self.maxResvrFrac)*self.waterBodyCap),0.0)*\
           pcr.max(0.0,ratioQBankfull*avgOutflow* vos.secondsPerDay()-\
                                      resvOutflow)
        floodOutflow = pcr.max(0.0,
                       pcr.min(floodOutflow,\
                       estmStorage - self.maxResvrFrac*\
                                     self.waterBodyCap*0.75)) # maximum limit of floodOutflow: bring the reservoir storages only to 3/4 of upper limit capacities

        # update resvOutflow after floodOutflow
        resvOutflow  = pcr.cover(resvOutflow , 0.0) +\
                       pcr.cover(floodOutflow, 0.0)

        # maximum release if storage > upper limit : bring the reservoir storages only to 3/4 of upper limit capacities
        resvOutflow  = pcr.ifthenelse(self.waterBodyStorage >
                       self.maxResvrFrac*self.waterBodyCap,\
                       pcr.min(resvOutflow,\
                       pcr.max(0,self.waterBodyStorage - \
                       self.maxResvrFrac*self.waterBodyCap*0.75)),
                       resvOutflow)

        # if storage > upper limit : resvOutflow > avgInflow
        resvOutflow  = pcr.ifthenelse(self.waterBodyStorage >
                       self.maxResvrFrac*self.waterBodyCap,\
                       pcr.max(0.0, resvOutflow, self.avgInflow),
                       resvOutflow)

        # resvOutflow < waterBodyStorage
        resvOutflow = pcr.min(self.waterBodyStorage, resvOutflow)

        resvOutflow = pcr.ifthen(
            pcr.scalar(self.waterBodyIds) > 0., resvOutflow)
        resvOutflow = pcr.ifthen(
            pcr.scalar(self.waterBodyTyp) == 2, resvOutflow)
        return (resvOutflow)  # unit: m3
Example #13
0
    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)
Example #14
0
    def initial(self):
        """ initial part of the water abstraction module
        """

        # self.testmap=windowaverage(self.var.Elevation,5)
        # self.report(self.testmap,"test.map")

        # ************************************************************
        # ***** WATER USE
        # ************************************************************
        settings = LisSettings.instance()
        option = settings.options
        binding = settings.binding
        maskinfo = MaskInfo.instance()
        if option['wateruse']:
            self.var.WUsePercRemain = loadmap('WUsePercRemain')
            self.var.NoWaterUseSteps = int(loadmap('maxNoWateruse'))
            self.var.GroundwaterBodies = loadmap('GroundwaterBodies')
            self.var.FractionGroundwaterUsed = np.minimum(
                np.maximum(loadmap('FractionGroundwaterUsed'),
                           maskinfo.in_zero()), 1.0)
            self.var.FractionNonConventionalWaterUsed = loadmap(
                'FractionNonConventionalWaterUsed')
            self.var.FractionLakeReservoirWaterUsed = loadmap(
                'FractionLakeReservoirWaterUsed')
            self.var.EFlowThreshold = loadmap('EFlowThreshold')
            # EFlowThreshold is map with m3/s discharge, e.g. the 10th percentile discharge of the baseline run

            self.var.WUseRegionC = loadmap('WUseRegion').astype(int)
            self.var.IrrigationMult = loadmap('IrrigationMult')

            # ************************************************************
            # ***** water use constant maps ******************************
            # ************************************************************

            self.var.IndustryConsumptiveUseFraction = loadmap(
                'IndustryConsumptiveUseFraction')
            # fraction (0-1)
            self.var.WaterReUseFraction = loadmap('WaterReUseFraction')
            # fraction of water re-used (0-1)
            self.var.EnergyConsumptiveUseFraction = loadmap(
                'EnergyConsumptiveUseFraction')
            # fraction (0-1), value depends on cooling technology of power plants
            self.var.LivestockConsumptiveUseFraction = loadmap(
                'LivestockConsumptiveUseFraction')
            # fraction (0-1)
            self.var.LeakageFraction = np.minimum(
                np.maximum(
                    loadmap('LeakageFraction') *
                    (1 - loadmap('LeakageReductionFraction')),
                    maskinfo.in_zero()), 1.0)
            self.var.DomesticLeakageConstant = np.minimum(
                np.maximum(1 / (1 - self.var.LeakageFraction),
                           maskinfo.in_zero()), 1.0)
            # Domestic Water Abstraction becomes larger in case of leakage
            # LeakageFraction is LeakageFraction (0-1) multiplied by reduction scenario (10% reduction is 0.1 in map)
            # 0.65 leakage and 0.1 reduction leads to 0.585 effective leakage, resulting in 2.41 times more water abstraction
            self.var.DomesticWaterSavingConstant = np.minimum(
                np.maximum(1 - loadmap('WaterSavingFraction'),
                           maskinfo.in_zero()), 1.0)
            # Domestic water saving if in place, changes this value from 1 to a value between 0 and 1, and will reduce demand and abstraction
            # so value = 0.9 if WaterSavingFraction equals 0.1 (10%)
            self.var.DomesticConsumptiveUseFraction = loadmap(
                'DomesticConsumptiveUseFraction')
            # fraction (0-1), typically rather low ~ 0.10
            self.var.LeakageWaterLossFraction = loadmap('LeakageWaterLoss')
            # fraction (0-1), 0=no leakage

            # Initialize water demand. Read from a static map either value or pcraster map or netcdf (single or stack).
            # If reading from NetCDF stack, get time step corresponding to model step.
            # Added management for sub-daily modelling time steps
            # Added possibility to use one single average year to be repeated during the simulation
            if option['useWaterDemandAveYear']:
                # CM: using one water demand average year throughout the model simulation
                self.var.DomesticDemandMM = loadmap(
                    'DomesticDemandMaps',
                    timestampflag='closest',
                    averageyearflag=True) * self.var.DtDay
                self.var.IndustrialDemandMM = loadmap(
                    'IndustrialDemandMaps',
                    timestampflag='closest',
                    averageyearflag=True) * self.var.DtDay
                self.var.LivestockDemandMM = loadmap(
                    'LivestockDemandMaps',
                    timestampflag='closest',
                    averageyearflag=True) * self.var.DtDay
                self.var.EnergyDemandMM = loadmap(
                    'EnergyDemandMaps',
                    timestampflag='closest',
                    averageyearflag=True) * self.var.DtDay
            else:
                # CM: using information on water demand from NetCDF files
                self.var.DomesticDemandMM = loadmap(
                    'DomesticDemandMaps',
                    timestampflag='closest') * self.var.DtDay
                self.var.IndustrialDemandMM = loadmap(
                    'IndustrialDemandMaps',
                    timestampflag='closest') * self.var.DtDay
                self.var.LivestockDemandMM = loadmap(
                    'LivestockDemandMaps',
                    timestampflag='closest') * self.var.DtDay
                self.var.EnergyDemandMM = loadmap(
                    'EnergyDemandMaps',
                    timestampflag='closest') * self.var.DtDay

            # Check consistency with the reference calendar that is read from the precipitation forcing file (global_modules.zusatz.optionBinding)
            if option['TransientWaterDemandChange'] and option[
                    'readNetcdfStack']:
                for k in ('DomesticDemandMaps', 'IndustrialDemandMaps',
                          'LivestockDemandMaps', 'EnergyDemandMaps'):
                    with Dataset(binding[k] + '.nc') as nc:
                        cal_type = get_calendar_type(nc)
                        if cal_type != binding['calendar_type']:
                            warnings.warn(
                                calendar_inconsistency_warning(
                                    binding[k], cal_type,
                                    binding['calendar_type']))

            if option['groundwaterSmooth']:
                self.var.GroundwaterBodiesPcr = decompress(
                    self.var.GroundwaterBodies)
                self.var.groundwaterCatch = boolean(
                    decompress((self.var.GroundwaterBodies *
                                self.var.Catchments).astype(int)))
                # nominal(scalar(GroundwaterBodies)*scalar(self.var.Catchments));
                # smoothing for groundwater to correct error by using windowtotal, based on groundwater bodies and catchments
                self.var.LZSmoothRange = loadmap('LZSmoothRange')

            if option['wateruseRegion']:
                WUseRegion = nominal(loadmap('WUseRegion', pcr=True))
                pitWuse1 = ifthen(self.var.AtLastPoint != 0, boolean(1))
                pitWuse1b = ifthen(defined(pitWuse1), WUseRegion)
                # use every existing pit in the Ldd and number them by the water regions
                # coastal water regions can have more than one pit per water region

                pitWuseMax = areamaximum(self.var.UpArea, WUseRegion)
                pitWuse2 = ifthen(pitWuseMax == self.var.UpArea, WUseRegion)
                # search outlets in the inland water regions by using the maximum  upstream area as criterium

                pitWuse3 = downstream(self.var.LddStructuresKinematic,
                                      WUseRegion)
                pitWuse3b = ifthen(pitWuse3 != WUseRegion, WUseRegion)
                # search point where ldd leaves a water region

                pitWuse = cover(pitWuse1b, pitWuse2, pitWuse3b, nominal(0))
                # join all sources of pits

                LddWaterRegion = lddrepair(
                    ifthenelse(pitWuse == 0, self.var.LddStructuresKinematic,
                               5))
                # create a Ldd with pits at every water region outlet
                # this results in a interrupted ldd, so water cannot be transfered to the next water region
                lddC = compressArray(LddWaterRegion)
                inAr = decompress(
                    np.arange(maskinfo.info.mapC[0], dtype="int32"))
                # giving a number to each non missing pixel as id
                self.var.downWRegion = (compressArray(
                    downstream(LddWaterRegion, inAr))).astype(np.int32)
                # each upstream pixel gets the id of the downstream pixel
                self.var.downWRegion[lddC == 5] = maskinfo.info.mapC[0]
                # all pits gets a high number

                # ************************************************************
                # ***** OUTFLOW AND INFLOW POINTS FOR WATER REGIONS **********
                # ************************************************************

                self.var.WaterRegionOutflowPoints = ifthen(
                    pitWuse != 0, boolean(1))
                # outflowpoints to calculate upstream inflow for balances and Water Exploitation Index
                # both inland outflowpoints to downstream subbasin, and coastal outlets

                WaterRegionInflow1 = boolean(
                    upstream(
                        self.var.LddStructuresKinematic,
                        cover(scalar(self.var.WaterRegionOutflowPoints), 0)))
                self.var.WaterRegionInflowPoints = ifthen(
                    WaterRegionInflow1, boolean(1))
                # inflowpoints to calculate upstream inflow for balances and Water Exploitation Index
            else:
                self.var.downWRegion = self.var.downstruct.copy()
                self.var.downWRegion = self.var.downWRegion.astype(np.int32)

            # ************************************************************
            # ***** Initialising cumulative output variables *************
            # ************************************************************

            # These are all needed to compute the cumulative mass balance error
            self.var.wateruseCum = maskinfo.in_zero()
            # water use cumulated amount
            self.var.WUseAddM3Dt = maskinfo.in_zero()
            self.var.WUseAddM3 = maskinfo.in_zero()

            self.var.IrriLossCUM = maskinfo.in_zero()
            # Cumulative irrigation loss [mm]
            # Cumulative abstraction from surface water [mm]

            self.var.TotalAbstractionFromSurfaceWaterM3 = maskinfo.in_zero()
            self.var.TotalAbstractionFromGroundwaterM3 = maskinfo.in_zero()
            self.var.TotalIrrigationAbstractionM3 = maskinfo.in_zero()
            self.var.TotalPaddyRiceIrrigationAbstractionM3 = maskinfo.in_zero()
            self.var.TotalLivestockAbstractionM3 = maskinfo.in_zero()

            self.var.IrrigationType = loadmap('IrrigationType')
            self.var.IrrigationEfficiency = loadmap('IrrigationEfficiency')
            self.var.ConveyanceEfficiency = loadmap('ConveyanceEfficiency')

            self.var.GroundwaterRegionPixels = np.take(
                np.bincount(self.var.WUseRegionC,
                            weights=self.var.GroundwaterBodies),
                self.var.WUseRegionC)
            self.var.AllRegionPixels = np.take(
                np.bincount(self.var.WUseRegionC,
                            weights=self.var.GroundwaterBodies * 0.0 + 1.0),
                self.var.WUseRegionC)
            self.var.RatioGroundWaterUse = self.var.AllRegionPixels / (
                self.var.GroundwaterRegionPixels + 0.01)
            self.var.FractionGroundwaterUsed = np.minimum(
                self.var.FractionGroundwaterUsed *
                self.var.RatioGroundWaterUse,
                1 - self.var.FractionNonConventionalWaterUsed)
            # FractionGroundwaterUsed is a percentage given at national scale
            # since the water needs to come from the GroundwaterBodies pixels,
            # the fraction needs correction for the non-Groundwaterbodies; this is done here
            self.var.EFlowIndicator = maskinfo.in_zero()
            self.var.ReservoirAbstractionM3 = maskinfo.in_zero()
            self.var.PotentialSurfaceWaterAvailabilityForIrrigationM3 = maskinfo.in_zero(
            )
            self.var.LakeAbstractionM3 = maskinfo.in_zero()
            self.var.FractionAbstractedFromChannels = maskinfo.in_zero()
            self.var.AreatotalIrrigationUseM3 = maskinfo.in_zero()
            self.var.totalAddM3 = maskinfo.in_zero()
            self.var.TotalDemandM3 = maskinfo.in_zero()
Example #15
0
 def dynamic(self):
     #####################
     # * dynamic section #
     #####################
     #-evaluation of the current date: return current month and the time step used
     #-reading in fluxes over land and water area for current time step [m/d]
     # and read in reservoir demand and surface water extraction [m3]
     try:
         self.landSurfaceQ = clippedRead.get(
             pcrm.generateNameT(landSurfaceQFileName,
                                self.currentTimeStep()))
     except:
         pass
     try:
         self.potWaterSurfaceQ = clippedRead.get(
             pcrm.generateNameT(waterSurfaceQFileName,
                                self.currentTimeStep()))
     except:
         pass
     #-surface water extraction and reservoir demand currently set to zero, should
     # be computed automatically and updated to reservoirs
     self.potSurfaceWaterExtraction = pcr.spatial(pcr.scalar(0.))
     #self.waterBodies.demand=  #self.reservoirDemandTSS.assignID(self.waterBodies.ID,self.currentTimeStep(),0.)*self.timeSec
     #-initialization of cumulative values of actual water extractions
     self.actWaterSurfaceQ = pcr.spatial(pcr.scalar(0.))
     self.actSurfaceWaterExtraction = pcr.spatial(pcr.scalar(0.))
     #-definition of sub-loop for routing scheme - explicit scheme has to satisfy Courant condition
     timeLimit= pcr.cellvalue(pcr.mapminimum((pcr.cover(pcr.ifthen(self.waterBodies.distribution == 0,\
      self.channelLength/self.flowVelocity),\
       self.timeSec/self.nrIterDefault)*self.timeSec/self.nrIterDefault)**0.5),1)[0]
     nrIter = int(self.timeSec / timeLimit)
     nrIter = min(nrIter, int(self.timeSec / 300.))
     while float(self.timeSec / nrIter) % 1 <> 0:
         nrIter += 1
     deltaTime = self.timeSec / nrIter
     #-sub-loop for current time step
     if self.currentDate.day == 1 or nrIter >= 24:
         print '\n*\tprocessing %s, currently using %d substeps of %d seconds\n' % \
          (self.currentDate.date(),nrIter,deltaTime)
     #-update discharge and storage
     for nrICur in range(nrIter):
         #-initializing discharge for the current sub-timestep and fill in values
         # for channels and at outlets of waterbodies
         # * channels *
         estQ= pcr.ifthenelse((self.actualStorage > 0.) & (self.waterBodies.distribution == 0) ,\
          (self.wettedArea/self.alphaQ)**(1./self.betaQ),0.)
         #estQ= pcr.ifthenelse((self.actualStorage > 0.) & (self.waterBodies.distribution == 0) ,\
         #0.5*(self.Q+(self.wettedArea/self.alphaQ)**(1./self.betaQ)),0.)
         #estQ= pcr.min(estQ,self.actualStorage/deltaTime)
         self.report(estQ, 'results/qest')
         self.Q = pcr.spatial(pcr.scalar(0.))
         self.Q= pcr.ifthenelse(self.waterBodies.distribution == 0,\
          pcr.kinematic(self.channelLDD,estQ,0.,self.alphaQ,\
           self.betaQ,1,deltaTime,self.channelLength),self.Q)
         # * water bodies *
         self.waterBodies.dischargeUpdate()
         self.Q = self.waterBodies.returnMapValue(self.Q,
                                                  self.waterBodies.actualQ)
         #-fluxes and resulting change in storage: first the local fluxes are evaluated
         # and aggregated over the water bodies where applicable; this includes the specific runoff [m/day/m2]
         # from input and the estimated extraction from surface water as volume per day [m3/day];
         # specific runoff from the land surface is always positive whereas the fluxes over the water surface
         # are potential, including discharge, and are adjusted to match the availabe storage; to this end,
         # surface water storage and fluxes over water bodies are totalized and assigned to the outlet;
         # discharge is updated in a separate step, after vertical fluxes are compared to the actual storage
         deltaActualStorage= ((self.landFraction*self.landSurfaceQ+\
          self.waterFraction*self.potWaterSurfaceQ)*self.cellArea-\
          self.potSurfaceWaterExtraction)*float(self.duration)/nrIter
         deltaActualStorage= pcr.ifthenelse(self.waterBodies.distribution != 0,\
          pcr.ifthenelse(self.waterBodies.location != 0,\
           pcr.areatotal(deltaActualStorage,self.waterBodies.distribution),0),\
            deltaActualStorage)
         adjustmentRatio= pcr.ifthenelse(deltaActualStorage < 0.,\
          pcr.min(1.,-self.actualStorage/deltaActualStorage),1.)
         self.actWaterSurfaceQ += adjustmentRatio * self.potWaterSurfaceQ
         self.actSurfaceWaterExtraction += adjustmentRatio * self.actSurfaceWaterExtraction
         deltaActualStorage *= adjustmentRatio
         #-local water balance check
         if testLocalWaterBalance:
             differenceActualStorage = self.actualStorage
             differenceActualStorage += deltaActualStorage
         #-overall water balance check: net input
         self.cumulativeDeltaStorage += pcr.catchmenttotal(
             deltaActualStorage, self.LDD)
         #-update storage first with local changes, then balance discharge with storage and update storage
         # with lateral flow and return value to water bodies
         self.actualStorage += deltaActualStorage
         self.actualStorage = pcr.max(0., self.actualStorage)
         self.Q = pcr.min(self.Q, self.actualStorage / deltaTime)
         deltaActualStorage = (-self.Q +
                               pcr.upstream(self.LDD, self.Q)) * deltaTime
         deltaActualStorage= pcr.ifthenelse(self.waterBodies.distribution != 0,\
          pcr.ifthenelse(self.waterBodies.location != 0,\
           pcr.areatotal(deltaActualStorage,self.waterBodies.distribution),0),\
            deltaActualStorage)
         self.actualStorage += deltaActualStorage
         self.actualStorage = pcr.max(0., self.actualStorage)
         self.waterBodies.actualStorage = self.waterBodies.retrieveMapValue(
             self.actualStorage)
         #-flooded fraction returned
         floodedFraction,floodedDepth,\
           self.wettedArea,self.alphaQ= self.kinAlphaComposite(self.actualStorage,self.floodplainMask)
         self.wettedArea= self.waterBodies.returnMapValue(self.wettedArea,\
          self.waterBodies.channelWidth+2.*self.waterBodies.updateWaterHeight())
         self.waterFraction= pcr.ifthenelse(self.waterBodies.distribution == 0,\
          pcr.max(self.waterFractionMask,floodedFraction),self.waterFractionMask)
         self.landFraction = pcr.max(0., 1. - self.waterFraction)
         self.flowVelocity = pcr.ifthenelse(self.wettedArea > 0,
                                            self.Q / self.wettedArea, 0.)
         #-local water balance check
         if testLocalWaterBalance:
             differenceActualStorage += deltaActualStorage
             differenceActualStorage -= self.actualStorage
             totalDifference = pcr.cellvalue(
                 pcr.maptotal(differenceActualStorage), 1)[0]
             minimumDifference = pcr.cellvalue(
                 pcr.mapminimum(differenceActualStorage), 1)[0]
             maximumDifference = pcr.cellvalue(
                 pcr.mapmaximum(differenceActualStorage), 1)[0]
             if abs(totalDifference) > 1.e-3:
                 print 'water balance error: total %e; min %e; max %e' %\
                  (totalDifference,minimumDifference,maximumDifference)
                 if reportLocalWaterBalance:
                     pcr.report(differenceActualStorage,
                                'mbe_%s.map' % self.currentDate.date())
         #-overall water balance check: updating cumulative discharge and total storage [m3]
         self.totalDischarge += self.Q * deltaTime
         self.totalStorage = pcr.catchmenttotal(self.actualStorage,
                                                self.LDD)
     #-check on occurrence of last day and report mass balance
     if self.currentDate == self.endDate:
         #-report initial maps
         pcr.report(self.Q, self.QIniMap)
         pcr.report(self.actualStorage, self.actualStorageIniMap)
         #-return relative and absolute water balance error per cell and
         # as total at basin outlets
         self.totalDischarge= pcr.ifthen((self.waterBodies.distribution == 0) | \
          (self.waterBodies.location != 0),self.totalDischarge)
         self.cumulativeDeltaStorage= pcr.ifthen((self.waterBodies.distribution == 0) | \
          (self.waterBodies.location != 0),self.cumulativeDeltaStorage)
         massBalanceError= self.totalStorage+self.totalDischarge-\
          self.cumulativeDeltaStorage
         relMassBalanceError = 1. + pcr.ifthenelse(
             self.cumulativeDeltaStorage <> 0.,
             massBalanceError / self.cumulativeDeltaStorage, 0.)
         totalMassBalanceError= pcr.cellvalue(pcr.maptotal(pcr.ifthen(self.basinOutlet,\
          massBalanceError)),1)[0]
         totalCumulativeDeltaStorage= pcr.cellvalue(pcr.maptotal(pcr.ifthen(self.basinOutlet,\
          self.cumulativeDeltaStorage)),1)[0]
         if totalCumulativeDeltaStorage > 0:
             totalRelativeMassBalanceError = 1. + totalMassBalanceError / totalCumulativeDeltaStorage
         else:
             totalRelativeMassBalanceError = 1.
         #-report maps and echo value
         pcr.report(massBalanceError, mbeFileName)
         pcr.report(relMassBalanceError, mbrFileName)
         print '\n*\ttotal global mass balance error [m3]: %8.3g' % totalMassBalanceError
         print '\n*\trelative global mass balance error [-]: %5.3f' % totalRelativeMassBalanceError
         #-echo to screen: total mass balance error and completion of run
         print '\trun completed'
     #-end of day: return states and fluxes
     #-get surface water attributes?
     if getSurfaceWaterAttributes:
         #-compute the following secondary variables:
         # surface water area [m2]: area given dynamic surface water fraction
         # residence time [days]: volume over discharge, assigned -1 in case discharge is zero
         # surface water depth [m], weighed by channel and floodplain volume
         surfaceWaterArea = self.waterFraction * self.cellArea
         surfaceWaterArea= pcr.ifthenelse(self.waterBodies.distribution != 0,\
           pcr.ifthenelse(self.waterBodies.location != 0,\
            pcr.areatotal(surfaceWaterArea,self.waterBodies.distribution),0),\
             surfaceWaterArea)
         surfaceWaterResidenceTime = pcr.ifthenelse(
             self.Q > 0., self.actualStorage / (self.Q * self.timeSec), -1)
         surfaceWaterDepth= pcr.ifthenelse(self.actualStorage > 0.,\
          pcr.max(0.,self.actualStorage-self.channelStorageCapacity)**2/\
           (self.actualStorage*surfaceWaterArea),0.)
         surfaceWaterDepth+= pcr.ifthenelse(self.actualStorage > 0.,\
          pcr.min(self.channelStorageCapacity,self.actualStorage)**2/(self.waterFractionMask*\
          self.cellArea*self.actualStorage),0.)
         #-reports: values at outlet of lakes or reservoirs are assigned to their full extent
         self.report(pcr.ifthenelse(self.waterBodies.distribution != 0,\
          pcr.areamaximum(surfaceWaterArea,self.waterBodies.distribution),surfaceWaterArea),\
           surfaceWaterAreaFileName)
         self.report(pcr.ifthenelse(self.waterBodies.distribution != 0,\
          pcr.areamaximum(surfaceWaterResidenceTime,self.waterBodies.distribution),surfaceWaterResidenceTime),\
           surfaceWaterResidenceTimeFileName)
         self.report(pcr.ifthenelse(self.waterBodies.distribution != 0,\
          pcr.areamaximum(surfaceWaterDepth,self.waterBodies.distribution),surfaceWaterDepth),\
           surfaceWaterDepthFileName)
     #-reports on standard output: values at outlet of lakes or reservoirs are assigned to their full extent
     self.report(
         pcr.ifthenelse(
             self.waterBodies.distribution != 0,
             pcr.areamaximum(self.flowVelocity,
                             self.waterBodies.distribution),
             self.flowVelocity), flowVelocityFileName)
     self.report(
         pcr.ifthenelse(
             self.waterBodies.distribution != 0,
             pcr.areamaximum(self.Q, self.waterBodies.distribution),
             self.Q), QFileName)
     self.report(pcr.ifthenelse(self.waterBodies.distribution == 0,\
      floodedFraction,0.),floodedFractionFileName)
     self.report(pcr.ifthenelse(self.waterBodies.distribution == 0,\
      floodedDepth,0.),floodedDepthFileName)
     self.report(self.actualStorage, actualStorageFileName)
     #-update date for time step and report relevant daily output
     self.currentDate = self.currentDate + datetime.timedelta(self.duration)
	def dynamic(self):
		#####################
		# * dynamic section #
		#####################
		#-evaluation of the current date: return current month and the time step used
		#-reading in fluxes over land and water area for current time step [m/d]
		# and read in reservoir demand and surface water extraction [m3]
		try:
			self.landSurfaceQ= clippedRead.get(pcrm.generateNameT(landSurfaceQFileName,self.currentTimeStep()))
		except:
			pass
		try:
			self.potWaterSurfaceQ= clippedRead.get(pcrm.generateNameT(waterSurfaceQFileName,self.currentTimeStep()))
		except:
			pass
		#-surface water extraction and reservoir demand currently set to zero, should
		# be computed automatically and updated to reservoirs
		self.potSurfaceWaterExtraction= pcr.spatial(pcr.scalar(0.))
		#self.waterBodies.demand=  #self.reservoirDemandTSS.assignID(self.waterBodies.ID,self.currentTimeStep(),0.)*self.timeSec
		#-initialization of cumulative values of actual water extractions
		self.actWaterSurfaceQ= pcr.spatial(pcr.scalar(0.))
		self.actSurfaceWaterExtraction= pcr.spatial(pcr.scalar(0.))    
		#-definition of sub-loop for routing scheme - explicit scheme has to satisfy Courant condition
		timeLimit= pcr.cellvalue(pcr.mapminimum((pcr.cover(pcr.ifthen(self.waterBodies.distribution == 0,\
			self.channelLength/self.flowVelocity),\
				self.timeSec/self.nrIterDefault)*self.timeSec/self.nrIterDefault)**0.5),1)[0]
		nrIter= int(self.timeSec/timeLimit)
		nrIter= min(nrIter,int(self.timeSec/300.))
		while float(self.timeSec/nrIter) % 1 <> 0:
			nrIter+= 1
		deltaTime= self.timeSec/nrIter
		#-sub-loop for current time step
		if self.currentDate.day == 1 or nrIter >= 24:
			print '\n*\tprocessing %s, currently using %d substeps of %d seconds\n' % \
				(self.currentDate.date(),nrIter,deltaTime)
		#-update discharge and storage
		for nrICur in range(nrIter):
			#-initializing discharge for the current sub-timestep and fill in values
			# for channels and at outlets of waterbodies
			# * channels *
			estQ= pcr.ifthenelse((self.actualStorage > 0.) & (self.waterBodies.distribution == 0) ,\
				(self.wettedArea/self.alphaQ)**(1./self.betaQ),0.)
			#estQ= pcr.ifthenelse((self.actualStorage > 0.) & (self.waterBodies.distribution == 0) ,\
				#0.5*(self.Q+(self.wettedArea/self.alphaQ)**(1./self.betaQ)),0.)
			#estQ= pcr.min(estQ,self.actualStorage/deltaTime)
			self.report(estQ,'results/qest')
			self.Q= pcr.spatial(pcr.scalar(0.))
			self.Q= pcr.ifthenelse(self.waterBodies.distribution == 0,\
				pcr.kinematic(self.channelLDD,estQ,0.,self.alphaQ,\
					self.betaQ,1,deltaTime,self.channelLength),self.Q)
			# * water bodies *
			self.waterBodies.dischargeUpdate()
			self.Q= self.waterBodies.returnMapValue(self.Q,self.waterBodies.actualQ)
			#-fluxes and resulting change in storage: first the local fluxes are evaluated
			# and aggregated over the water bodies where applicable; this includes the specific runoff [m/day/m2]
			# from input and the estimated extraction from surface water as volume per day [m3/day];
			# specific runoff from the land surface is always positive whereas the fluxes over the water surface
			# are potential, including discharge, and are adjusted to match the availabe storage; to this end,
			# surface water storage and fluxes over water bodies are totalized and assigned to the outlet;
			# discharge is updated in a separate step, after vertical fluxes are compared to the actual storage
			deltaActualStorage= ((self.landFraction*self.landSurfaceQ+\
				self.waterFraction*self.potWaterSurfaceQ)*self.cellArea-\
				self.potSurfaceWaterExtraction)*float(self.duration)/nrIter
			deltaActualStorage= pcr.ifthenelse(self.waterBodies.distribution != 0,\
				pcr.ifthenelse(self.waterBodies.location != 0,\
					pcr.areatotal(deltaActualStorage,self.waterBodies.distribution),0),\
						deltaActualStorage)   
			adjustmentRatio= pcr.ifthenelse(deltaActualStorage < 0.,\
				pcr.min(1.,-self.actualStorage/deltaActualStorage),1.)
			self.actWaterSurfaceQ+= adjustmentRatio*self.potWaterSurfaceQ
			self.actSurfaceWaterExtraction+= adjustmentRatio*self.actSurfaceWaterExtraction
			deltaActualStorage*= adjustmentRatio
			#-local water balance check
			if testLocalWaterBalance:
				differenceActualStorage= self.actualStorage
				differenceActualStorage+= deltaActualStorage
			#-overall water balance check: net input
			self.cumulativeDeltaStorage+= pcr.catchmenttotal(deltaActualStorage,self.LDD)
			#-update storage first with local changes, then balance discharge with storage and update storage
			# with lateral flow and return value to water bodies
			self.actualStorage+= deltaActualStorage
			self.actualStorage= pcr.max(0.,self.actualStorage)
			self.Q= pcr.min(self.Q,self.actualStorage/deltaTime)
			deltaActualStorage= (-self.Q+pcr.upstream(self.LDD,self.Q))*deltaTime
			deltaActualStorage= pcr.ifthenelse(self.waterBodies.distribution != 0,\
				pcr.ifthenelse(self.waterBodies.location != 0,\
					pcr.areatotal(deltaActualStorage,self.waterBodies.distribution),0),\
						deltaActualStorage)
			self.actualStorage+= deltaActualStorage
			self.actualStorage= pcr.max(0.,self.actualStorage)
			self.waterBodies.actualStorage= self.waterBodies.retrieveMapValue(self.actualStorage)
			#-flooded fraction returned
			floodedFraction,floodedDepth,\
					self.wettedArea,self.alphaQ= self.kinAlphaComposite(self.actualStorage,self.floodplainMask)
			self.wettedArea= self.waterBodies.returnMapValue(self.wettedArea,\
				self.waterBodies.channelWidth+2.*self.waterBodies.updateWaterHeight())
			self.waterFraction= pcr.ifthenelse(self.waterBodies.distribution == 0,\
				pcr.max(self.waterFractionMask,floodedFraction),self.waterFractionMask)
			self.landFraction= pcr.max(0.,1.-self.waterFraction)
			self.flowVelocity= pcr.ifthenelse(self.wettedArea > 0,self.Q/self.wettedArea,0.)
			#-local water balance check
			if testLocalWaterBalance:
				differenceActualStorage+= deltaActualStorage
				differenceActualStorage-= self.actualStorage
				totalDifference= pcr.cellvalue(pcr.maptotal(differenceActualStorage),1)[0]
				minimumDifference= pcr.cellvalue(pcr.mapminimum(differenceActualStorage),1)[0]
				maximumDifference= pcr.cellvalue(pcr.mapmaximum(differenceActualStorage),1)[0]
				if abs(totalDifference) > 1.e-3:
					print 'water balance error: total %e; min %e; max %e' %\
						(totalDifference,minimumDifference,maximumDifference)
					if  reportLocalWaterBalance:           
						pcr.report(differenceActualStorage,'mbe_%s.map' % self.currentDate.date())
			#-overall water balance check: updating cumulative discharge and total storage [m3]
			self.totalDischarge+= self.Q*deltaTime
			self.totalStorage= pcr.catchmenttotal(self.actualStorage,self.LDD)
		#-check on occurrence of last day and report mass balance
		if self.currentDate == self.endDate:
			#-report initial maps
			pcr.report(self.Q,self.QIniMap)
			pcr.report(self.actualStorage,self.actualStorageIniMap)
			#-return relative and absolute water balance error per cell and
			# as total at basin outlets
			self.totalDischarge= pcr.ifthen((self.waterBodies.distribution == 0) | \
				(self.waterBodies.location != 0),self.totalDischarge)
			self.cumulativeDeltaStorage= pcr.ifthen((self.waterBodies.distribution == 0) | \
				(self.waterBodies.location != 0),self.cumulativeDeltaStorage)
			massBalanceError= self.totalStorage+self.totalDischarge-\
				self.cumulativeDeltaStorage
			relMassBalanceError= 1.+pcr.ifthenelse(self.cumulativeDeltaStorage <> 0.,
				massBalanceError/self.cumulativeDeltaStorage,0.)
			totalMassBalanceError= pcr.cellvalue(pcr.maptotal(pcr.ifthen(self.basinOutlet,\
				massBalanceError)),1)[0]
			totalCumulativeDeltaStorage= pcr.cellvalue(pcr.maptotal(pcr.ifthen(self.basinOutlet,\
				self.cumulativeDeltaStorage)),1)[0]
			if totalCumulativeDeltaStorage > 0:
				totalRelativeMassBalanceError= 1.+totalMassBalanceError/totalCumulativeDeltaStorage
			else:
				totalRelativeMassBalanceError= 1.
			#-report maps and echo value
			pcr.report(massBalanceError,mbeFileName)
			pcr.report(relMassBalanceError,mbrFileName)
			print '\n*\ttotal global mass balance error [m3]: %8.3g' % totalMassBalanceError
			print '\n*\trelative global mass balance error [-]: %5.3f' % totalRelativeMassBalanceError     
			#-echo to screen: total mass balance error and completion of run
			print '\trun completed'
		#-end of day: return states and fluxes
		#-get surface water attributes?
		if getSurfaceWaterAttributes:
			#-compute the following secondary variables:
			# surface water area [m2]: area given dynamic surface water fraction
			# residence time [days]: volume over discharge, assigned -1 in case discharge is zero
			# surface water depth [m], weighed by channel and floodplain volume
			surfaceWaterArea= self.waterFraction*self.cellArea
			surfaceWaterArea= pcr.ifthenelse(self.waterBodies.distribution != 0,\
					pcr.ifthenelse(self.waterBodies.location != 0,\
						pcr.areatotal(surfaceWaterArea,self.waterBodies.distribution),0),\
							surfaceWaterArea)     
			surfaceWaterResidenceTime= pcr.ifthenelse(self.Q > 0.,self.actualStorage/(self.Q*self.timeSec),-1)
			surfaceWaterDepth= pcr.ifthenelse(self.actualStorage > 0.,\
				pcr.max(0.,self.actualStorage-self.channelStorageCapacity)**2/\
					(self.actualStorage*surfaceWaterArea),0.)
			surfaceWaterDepth+= pcr.ifthenelse(self.actualStorage > 0.,\
				pcr.min(self.channelStorageCapacity,self.actualStorage)**2/(self.waterFractionMask*\
				self.cellArea*self.actualStorage),0.)
			#-reports: values at outlet of lakes or reservoirs are assigned to their full extent
			self.report(pcr.ifthenelse(self.waterBodies.distribution != 0,\
				pcr.areamaximum(surfaceWaterArea,self.waterBodies.distribution),surfaceWaterArea),\
					surfaceWaterAreaFileName)   
			self.report(pcr.ifthenelse(self.waterBodies.distribution != 0,\
				pcr.areamaximum(surfaceWaterResidenceTime,self.waterBodies.distribution),surfaceWaterResidenceTime),\
					surfaceWaterResidenceTimeFileName)
			self.report(pcr.ifthenelse(self.waterBodies.distribution != 0,\
				pcr.areamaximum(surfaceWaterDepth,self.waterBodies.distribution),surfaceWaterDepth),\
					surfaceWaterDepthFileName)
		#-reports on standard output: values at outlet of lakes or reservoirs are assigned to their full extent
		self.report(pcr.ifthenelse(self.waterBodies.distribution != 0,
			pcr.areamaximum(self.flowVelocity,self.waterBodies.distribution),self.flowVelocity),flowVelocityFileName)
		self.report(pcr.ifthenelse(self.waterBodies.distribution != 0,
			pcr.areamaximum(self.Q,self.waterBodies.distribution),self.Q),QFileName)
		self.report(pcr.ifthenelse(self.waterBodies.distribution == 0,\
			floodedFraction,0.),floodedFractionFileName)
		self.report(pcr.ifthenelse(self.waterBodies.distribution == 0,\
			floodedDepth,0.),floodedDepthFileName)
		self.report(self.actualStorage,actualStorageFileName)
		#-update date for time step and report relevant daily output 
		self.currentDate= self.currentDate+datetime.timedelta(self.duration)
Example #17
0
    def getParameterFiles(
        self, currTimeStep, cellArea, ldd, initial_condition_dictionary=None
    ):

        # parameters for Water Bodies: fracWat
        #                              waterBodyIds
        #                              waterBodyOut
        #                              waterBodyArea
        #                              waterBodyTyp
        #                              waterBodyCap

        # cell surface area (m2) and ldd
        self.cellArea = cellArea
        ldd = pcr.ifthen(self.landmask, ldd)

        # date used for accessing/extracting water body information
        date_used = currTimeStep.fulldate
        year_used = currTimeStep.year
        if self.onlyNaturalWaterBodies == True:
            date_used = self.dateForNaturalCondition
            year_used = self.dateForNaturalCondition[0:4]

        # fracWat = fraction of surface water bodies (dimensionless)
        self.fracWat = pcr.scalar(0.0)

        if self.useNetCDF:
            self.fracWat = vos.netcdf2PCRobjClone(
                self.ncFileInp,
                "fracWaterInp",
                date_used,
                useDoy="yearly",
                cloneMapFileName=self.cloneMap,
            )
        else:
            self.fracWat = vos.readPCRmapClone(
                self.fracWaterInp + str(year_used) + ".map",
                self.cloneMap,
                self.tmpDir,
                self.inputDir,
            )

        self.fracWat = pcr.cover(self.fracWat, 0.0)
        self.fracWat = pcr.max(0.0, self.fracWat)
        self.fracWat = pcr.min(1.0, self.fracWat)

        self.waterBodyIds = pcr.nominal(0)  # waterBody ids
        self.waterBodyOut = pcr.boolean(0)  # waterBody outlets
        self.waterBodyArea = pcr.scalar(0.0)  # waterBody surface areas

        # water body ids
        if self.useNetCDF:
            self.waterBodyIds = vos.netcdf2PCRobjClone(
                self.ncFileInp,
                "waterBodyIds",
                date_used,
                useDoy="yearly",
                cloneMapFileName=self.cloneMap,
            )
        else:
            self.waterBodyIds = vos.readPCRmapClone(
                self.waterBodyIdsInp + str(year_used) + ".map",
                self.cloneMap,
                self.tmpDir,
                self.inputDir,
                False,
                None,
                True,
            )
        #
        self.waterBodyIds = pcr.ifthen(
            pcr.scalar(self.waterBodyIds) > 0.0, pcr.nominal(self.waterBodyIds)
        )

        # water body outlets (correcting outlet positions)
        wbCatchment = pcr.catchmenttotal(pcr.scalar(1), ldd)
        self.waterBodyOut = pcr.ifthen(
            wbCatchment == pcr.areamaximum(wbCatchment, self.waterBodyIds),
            self.waterBodyIds,
        )  # = outlet ids
        self.waterBodyOut = pcr.ifthen(
            pcr.scalar(self.waterBodyIds) > 0.0, self.waterBodyOut
        )
        # TODO: Please also consider endorheic lakes!

        # correcting water body ids
        self.waterBodyIds = pcr.ifthen(
            pcr.scalar(self.waterBodyIds) > 0.0,
            pcr.subcatchment(ldd, self.waterBodyOut),
        )

        # boolean map for water body outlets:
        self.waterBodyOut = pcr.ifthen(
            pcr.scalar(self.waterBodyOut) > 0.0, pcr.boolean(1)
        )

        # reservoir surface area (m2):
        if self.useNetCDF:
            resSfArea = (
                1000.0
                * 1000.0
                * vos.netcdf2PCRobjClone(
                    self.ncFileInp,
                    "resSfAreaInp",
                    date_used,
                    useDoy="yearly",
                    cloneMapFileName=self.cloneMap,
                )
            )
        else:
            resSfArea = (
                1000.0
                * 1000.0
                * vos.readPCRmapClone(
                    self.resSfAreaInp + str(year_used) + ".map",
                    self.cloneMap,
                    self.tmpDir,
                    self.inputDir,
                )
            )
        resSfArea = pcr.areaaverage(resSfArea, self.waterBodyIds)
        resSfArea = pcr.cover(resSfArea, 0.0)

        # water body surface area (m2): (lakes and reservoirs)
        self.waterBodyArea = pcr.max(
            pcr.areatotal(
                pcr.cover(self.fracWat * self.cellArea, 0.0), self.waterBodyIds
            ),
            pcr.areaaverage(pcr.cover(resSfArea, 0.0), self.waterBodyIds),
        )
        self.waterBodyArea = pcr.ifthen(self.waterBodyArea > 0.0, self.waterBodyArea)

        # correcting water body ids and outlets (exclude all water bodies with surfaceArea = 0)
        self.waterBodyIds = pcr.ifthen(self.waterBodyArea > 0.0, self.waterBodyIds)
        self.waterBodyOut = pcr.ifthen(
            pcr.boolean(self.waterBodyIds), self.waterBodyOut
        )

        # water body types:
        # - 2 = reservoirs (regulated discharge)
        # - 1 = lakes (weirFormula)
        # - 0 = non lakes or reservoirs (e.g. wetland)
        self.waterBodyTyp = pcr.nominal(0)

        if self.useNetCDF:
            self.waterBodyTyp = vos.netcdf2PCRobjClone(
                self.ncFileInp,
                "waterBodyTyp",
                date_used,
                useDoy="yearly",
                cloneMapFileName=self.cloneMap,
            )
        else:
            self.waterBodyTyp = vos.readPCRmapClone(
                self.waterBodyTypInp + str(year_used) + ".map",
                self.cloneMap,
                self.tmpDir,
                self.inputDir,
                False,
                None,
                True,
            )

        # excluding wetlands (waterBodyTyp = 0) in all functions related to lakes/reservoirs
        #
        self.waterBodyTyp = pcr.ifthen(
            pcr.scalar(self.waterBodyTyp) > 0, pcr.nominal(self.waterBodyTyp)
        )
        self.waterBodyTyp = pcr.ifthen(
            pcr.scalar(self.waterBodyIds) > 0, pcr.nominal(self.waterBodyTyp)
        )
        self.waterBodyTyp = pcr.areamajority(
            self.waterBodyTyp, self.waterBodyIds
        )  # choose only one type: either lake or reservoir
        self.waterBodyTyp = pcr.ifthen(
            pcr.scalar(self.waterBodyTyp) > 0, pcr.nominal(self.waterBodyTyp)
        )
        self.waterBodyTyp = pcr.ifthen(
            pcr.boolean(self.waterBodyIds), self.waterBodyTyp
        )

        # correcting lakes and reservoirs ids and outlets
        self.waterBodyIds = pcr.ifthen(
            pcr.scalar(self.waterBodyTyp) > 0, self.waterBodyIds
        )
        self.waterBodyOut = pcr.ifthen(
            pcr.scalar(self.waterBodyIds) > 0, self.waterBodyOut
        )

        # reservoir maximum capacity (m3):
        self.resMaxCap = pcr.scalar(0.0)
        self.waterBodyCap = pcr.scalar(0.0)

        if self.useNetCDF:
            self.resMaxCap = (
                1000.0
                * 1000.0
                * vos.netcdf2PCRobjClone(
                    self.ncFileInp,
                    "resMaxCapInp",
                    date_used,
                    useDoy="yearly",
                    cloneMapFileName=self.cloneMap,
                )
            )
        else:
            self.resMaxCap = (
                1000.0
                * 1000.0
                * vos.readPCRmapClone(
                    self.resMaxCapInp + str(year_used) + ".map",
                    self.cloneMap,
                    self.tmpDir,
                    self.inputDir,
                )
            )

        self.resMaxCap = pcr.ifthen(self.resMaxCap > 0, self.resMaxCap)
        self.resMaxCap = pcr.areaaverage(self.resMaxCap, self.waterBodyIds)

        # water body capacity (m3): (lakes and reservoirs)
        self.waterBodyCap = pcr.cover(
            self.resMaxCap, 0.0
        )  # Note: Most of lakes have capacities > 0.
        self.waterBodyCap = pcr.ifthen(
            pcr.boolean(self.waterBodyIds), self.waterBodyCap
        )

        # correcting water body types:                                  # Reservoirs that have zero capacities will be assumed as lakes.
        self.waterBodyTyp = pcr.ifthen(
            pcr.scalar(self.waterBodyTyp) > 0.0, self.waterBodyTyp
        )
        self.waterBodyTyp = pcr.ifthenelse(
            self.waterBodyCap > 0.0,
            self.waterBodyTyp,
            pcr.ifthenelse(
                pcr.scalar(self.waterBodyTyp) == 2, pcr.nominal(1), self.waterBodyTyp
            ),
        )

        # final corrections:
        self.waterBodyTyp = pcr.ifthen(
            self.waterBodyArea > 0.0, self.waterBodyTyp
        )  # make sure that all lakes and/or reservoirs have surface areas
        self.waterBodyTyp = pcr.ifthen(
            pcr.scalar(self.waterBodyTyp) > 0.0, self.waterBodyTyp
        )  # make sure that only types 1 and 2 will be considered in lake/reservoir functions
        self.waterBodyIds = pcr.ifthen(
            pcr.scalar(self.waterBodyTyp) > 0.0, self.waterBodyIds
        )  # make sure that all lakes and/or reservoirs have ids
        self.waterBodyOut = pcr.ifthen(
            pcr.scalar(self.waterBodyIds) > 0.0, self.waterBodyOut
        )  # make sure that all lakes and/or reservoirs have outlets

        # for a natural run (self.onlyNaturalWaterBodies == True)
        # which uses only the year 1900, assume all reservoirs are lakes
        if (
            self.onlyNaturalWaterBodies == True
            and date_used == self.dateForNaturalCondition
        ):
            logger.info(
                "Using only natural water bodies identified in the year 1900. All reservoirs in 1900 are assumed as lakes."
            )
            self.waterBodyTyp = pcr.ifthen(
                pcr.scalar(self.waterBodyTyp) > 0.0, pcr.nominal(1)
            )

        # check that all lakes and/or reservoirs have types, ids, surface areas and outlets:
        test = (
            pcr.defined(self.waterBodyTyp)
            & pcr.defined(self.waterBodyArea)
            & pcr.defined(self.waterBodyIds)
            & pcr.boolean(
                pcr.areamaximum(pcr.scalar(self.waterBodyOut), self.waterBodyIds)
            )
        )
        a, b, c = vos.getMinMaxMean(pcr.cover(pcr.scalar(test), 1.0) - pcr.scalar(1.0))
        threshold = 1e-3
        if abs(a) > threshold or abs(b) > threshold:
            logger.warning("Missing information in some lakes and/or reservoirs.")

        # at the beginning of simulation period (timeStepPCR = 1)
        # - we have to define/get the initial conditions
        #
        if currTimeStep.timeStepPCR == 1:
            self.getICs(initial_condition_dictionary)

        # For each new reservoir (introduced at the beginning of the year)
        # initiating storage, average inflow and outflow
        #
        self.waterBodyStorage = pcr.cover(self.waterBodyStorage, 0.0)
        self.avgInflow = pcr.cover(self.avgInflow, 0.0)
        self.avgOutflow = pcr.cover(self.avgOutflow, 0.0)

        # cropping only in the landmask region:
        self.fracWat = pcr.ifthen(self.landmask, self.fracWat)
        self.waterBodyIds = pcr.ifthen(self.landmask, self.waterBodyIds)
        self.waterBodyOut = pcr.ifthen(self.landmask, self.waterBodyOut)
        self.waterBodyArea = pcr.ifthen(self.landmask, self.waterBodyArea)
        self.waterBodyTyp = pcr.ifthen(self.landmask, self.waterBodyTyp)
        self.waterBodyCap = pcr.ifthen(self.landmask, self.waterBodyCap)
        self.waterBodyStorage = pcr.ifthen(self.landmask, self.waterBodyStorage)
        self.avgInflow = pcr.ifthen(self.landmask, self.avgInflow)
        self.avgOutflow = pcr.ifthen(self.landmask, self.avgOutflow)
    def set_river_package(self, discharge):

        logger.info("Set the river package.")

        # specify the river package
        #
        # - surface water river bed/bottom elevation
        #
        # - for lakes and resevoirs, make the bottom elevation deep --- Shall we do this?
        #~ additional_depth = 500.
        #~ surface_water_bed_elevation = pcr.ifthen(pcr.scalar(self.WaterBodies.waterBodyIds) > 0.0, \
        #~ self.dem_riverbed - additional_depth)
        #~ surface_water_bed_elevation = pcr.cover(surface_water_bed_elevation, self.dem_riverbed)
        #
        surface_water_bed_elevation = self.dem_riverbed  # This is an alternative, if we do not want to introduce very deep bottom elevations of lakes and/or reservoirs.
        #
        # rounding values for surface_water_bed_elevation
        self.surface_water_bed_elevation = pcr.roundup(
            surface_water_bed_elevation * 1000.) / 1000.
        #
        # - river bed condutance (unit: m2/day)
        bed_surface_area = pcr.ifthen(pcr.scalar(self.WaterBodies.waterBodyIds) > 0.0, \
                                                 self.WaterBodies.fracWat * self.cellAreaMap)   # TODO: Incorporate the concept of dynamicFracWat
        bed_surface_area = pcr.cover(bed_surface_area, \
                                     self.bankfull_width * self.channelLength)
        bed_surface_area = self.bankfull_width * self.channelLength
        bed_conductance = (1.0 / self.bed_resistance) * bed_surface_area
        bed_conductance = pcr.ifthenelse(bed_conductance < 1e-20, 0.0, \
                                         bed_conductance)
        self.bed_conductance = pcr.cover(bed_conductance, 0.0)
        #
        # - 'channel width' for lakes and reservoirs
        channel_width = pcr.areamaximum(self.bankfull_width,
                                        self.WaterBodies.waterBodyIds)
        channel_width = pcr.cover(channel_width, self.bankfull_width)
        #
        # - convert discharge value to surface water elevation (m)
        river_water_height = (channel_width**(-3 / 5)) * (discharge**(
            3 / 5)) * ((self.gradient)**(-3 / 10)) * (self.manningsN**(3 / 5))
        surface_water_elevation = self.dem_riverbed + \
                                  river_water_height
        #
        # - calculating water level (unit: m) above the flood plain   # TODO: Improve this concept (using Rens's latest innundation scheme)
        #----------------------------------------------------------
        water_above_fpl = pcr.max(
            0.0, surface_water_elevation - self.dem_floodplain
        )  # unit: m, water level above the floodplain (not distributed)
        water_above_fpl *= self.bankfull_depth * self.bankfull_width / self.cellAreaMap  # unit: m, water level above the floodplain (distributed within the cell)
        # TODO: Improve this concept using Rens's latest scheme
        #
        # - corrected surface water elevation
        surface_water_elevation = pcr.ifthenelse(surface_water_elevation > self.dem_floodplain, \
                                                                           self.dem_floodplain + water_above_fpl, \
                                                                           surface_water_elevation)
        # - surface water elevation for lakes and reservoirs:
        lake_reservoir_water_elevation = pcr.ifthen(
            self.WaterBodies.waterBodyOut, surface_water_elevation)
        lake_reservoir_water_elevation = pcr.areamaximum(
            lake_reservoir_water_elevation, self.WaterBodies.waterBodyIds)
        lake_reservoir_water_elevation = pcr.cover(lake_reservoir_water_elevation, \
                                         pcr.areaaverage(surface_water_elevation, self.WaterBodies.waterBodyIds))
        # - maximum and minimum values for lake_reservoir_water_elevation
        lake_reservoir_water_elevation = pcr.min(
            self.dem_floodplain, lake_reservoir_water_elevation)
        lake_reservoir_water_elevation = pcr.max(
            surface_water_bed_elevation, lake_reservoir_water_elevation)
        # - smoothing
        lake_reservoir_water_elevation = pcr.areaaverage(
            surface_water_elevation, self.WaterBodies.waterBodyIds)
        #
        # - merge lake and reservoir water elevation
        surface_water_elevation = pcr.cover(lake_reservoir_water_elevation,
                                            surface_water_elevation)
        #
        # - pass values to the river package
        surface_water_elevation = pcr.cover(surface_water_elevation,
                                            self.surface_water_bed_elevation)
        surface_water_elevation = pcr.rounddown(
            surface_water_elevation * 1000.) / 1000.
        #
        # - make sure that HRIV >= RBOT ; no infiltration if HRIV = RBOT (and h < RBOT)
        self.surface_water_elevation = pcr.max(
            surface_water_elevation, self.surface_water_bed_elevation)
        #
        # - pass the values to the RIV package
        self.pcr_modflow.setRiver(self.surface_water_elevation, \
                                  self.surface_water_bed_elevation, self.bed_conductance, 2)
Example #19
0
def subcatch_stream(
    ldd,
    threshold,
    min_strahler=-999,
    max_strahler=999,
    assign_edge=False,
    assign_existing=False,
    up_area=None,
):
    """
    (From Deltares Hydrotools)

    Derive catchments based upon strahler threshold
    Input:
        ldd -- pcraster object direction, local drain directions
        threshold -- integer, strahler threshold, subcatchments ge threshold
            are derived
        min_strahler -- integer, minimum strahler threshold of river catchments
            to return
        max_strahler -- integer, maximum strahler threshold of river catchments
            to return
        assign_unique=False -- if set to True, unassigned connected areas at
            the edges of the domain are assigned a unique id as well. If set
            to False, edges are not assigned
        assign_existing=False == if set to True, unassigned edges are assigned
            to existing basins with an upstream weighting. If set to False,
            edges are assigned to unique IDs, or not assigned
    output:
        stream_ge -- pcraster object, streams of strahler order ge threshold
        subcatch -- pcraster object, subcatchments of strahler order ge threshold

    """
    # derive stream order

    stream = pcr.streamorder(ldd)
    stream_ge = pcr.ifthen(stream >= threshold, stream)
    stream_up_sum = pcr.ordinal(pcr.upstream(ldd, pcr.cover(pcr.scalar(stream_ge), 0)))
    # detect any transfer of strahler order, to a higher strahler order.
    transition_strahler = pcr.ifthenelse(
        pcr.downstream(ldd, stream_ge) != stream_ge,
        pcr.boolean(1),
        pcr.ifthenelse(
            pcr.nominal(ldd) == 5,
            pcr.boolean(1),
            pcr.ifthenelse(
                pcr.downstream(ldd, pcr.scalar(stream_up_sum)) > pcr.scalar(stream_ge),
                pcr.boolean(1),
                pcr.boolean(0),
            ),
        ),
    )
    # make unique ids (write to file)
    transition_unique = pcr.ordinal(pcr.uniqueid(transition_strahler))

    # derive upstream catchment areas (write to file)
    subcatch = pcr.nominal(pcr.subcatchment(ldd, transition_unique))

    if assign_edge:
        # fill unclassified areas (in pcraster equal to zero) with a unique id, above the maximum id assigned so far
        unique_edge = pcr.clump(pcr.ifthen(subcatch == 0, pcr.ordinal(0)))
        subcatch = pcr.ifthenelse(
            subcatch == 0,
            pcr.nominal(pcr.mapmaximum(pcr.scalar(subcatch)) + pcr.scalar(unique_edge)),
            pcr.nominal(subcatch),
        )
    elif assign_existing:
        # unaccounted areas are added to largest nearest draining basin
        if up_area is None:
            up_area = pcr.ifthen(
                pcr.boolean(pcr.cover(stream_ge, 0)), pcr.accuflux(ldd, 1)
            )
        riverid = pcr.ifthen(pcr.boolean(pcr.cover(stream_ge, 0)), subcatch)

        friction = 1.0 / pcr.scalar(
            pcr.spreadzone(pcr.cover(pcr.ordinal(up_area), 0), 0, 0)
        )  # *(pcr.scalar(ldd)*0+1)
        delta = pcr.ifthen(
            pcr.scalar(ldd) >= 0,
            pcr.ifthen(
                pcr.cover(subcatch, 0) == 0,
                pcr.spreadzone(pcr.cover(riverid, 0), 0, friction),
            ),
        )
        subcatch = pcr.ifthenelse(pcr.boolean(pcr.cover(subcatch, 0)), subcatch, delta)

    # finally, only keep basins with minimum and maximum river order flowing through them
    strahler_subcatch = pcr.areamaximum(stream, subcatch)
    subcatch = pcr.ifthen(
        pcr.ordinal(strahler_subcatch) >= min_strahler,
        pcr.ifthen(pcr.ordinal(strahler_subcatch) <= max_strahler, subcatch),
    )

    return stream_ge, pcr.ordinal(subcatch)
Example #20
0
def main():
    """
        
    :ivar masterdem: digital elevation model
    :ivar dem: digital elevation model
    :ivar river: optional river map
    """

    # Default values
    strRiver = 8
    masterdem = "dem.map"
    step1dir = "step1"
    step2dir = "step2"
    workdir = "."
    inifile = "wflow_prepare.ini"
    recreate = False
    snapgaugestoriver = False

    try:
        opts, args = getopt.getopt(sys.argv[1:], "W:hI:f",['version'])
    except getopt.error as msg:
        usage(msg)

    for o, a in opts:
        if o == "-W":
            workdir = a
        if o == "-I":
            inifile = a
        if o == "-h":
            usage()
        if o == "-f":
            recreate = True
        if o == "--version":
            import wflow
            print("wflow version: ", wflow.__version__)
            sys.exit(0)

    pcr.setglobaloption("unitcell")
    os.chdir(workdir)

    config = OpenConf(workdir + "/" + inifile)

    masterdem = configget(config, "files", "masterdem", "dem.map")
    pcr.setclone(masterdem)

    strRiver = int(configget(config, "settings", "riverorder", "4"))

    try:
        gauges_x = config.get("settings", "gauges_x")
        gauges_y = config.get("settings", "gauges_y")
    except:
        print("gauges_x and  gauges_y are required entries in the ini file")
        sys.exit(1)

    step1dir = configget(config, "directories", "step1dir", "step1")
    step2dir = configget(config, "directories", "step2dir", "step2")
    # upscalefactor = float(config.get("settings","upscalefactor"))

    corevolume = float(configget(config, "settings", "corevolume", "1E35"))
    catchmentprecipitation = float(
        configget(config, "settings", "catchmentprecipitation", "1E35")
    )
    corearea = float(configget(config, "settings", "corearea", "1E35"))
    outflowdepth = float(configget(config, "settings", "lddoutflowdepth", "1E35"))

    initialscale = int(configget(config, "settings", "initialscale", "1"))
    csize = float(configget(config, "settings", "cellsize", "1"))

    snapgaugestoriver = bool(
        int(configget(config, "settings", "snapgaugestoriver", "1"))
    )
    lddglobaloption = configget(config, "settings", "lddglobaloption", "lddout")
    pcr.setglobaloption(lddglobaloption)
    lu_water = configget(config, "files", "lu_water", "")
    lu_paved = configget(config, "files", "lu_paved", "")

    # X/Y coordinates of the gauges the system    
    X = np.fromstring(gauges_x, sep=',')
    Y = np.fromstring(gauges_y, sep=',')

    tr.Verbose = 1

    # make the directories to save results in
    if not os.path.isdir(step1dir + "/"):
        os.makedirs(step1dir)
    if not os.path.isdir(step2dir):
        os.makedirs(step2dir)

    if initialscale > 1:
        print("Initial scaling of DEM...")
        os.system(
            "resample -r "
            + str(initialscale)
            + " "
            + masterdem
            + " "
            + step1dir
            + "/dem_scaled.map"
        )
        print("Reading dem...")
        dem = pcr.readmap(step1dir + "/dem_scaled.map")
        ldddem = dem
    else:
        print ("Reading dem...")
        dem = pcr.readmap(masterdem)
        ldddem = dem

    try:
        catchmask = config.get("files", "catchment_mask")
    except:
        print("No catchment mask...")
    else:
        print("clipping DEM with mask.....")
        mask = pcr.readmap(catchmask)
        ldddem = pcr.ifthen(pcr.boolean(mask), ldddem)
        dem = pcr.ifthen(pcr.boolean(mask), dem)

    # See if there is a shape file of the river to burn in
    try:
        rivshp = config.get("files", "river")
    except:
        print("no river file specified")
        outletpointX = float(configget(config, "settings", "outflowpointX", "0.0"))
        outletpointY = float(configget(config, "settings", "outflowpointY", "0.0"))
    else:
        print("river file specified.....")
        try:
            outletpointX = float(configget(config, "settings", "outflowpointX", "0.0"))
            outletpointY = float(configget(config, "settings", "outflowpointY", "0.0"))
        except:
            print(
                "Need to specify the river outletpoint (a point at the end of the river within the current map)"
            )
            exit(1)

        outletpointmap = tr.points_to_map(dem, outletpointX, outletpointY, 0.5)
        pcr.report(outletpointmap, step1dir + "/outletpoint.map")
        # rivshpattr = config.get("files","riverattr")
        pcr.report(dem * 0.0, step1dir + "/nilmap.map")
        thestr = (
            "gdal_translate -of GTiff "
            + step1dir
            + "/nilmap.map "
            + step1dir
            + "/riverburn.tif"
        )
        os.system(thestr)
        rivshpattr = os.path.splitext(os.path.basename(rivshp))[0]
        os.system(
            "gdal_rasterize -burn 1 -l "
            + rivshpattr
            + " "
            + rivshp
            + " "
            + step1dir
            + "/riverburn.tif"
        )
        thestr = (
            "gdal_translate -of PCRaster "
            + step1dir
            + "/riverburn.tif "
            + step1dir
            + "/riverburn.map"
        )
        os.system(thestr)
        riverburn = pcr.readmap(step1dir + "/riverburn.map")
        # Determine regional slope assuming that is the way the river should run
        # Determine regional slope assuming that is the way the river should run
        # pcr.setglobaloption("unitcell")
        # demregional=pcr.windowaverage(dem,100)
        ldddem = pcr.ifthenelse(riverburn >= 1.0, dem - 1000, dem)

    pcr.setglobaloption("unittrue")
    upscalefactor = int(csize / pcr.celllength())

    print("Creating ldd...")
    ldd = tr.lddcreate_save(
        step1dir + "/ldd.map",
        ldddem,
        recreate,
        outflowdepth=outflowdepth,
        corevolume=corevolume,
        catchmentprecipitation=catchmentprecipitation,
        corearea=corearea,
    )

    print("Determining streamorder...")
    stro = pcr.streamorder(ldd)
    pcr.report(stro, step1dir + "/streamorder.map")
    strdir = pcr.ifthen(stro >= strRiver, stro)
    pcr.report(strdir, step1dir + "/streamorderrive.map")
    pcr.report(pcr.boolean(pcr.ifthen(stro >= strRiver, stro)), step1dir + "/rivers.map")

    pcr.setglobaloption("unittrue")
    # outlet (and other gauges if given)
    # TODO: check is x/y set if not skip this
    print("Outlet...")

    outlmap = tr.points_to_map(dem, X, Y, 0.5)

    if snapgaugestoriver:
        print("Snapping gauges to nearest river cells...")
        pcr.report(outlmap, step1dir + "/orggauges.map")
        outlmap = tr.snaptomap(outlmap, strdir)

    # noutletmap = tr.points_to_map(dem,XX,YY,0.5)
    # pcr.report(noutletmap,'noutlet.map')

    pcr.report(outlmap, step1dir + "/gauges.map")

    # check if there is a pre-define catchment map
    try:
        catchmask = config.get("files", "catchment_mask")
    except:
        print("No catchment mask, finding outlet")
        # Find catchment (overall)
        outlet = tr.find_outlet(ldd)
        sub = tr.subcatch(ldd, outlet)
        pcr.report(sub, step1dir + "/catchment_overall.map")
    else:
        print("reading and converting catchment mask.....")
        os.system(
            "resample -r "
            + str(initialscale)
            + " "
            + catchmask
            + " "
            + step1dir
            + "/catchment_overall.map"
        )
        sub = pcr.readmap(step1dir + "/catchment_overall.map")

    print("Scatch...")
    sd = tr.subcatch(ldd, pcr.ifthen(outlmap > 0, outlmap))
    pcr.report(sd, step1dir + "/scatch.map")

    pcr.setglobaloption("unitcell")
    print("Upscalefactor: " + str(upscalefactor))

    if upscalefactor > 1:
        gc.collect()
        print("upscale river length1 (checkerboard map)...")
        ck = tr.checkerboard(dem, upscalefactor)
        pcr.report(ck, step1dir + "/ck.map")
        pcr.report(dem, step1dir + "/demck.map")
        print("upscale river length2...")
        fact = tr.area_riverlength_factor(ldd, ck, upscalefactor)
        pcr.report(fact, step1dir + "/riverlength_fact.map")

        # print("make dem statistics...")
        dem_ = pcr.areaaverage(dem, ck)
        pcr.report(dem_, step1dir + "/demavg.map")

        print("Create DEM statistics...")
        dem_ = pcr.areaminimum(dem, ck)
        pcr.report(dem_, step1dir + "/demmin.map")
        dem_ = pcr.areamaximum(dem, ck)
        pcr.report(dem_, step1dir + "/demmax.map")
        # calculate percentiles
        order = pcr.areaorder(dem, ck)
        n = pcr.areatotal(pcr.spatial(pcr.scalar(1.0)), ck)
        #: calculate 25 percentile
        perc = tr.area_percentile(dem, ck, n, order, 25.0)
        pcr.report(perc, step1dir + "/dem25.map")
        perc = tr.area_percentile(dem, ck, n, order, 10.0)
        pcr.report(perc, step1dir + "/dem10.map")
        perc = tr.area_percentile(dem, ck, n, order, 50.0)
        pcr.report(perc, step1dir + "/dem50.map")
        perc = tr.area_percentile(dem, ck, n, order, 33.0)
        pcr.report(perc, step1dir + "/dem33.map")
        perc = tr.area_percentile(dem, ck, n, order, 66.0)
        pcr.report(perc, step1dir + "/dem66.map")
        perc = tr.area_percentile(dem, ck, n, order, 75.0)
        pcr.report(perc, step1dir + "/dem75.map")
        perc = tr.area_percentile(dem, ck, n, order, 90.0)
        pcr.report(perc, step1dir + "/dem90.map")
    else:
        print("No fancy scaling done. Going strait to step2....")
        pcr.report(dem, step1dir + "/demavg.map")
        Xul = float(config.get("settings", "Xul"))
        Yul = float(config.get("settings", "Yul"))
        Xlr = float(config.get("settings", "Xlr"))
        Ylr = float(config.get("settings", "Ylr"))
        gdalstr = (
            "gdal_translate  -projwin "
            + str(Xul)
            + " "
            + str(Yul)
            + " "
            + str(Xlr)
            + " "
            + str(Ylr)
            + " -of PCRaster  "
        )
        # gdalstr = "gdal_translate  -a_ullr " + str(Xul) + " " + str(Yul) + " " +str(Xlr) + " " +str(Ylr) + " -of PCRaster  "
        print(gdalstr)
        pcr.report(pcr.cover(1.0), step1dir + "/wflow_riverlength_fact.map")
        # Now us gdat tp convert the maps
        os.system(
            gdalstr
            + step1dir
            + "/wflow_riverlength_fact.map"
            + " "
            + step2dir
            + "/wflow_riverlength_fact.map"
        )
        os.system(
            gdalstr + step1dir + "/demavg.map" + " " + step2dir + "/wflow_dem.map"
        )
        os.system(
            gdalstr + step1dir + "/demavg.map" + " " + step2dir + "/wflow_demmin.map"
        )
        os.system(
            gdalstr + step1dir + "/demavg.map" + " " + step2dir + "/wflow_demmax.map"
        )
        os.system(
            gdalstr + step1dir + "/gauges.map" + " " + step2dir + "/wflow_gauges.map"
        )
        os.system(
            gdalstr + step1dir + "/rivers.map" + " " + step2dir + "/wflow_river.map"
        )
        os.system(
            gdalstr
            + step1dir
            + "/streamorder.map"
            + " "
            + step2dir
            + "/wflow_streamorder.map"
        )
        os.system(
            gdalstr + step1dir + "/gauges.map" + " " + step2dir + "/wflow_outlet.map"
        )
        os.system(
            gdalstr + step1dir + "/scatch.map" + " " + step2dir + "/wflow_catchment.map"
        )
        os.system(gdalstr + step1dir + "/ldd.map" + " " + step2dir + "/wflow_ldd.map")
        os.system(
            gdalstr + step1dir + "/scatch.map" + " " + step2dir + "/wflow_subcatch.map"
        )

        if lu_water:
            os.system(gdalstr + lu_water + " " + step2dir + "/WaterFrac.map")

        if lu_paved:
            os.system(gdalstr + lu_paved + " " + step2dir + "/PathFrac.map")

        try:
            lumap = config.get("files", "landuse")
        except:
            print("no landuse map...creating uniform map")
            # clone=pcr.readmap(step2dir + "/wflow_dem.map")
            pcr.setclone(step2dir + "/wflow_dem.map")
            pcr.report(pcr.nominal(1), step2dir + "/wflow_landuse.map")
        else:
            os.system(
                "resample --clone "
                + step2dir
                + "/wflow_dem.map "
                + lumap
                + " "
                + step2dir
                + "/wflow_landuse.map"
            )

        try:
            soilmap = config.get("files", "soil")
        except:
            print("no soil map..., creating uniform map")
            pcr.setclone(step2dir + "/wflow_dem.map")
            pcr.report(pcr.nominal(1), step2dir + "/wflow_soil.map")
        else:
            os.system(
                "resample --clone "
                + step2dir
                + "/wflow_dem.map "
                + soilmap
                + " "
                + step2dir
                + "/wflow_soil.map"
            )
                             pcr.cover(\
                             vos.readPCRmapClone(reservoir_capacity_file, \
                                                 clone_map_file, \
                                                 tmp_folder, \
                                                 None, False, None, False), 0.0)) * 1000. * 1000.
        water_body_id      = vos.readPCRmapClone(water_body_id_file, \
                                                 clone_map_file, \
                                                 tmp_folder, \
                                                 None, False, None, True )
        water_body_id      = pcr.ifthen(pcr.scalar(water_body_id) > 0.00, water_body_id)
        water_body_id      = pcr.ifthen( landmask, water_body_id)                                         
        #
        # water body outlet
        wbCatchment        = pcr.catchmenttotal(pcr.scalar(1), ldd_map_low_resolution)
        water_body_outlet  = pcr.ifthen(wbCatchment ==\
                             pcr.areamaximum(wbCatchment, \
                             water_body_id),\
                             water_body_id) # = outlet ids      # This may give more than two outlets, particularly if there are more than one cells that have largest upstream areas      
        # - make sure that there is only one outlet for each water body 
        water_body_outlet  = pcr.ifthen(\
                             pcr.areaorder(pcr.scalar( water_body_outlet), \
                             water_body_outlet) == 1., water_body_outlet)
        water_body_outlet  = pcr.ifthen(\
                             pcr.scalar(water_body_outlet) > 0., water_body_outlet)

        # calculate overbank volume from reservoirs (and lakes)
        lake_reservoir_volume          = pcr.areatotal(extreme_value_map, water_body_id)
        lake_reservoir_overbank_volume = pcr.cover(
                                         pcr.max(0.0, lake_reservoir_volume - reservoir_capacity), 0.0)
        #~ pcr.aguila(lake_reservoir_overbank_volume)
        #
        # transfer 75% of overbank volume to the downstream (several cells downstream)
                             pcr.cover(\
                             vos.readPCRmapClone(reservoir_capacity_file, \
                                                 clone_map_file, \
                                                 tmp_folder, \
                                                 None, False, None, False), 0.0)) * 1000. * 1000.
        water_body_id      = vos.readPCRmapClone(water_body_id_file, \
                                                 clone_map_file, \
                                                 tmp_folder, \
                                                 None, False, None, True )
        water_body_id      = pcr.ifthen(pcr.scalar(water_body_id) > 0.00, water_body_id)
        water_body_id      = pcr.ifthen( landmask, water_body_id)                                         
        #
        # water body outlet
        wbCatchment        = pcr.catchmenttotal(pcr.scalar(1), ldd_map_low_resolution)
        water_body_outlet  = pcr.ifthen(wbCatchment ==\
                             pcr.areamaximum(wbCatchment, \
                             water_body_id),\
                             water_body_id) # = outlet ids      # This may give more than two outlets, particularly if there are more than one cells that have largest upstream areas      
        # - make sure that there is only one outlet for each water body 
        water_body_outlet  = pcr.ifthen(\
                             pcr.areaorder(pcr.scalar( water_body_outlet), \
                             water_body_outlet) == 1., water_body_outlet)
        water_body_outlet  = pcr.ifthen(\
                             pcr.scalar(water_body_outlet) > 0., water_body_outlet)

        # calculate overbank volume from reservoirs (and lakes)
        lake_reservoir_volume          = pcr.areatotal(extreme_value_map, water_body_id)
        lake_reservoir_overbank_volume = pcr.cover(
                                         pcr.max(0.0, lake_reservoir_volume - reservoir_capacity), 0.0)
        #~ pcr.aguila(lake_reservoir_overbank_volume)
        #
        # transfer 75% of overbank volume to the downstream (several cells downstream)
                                                   useDoy = None,
                                                   cloneMapFileName  = None,\
                                                   LatitudeLongitude = True,\
                                                   specificFillValue = None)
areal_groundwater_recharge = pcr.areatotal(groundwater_recharge * cell_area, class_map)/pcr.areatotal(cell_area, class_map)
# - ignore negative groundwater recharge (due to capillary rise)
areal_groundwater_recharge = pcr.max(0.0, areal_groundwater_recharge)

# areal groundwater contribution to meet enviromental flow (unit: m/year)
groundwater_contribution_to_environmental_flow          = pcr.max(0.10, fraction_reserved_recharge * groundwater_recharge)
groundwater_contribution_to_environmental_flow_filename = output_directory + "/" + "groundwater_contribution_to_environmental_flow.m.per.year.map" 
pcr.report(pcr.ifthen(landmask, groundwater_contribution_to_environmental_flow), groundwater_contribution_to_environmental_flow_filename)
areal_groundwater_contribution_to_environmental_flow = pcr.areatotal(groundwater_contribution_to_environmental_flow * cell_area, class_map)/pcr.areatotal(cell_area, class_map) 
areal_groundwater_contribution_to_environmental_flow = pcr.min(0.75 * areal_groundwater_recharge, areal_groundwater_contribution_to_environmental_flow)

# groundwater stress map (dimensionless)
groundwater_stress_map = pcr.ifthen(landmask, \
                             areal_groundwater_abstraction/(pcr.cover(pcr.max(0.001, areal_groundwater_recharge - areal_groundwater_contribution_to_environmental_flow), 0.001)))
# fill in the entire cell
groundwater_stress_map = pcr.ifthen(landmask, \
                         pcr.areamaximum(groundwater_stress_map, class_map_all))
groundwater_stress_map_filename = output_directory + "/" + str(sys.argv[2]) + "_" + str(start_year) + "to" + str(end_year) + ".groundwater_stress.map"
pcr.report(groundwater_stress_map, groundwater_stress_map_filename)
pcr.aguila(groundwater_stress_map)

# groundwater footprint map (km2)
groundwater_footprint_map = groundwater_stress_map * pcr.cover(pcr.areatotal(cell_area, class_map), 0.0) / (1000. * 1000.)
groundwater_footprint_map_filename = output_directory + "/" + str(sys.argv[2]) + "_" + str(start_year) + "to" + str(end_year) + ".groundwater_footprint.km2.map"
pcr.report(groundwater_footprint_map, groundwater_footprint_map_filename)
pcr.aguila(groundwater_footprint_map)
Example #24
0
#~ 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)
Example #25
0
def subcatch_stream(ldd, threshold, stream=None, min_strahler=-999, max_strahler=999, assign_edge=False, assign_existing=False, up_area=None, basin=None):
    """
    Derive catchments based upon strahler threshold
    Input:
        ldd -- pcraster object direction, local drain directions
        threshold -- integer, strahler threshold, subcatchments ge threshold
            are derived
        stream=None -- pcraster object ordinal, stream order map (made with pcr.streamorder), if provided, stream order
            map is not generated on the fly but used from this map. Useful when a subdomain within a catchment is
            provided, which would cause edge effects in the stream order map
        min_strahler=-999 -- integer, minimum strahler threshold of river catchments
            to return
        max_strahler=999 -- integer, maximum strahler threshold of river catchments
            to return
        assign_unique=False -- if set to True, unassigned connected areas at
            the edges of the domain are assigned a unique id as well. If set
            to False, edges are not assigned
        assign_existing=False == if set to True, unassigned edges are assigned
            to existing basins with an upstream weighting. If set to False,
            edges are assigned to unique IDs, or not assigned
    output:
        stream_ge -- pcraster object, streams of strahler order ge threshold
        subcatch -- pcraster object, subcatchments of strahler order ge threshold

    """
    # derive stream order

    if stream is None:
        stream = pcr.streamorder(ldd)

    stream_ge = pcr.ifthen(stream >= threshold, stream)
    stream_up_sum = pcr.ordinal(pcr.upstream(ldd, pcr.cover(pcr.scalar(stream_ge), 0)))
    # detect any transfer of strahler order, to a higher strahler order.
    transition_strahler = pcr.ifthenelse(pcr.downstream(ldd, stream_ge) != stream_ge, pcr.boolean(1),
                                         pcr.ifthenelse(pcr.nominal(ldd) == 5, pcr.boolean(1), pcr.ifthenelse(pcr.downstream(ldd, pcr.scalar(stream_up_sum)) > pcr.scalar(stream_ge), pcr.boolean(1),
                                                                                                              pcr.boolean(0))))
    # make unique ids (write to file)
    transition_unique = pcr.ordinal(pcr.uniqueid(transition_strahler))

    # derive upstream catchment areas (write to file)
    subcatch = pcr.nominal(pcr.subcatchment(ldd, transition_unique))
    # mask out areas outside basin
    if basin is not None:
        subcatch = pcr.ifthen(basin, subcatch)

    if assign_edge:
        # fill unclassified areas (in pcraster equal to zero) with a unique id, above the maximum id assigned so far
        unique_edge = pcr.clump(pcr.ifthen(subcatch==0, pcr.ordinal(0)))
        subcatch = pcr.ifthenelse(subcatch==0, pcr.nominal(pcr.mapmaximum(pcr.scalar(subcatch)) + pcr.scalar(unique_edge)), pcr.nominal(subcatch))
    elif assign_existing:
        # unaccounted areas are added to largest nearest draining basin
        if up_area is None:
            up_area = pcr.ifthen(pcr.boolean(pcr.cover(stream_ge, 0)), pcr.accuflux(ldd, 1))
        riverid = pcr.ifthen(pcr.boolean(pcr.cover(stream_ge, 0)), subcatch)

        friction = 1./pcr.scalar(pcr.spreadzone(pcr.cover(pcr.ordinal(up_area), 0), 0, 0)) # *(pcr.scalar(ldd)*0+1)
        delta = pcr.ifthen(pcr.scalar(ldd)>=0, pcr.ifthen(pcr.cover(subcatch, 0)==0, pcr.spreadzone(pcr.cover(riverid, 0), 0, friction)))
        subcatch = pcr.ifthenelse(pcr.boolean(pcr.cover(subcatch, 0)),
                                      subcatch,
                                      delta)

    # finally, only keep basins with minimum and maximum river order flowing through them
    strahler_subcatch = pcr.areamaximum(stream, subcatch)
    subcatch = pcr.ifthen(pcr.ordinal(strahler_subcatch) >= min_strahler, pcr.ifthen(pcr.ordinal(strahler_subcatch) <= max_strahler, subcatch))

    return stream_ge, pcr.ordinal(subcatch)
                             vos.readPCRmapClone(reservoir_capacity_file, \
                                                 clone_map_file, \
                                                 tmp_folder, \
                                                 None, False, None, False), 0.0)) * 1000. * 1000.
        water_body_id      = vos.readPCRmapClone(water_body_id_file, \
                                                 clone_map_file, \
                                                 tmp_folder, \
                                                 None, False, None, True )
        water_body_id = pcr.ifthen(
            pcr.scalar(water_body_id) > 0.00, water_body_id)
        water_body_id = pcr.ifthen(landmask, water_body_id)
        #
        # water body outlet
        wbCatchment = pcr.catchmenttotal(pcr.scalar(1), ldd_map_low_resolution)
        water_body_outlet  = pcr.ifthen(wbCatchment ==\
                             pcr.areamaximum(wbCatchment, \
                             water_body_id),\
                             water_body_id) # = outlet ids      # This may give more than two outlets, particularly if there are more than one cells that have largest upstream areas
        # - make sure that there is only one outlet for each water body
        water_body_outlet  = pcr.ifthen(\
                             pcr.areaorder(pcr.scalar( water_body_outlet), \
                             water_body_outlet) == 1., water_body_outlet)
        water_body_outlet  = pcr.ifthen(\
                             pcr.scalar(water_body_outlet) > 0., water_body_outlet)

        # calculate overbank volume from reservoirs (and lakes)
        lake_reservoir_volume = pcr.areatotal(extreme_value_map, water_body_id)
        lake_reservoir_overbank_volume = pcr.cover(
            pcr.max(0.0, lake_reservoir_volume - reservoir_capacity), 0.0)
        #~ pcr.aguila(lake_reservoir_overbank_volume)
        #
        # transfer 75% of overbank volume to the downstream (several cells downstream)
                             vos.readPCRmapClone(reservoir_capacity_file, \
                                                 clone_map_file, \
                                                 tmp_folder, \
                                                 None, False, None, False), 0.0)) * 1000. * 1000.
        water_body_id      = vos.readPCRmapClone(water_body_id_file, \
                                                 clone_map_file, \
                                                 tmp_folder, \
                                                 None, False, None, True )
        water_body_id = pcr.ifthen(
            pcr.scalar(water_body_id) > 0.00, water_body_id)
        water_body_id = pcr.ifthen(landmask, water_body_id)
        #
        # water body outlet
        wbCatchment = pcr.catchmenttotal(pcr.scalar(1), ldd_map_low_resolution)
        water_body_outlet  = pcr.ifthen(wbCatchment ==\
                             pcr.areamaximum(wbCatchment, \
                             water_body_id),\
                             water_body_id) # = outlet ids      # This may give more than two outlets, particularly if there are more than one cells that have largest upstream areas
        # - make sure that there is only one outlet for each water body
        water_body_outlet  = pcr.ifthen(\
                             pcr.areaorder(pcr.scalar( water_body_outlet), \
                             water_body_outlet) == 1., water_body_outlet)
        water_body_outlet  = pcr.ifthen(\
                             pcr.scalar(water_body_outlet) > 0., water_body_outlet)

        # calculate overbank volume from reservoirs (and lakes)
        lake_reservoir_volume = pcr.areatotal(extreme_value_map, water_body_id)
        lake_reservoir_overbank_volume = pcr.cover(
            pcr.max(0.0, lake_reservoir_volume - reservoir_capacity), 0.0)
        #~ pcr.aguila(lake_reservoir_overbank_volume)
        #
        # transfer 75% of overbank volume to the downstream (several cells downstream)
Example #28
0
    def getReservoirOutflow(
        self, avgChannelDischarge, length_of_time_step, downstreamDemand
    ):

        # avgOutflow (m3/s)
        avgOutflow = self.avgOutflow
        # The following is needed when new lakes/reservoirs introduced (its avgOutflow is still zero).
        # ~ # - alternative 1
        # ~ avgOutflow = pcr.ifthenelse(\
        # ~ avgOutflow > 0.,\
        # ~ avgOutflow,
        # ~ pcr.max(avgChannelDischarge, self.avgInflow, 0.001))
        # - alternative 2
        avgOutflow = pcr.ifthenelse(
            avgOutflow > 0.0, avgOutflow, pcr.max(avgChannelDischarge, self.avgInflow)
        )
        avgOutflow = pcr.ifthenelse(
            avgOutflow > 0.0, avgOutflow, pcr.downstream(self.lddMap, avgOutflow)
        )
        avgOutflow = pcr.areamaximum(avgOutflow, self.waterBodyIds)

        # calculate resvOutflow (m2/s) (based on reservoir storage and avgDischarge):
        # - using reductionFactor in such a way that:
        #   - if relativeCapacity < minResvrFrac : release is terminated
        #   - if relativeCapacity > maxResvrFrac : longterm average
        reductionFactor = pcr.cover(
            pcr.min(
                1.0,
                pcr.max(
                    0.0, self.waterBodyStorage - self.minResvrFrac * self.waterBodyCap
                )
                / (self.maxResvrFrac - self.minResvrFrac)
                * self.waterBodyCap,
            ),
            0.0,
        )
        #
        resvOutflow = reductionFactor * avgOutflow * length_of_time_step  # unit: m3

        # maximum release <= average inflow (especially during dry condition)
        resvOutflow = pcr.max(
            0, pcr.min(resvOutflow, self.avgInflow * length_of_time_step)
        )  # unit: m3

        # downstream demand (m3/s)
        # reduce demand if storage < lower limit
        reductionFactor = vos.getValDivZero(
            downstreamDemand, self.minResvrFrac * self.waterBodyCap, vos.smallNumber
        )
        reductionFactor = pcr.cover(reductionFactor, 0.0)
        downstreamDemand = pcr.min(downstreamDemand, downstreamDemand * reductionFactor)
        # resvOutflow > downstreamDemand
        resvOutflow = pcr.max(
            resvOutflow, downstreamDemand * length_of_time_step
        )  # unit: m3

        # floodOutflow: additional release if storage > upper limit
        ratioQBankfull = 2.3
        estmStorage = pcr.max(0.0, self.waterBodyStorage - resvOutflow)
        floodOutflow = pcr.max(0.0, estmStorage - self.waterBodyCap) + pcr.cover(
            pcr.max(0.0, estmStorage - self.maxResvrFrac * self.waterBodyCap)
            / ((1.0 - self.maxResvrFrac) * self.waterBodyCap),
            0.0,
        ) * pcr.max(
            0.0, ratioQBankfull * avgOutflow * vos.secondsPerDay() - resvOutflow
        )
        floodOutflow = pcr.max(
            0.0,
            pcr.min(
                floodOutflow, estmStorage - self.maxResvrFrac * self.waterBodyCap * 0.75
            ),
        )  # maximum limit of floodOutflow: bring the reservoir storages only to 3/4 of upper limit capacities

        # update resvOutflow after floodOutflow
        resvOutflow = pcr.cover(resvOutflow, 0.0) + pcr.cover(floodOutflow, 0.0)

        # maximum release if storage > upper limit : bring the reservoir storages only to 3/4 of upper limit capacities
        resvOutflow = pcr.ifthenelse(
            self.waterBodyStorage > self.maxResvrFrac * self.waterBodyCap,
            pcr.min(
                resvOutflow,
                pcr.max(
                    0,
                    self.waterBodyStorage
                    - self.maxResvrFrac * self.waterBodyCap * 0.75,
                ),
            ),
            resvOutflow,
        )

        # if storage > upper limit : resvOutflow > avgInflow
        resvOutflow = pcr.ifthenelse(
            self.waterBodyStorage > self.maxResvrFrac * self.waterBodyCap,
            pcr.max(0.0, resvOutflow, self.avgInflow),
            resvOutflow,
        )

        # resvOutflow < waterBodyStorage
        resvOutflow = pcr.min(self.waterBodyStorage, resvOutflow)

        resvOutflow = pcr.ifthen(pcr.scalar(self.waterBodyIds) > 0.0, resvOutflow)
        resvOutflow = pcr.ifthen(pcr.scalar(self.waterBodyTyp) == 2, resvOutflow)
        return resvOutflow  # unit: m3
#~ pcr.aguila(basin_map)
# - extend/extrapolate the basin
basin_map = pcr.cover(basin_map, pcr.windowmajority(basin_map, 0.5))
basin_map = pcr.cover(basin_map, pcr.windowmajority(basin_map, 0.5))
basin_map = pcr.cover(basin_map, pcr.windowmajority(basin_map, 0.5))
basin_map = pcr.cover(basin_map, pcr.windowmajority(basin_map, 1.0))
basin_map = pcr.cover(basin_map, pcr.windowmajority(basin_map, 1.5))
basin_map = pcr.ifthen(landmask, basin_map)
#~ pcr.aguila(basin_map)

msg = "Redefining the basin map (so that it is consistent with the ldd map used in PCR-GLOBWB):"
logger.info(msg)
# - calculate the upstream area of every pixel:
upstream_area = pcr.catchmenttotal(cell_area, ldd)
# - calculate the catchment area of every basin:
upstream_area_maximum = pcr.areamaximum(upstream_area, basin_map)
# - identify the outlet of every basin (in order to rederive the basin so that it is consistent with the ldd)
outlet = pcr.nominal(pcr.uniqueid(pcr.ifthen(upstream_area == upstream_area_maximum, pcr.boolean(1.0))))
# - ignoring outlets with small upstream areas
threshold = 50. * 1000. * 1000.                                                 # unit: m2
outlet    = pcr.ifthen(upstream_area_maximum > threshold, outlet)
#~ pcr.aguila(outlet)
outlet = pcr.cover(outlet, pcr.nominal(0.0))
# - recalculate the basin
basin_map  = pcr.nominal(pcr.subcatchment(ldd, outlet))
basin_map  = pcr.clump(basin_map)
basin_map  = pcr.ifthen(landmask, basin_map)
pcr.report(basin_map , "basin_map.map")
#~ pcr.aguila(basin_map)
# - calculate the basin area
basin_area = pcr.areatotal(cell_area, basin_map)
Example #30
0
    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)
Example #31
0
def main():
    """
        
    :ivar masterdem: digital elevation model
    :ivar dem: digital elevation model
    :ivar river: optional river map
    """

    # Default values
    strRiver = 8
    masterdem = "dem.map"
    step1dir = "step1"
    step2dir = "step2"
    workdir = "."
    inifile = "wflow_prepare.ini"
    recreate = False
    snapgaugestoriver = False

    try:
        opts, args = getopt.getopt(sys.argv[1:], "W:hI:f")
    except getopt.error as msg:
        usage(msg)

    for o, a in opts:
        if o == "-W":
            workdir = a
        if o == "-I":
            inifile = a
        if o == "-h":
            usage()
        if o == "-f":
            recreate = True

    pcr.setglobaloption("unitcell")
    os.chdir(workdir)

    config = OpenConf(workdir + "/" + inifile)

    masterdem = configget(config, "files", "masterdem", "dem.map")
    pcr.setclone(masterdem)

    strRiver = int(configget(config, "settings", "riverorder", "4"))

    try:
        gauges_x = config.get("settings", "gauges_x")
        gauges_y = config.get("settings", "gauges_y")
    except:
        print("gauges_x and  gauges_y are required entries in the ini file")
        sys.exit(1)

    step1dir = configget(config, "directories", "step1dir", "step1")
    step2dir = configget(config, "directories", "step2dir", "step2")
    # upscalefactor = float(config.get("settings","upscalefactor"))

    corevolume = float(configget(config, "settings", "corevolume", "1E35"))
    catchmentprecipitation = float(
        configget(config, "settings", "catchmentprecipitation", "1E35"))
    corearea = float(configget(config, "settings", "corearea", "1E35"))
    outflowdepth = float(
        configget(config, "settings", "lddoutflowdepth", "1E35"))

    initialscale = int(configget(config, "settings", "initialscale", "1"))
    csize = float(configget(config, "settings", "cellsize", "1"))

    snapgaugestoriver = bool(
        int(configget(config, "settings", "snapgaugestoriver", "1")))
    lddglobaloption = configget(config, "settings", "lddglobaloption",
                                "lddout")
    pcr.setglobaloption(lddglobaloption)
    lu_water = configget(config, "files", "lu_water", "")
    lu_paved = configget(config, "files", "lu_paved", "")

    # X/Y coordinates of the gauges the system
    exec("X=tr.array(" + gauges_x + ")")
    exec("Y=tr.array(" + gauges_y + ")")

    tr.Verbose = 1

    # make the directories to save results in
    mkoutputdirs(step1dir, step2dir)

    ldddem = readdem(initialscale, masterdem, step1dir)
    dem = ldddem

    try:
        catchmask = config.get("files", "catchment_mask")
    except:
        print("No catchment mask...")
    else:
        print("clipping DEM with mask.....")
        mask = pcr.readmap(catchmask)
        ldddem = pcr.ifthen(pcr.boolean(mask), ldddem)
        dem = pcr.ifthen(pcr.boolean(mask), dem)

    # See if there is a shape file of the river to burn in
    try:
        rivshp = config.get("files", "river")
    except:
        print("no river file specified")
        outletpointX = float(
            configget(config, "settings", "outflowpointX", "0.0"))
        outletpointY = float(
            configget(config, "settings", "outflowpointY", "0.0"))
    else:
        print("river file specified.....")
        try:
            outletpointX = float(
                configget(config, "settings", "outflowpointX", "0.0"))
            outletpointY = float(
                configget(config, "settings", "outflowpointY", "0.0"))
        except:
            print(
                "Need to specify the river outletpoint (a point at the end of the river within the current map)"
            )
            exit(1)

        outletpointmap = tr.points_to_map(dem, outletpointX, outletpointY, 0.5)
        pcr.report(outletpointmap, step1dir + "/outletpoint.map")
        rivshpattr = config.get("files", "riverattr")
        pcr.report(dem * 0.0, step1dir + "/nilmap.map")
        thestr = ("gdal_translate -of GTiff " + step1dir + "/nilmap.map " +
                  step1dir + "/riverburn.tif")
        os.system(thestr)
        os.system("gdal_rasterize -burn 1 -l " + rivshpattr + " " + rivshp +
                  " " + step1dir + "/riverburn.tif")
        thestr = ("gdal_translate -of PCRaster " + step1dir +
                  "/riverburn.tif " + step1dir + "/riverburn.map")
        os.system(thestr)
        riverburn = pcr.readmap(step1dir + "/riverburn.map")
        # Determine regional slope assuming that is the way the river should run
        pcr.setglobaloption("unitcell")
        demregional = pcr.windowaverage(dem, 100)
        ldddem = pcr.ifthenelse(riverburn >= 1.0, demregional - 1000, dem)

    pcr.setglobaloption("unittrue")
    upscalefactor = int(csize / pcr.celllength())

    print("Creating ldd...")
    ldd = tr.lddcreate_save(
        step1dir + "/ldd.map",
        ldddem,
        recreate,
        outflowdepth=outflowdepth,
        corevolume=corevolume,
        catchmentprecipitation=catchmentprecipitation,
        corearea=corearea,
    )

    print("Determining streamorder...")
    stro = pcr.streamorder(ldd)
    pcr.report(stro, step1dir + "/streamorder.map")
    strdir = pcr.ifthen(stro >= strRiver, stro)
    pcr.report(strdir, step1dir + "/streamorderrive.map")
    pcr.report(pcr.boolean(pcr.ifthen(stro >= strRiver, stro)),
               step1dir + "/rivers.map")

    pcr.setglobaloption("unittrue")
    # outlet (and other gauges if given)
    # TODO: check is x/y set if not skip this
    print("Outlet...")

    outlmap = tr.points_to_map(dem, X, Y, 0.5)

    if snapgaugestoriver:
        print("Snapping gauges to nearest river cells...")
        pcr.report(outlmap, step1dir + "/orggauges.map")
        outlmap = tr.snaptomap(outlmap, strdir)

    # noutletmap = tr.points_to_map(dem,XX,YY,0.5)
    # pcr.report(noutletmap,'noutlet.map')

    pcr.report(outlmap, step1dir + "/gauges.map")

    # check if there is a pre-define catchment map
    try:
        catchmask = config.get("files", "catchment_mask")
    except:
        print("No catchment mask, finding outlet")
        # Find catchment (overall)
        outlet = tr.find_outlet(ldd)
        sub = pcr.subcatch(ldd, outlet)
        pcr.report(sub, step1dir + "/catchment_overall.map")
    else:
        print("reading and converting catchment mask.....")
        os.system("resample -r " + str(initialscale) + " " + catchmask + " " +
                  step1dir + "/catchment_overall.map")
        sub = pcr.readmap(step1dir + "/catchment_overall.map")

    print("Scatch...")
    sd = pcr.subcatch(ldd, pcr.ifthen(outlmap > 0, outlmap))
    pcr.report(sd, step1dir + "/scatch.map")

    pcr.setglobaloption("unitcell")
    print("Upscalefactor: " + str(upscalefactor))

    if upscalefactor > 1:
        gc.collect()
        print("upscale river length1 (checkerboard map)...")
        ck = tr.checkerboard(dem, upscalefactor)
        pcr.report(ck, step1dir + "/ck.map")
        pcr.report(dem, step1dir + "/demck.map")
        print("upscale river length2...")
        fact = tr.area_riverlength_factor(ldd, ck, upscalefactor)
        pcr.report(fact, step1dir + "/riverlength_fact.map")

        # print("make dem statistics...")
        dem_ = pcr.areaaverage(dem, ck)
        pcr.report(dem_, step1dir + "/demavg.map")

        print("Create DEM statistics...")
        dem_ = pcr.areaminimum(dem, ck)
        pcr.report(dem_, step1dir + "/demmin.map")
        dem_ = pcr.areamaximum(dem, ck)
        pcr.report(dem_, step1dir + "/demmax.map")
        # calculate percentiles
        order = pcr.areaorder(dem, ck)
        n = pcr.areatotal(pcr.spatial(pcr.scalar(1.0)), ck)
        #: calculate 25 percentile
        perc = tr.area_percentile(dem, ck, n, order, 25.0)
        pcr.report(perc, step1dir + "/dem25.map")
        perc = tr.area_percentile(dem, ck, n, order, 10.0)
        pcr.report(perc, step1dir + "/dem10.map")
        perc = tr.area_percentile(dem, ck, n, order, 50.0)
        pcr.report(perc, step1dir + "/dem50.map")
        perc = tr.area_percentile(dem, ck, n, order, 33.0)
        pcr.report(perc, step1dir + "/dem33.map")
        perc = tr.area_percentile(dem, ck, n, order, 66.0)
        pcr.report(perc, step1dir + "/dem66.map")
        perc = tr.area_percentile(dem, ck, n, order, 75.0)
        pcr.report(perc, step1dir + "/dem75.map")
        perc = tr.area_percentile(dem, ck, n, order, 90.0)
        pcr.report(perc, step1dir + "/dem90.map")
    else:
        print("No fancy scaling done. Going strait to step2....")
        pcr.report(dem, step1dir + "/demavg.map")
        Xul = float(config.get("settings", "Xul"))
        Yul = float(config.get("settings", "Yul"))
        Xlr = float(config.get("settings", "Xlr"))
        Ylr = float(config.get("settings", "Ylr"))
        gdalstr = ("gdal_translate  -projwin " + str(Xul) + " " + str(Yul) +
                   " " + str(Xlr) + " " + str(Ylr) + " -of PCRaster  ")
        # gdalstr = "gdal_translate  -a_ullr " + str(Xul) + " " + str(Yul) + " " +str(Xlr) + " " +str(Ylr) + " -of PCRaster  "
        print(gdalstr)
        pcr.report(pcr.cover(1.0), step1dir + "/wflow_riverlength_fact.map")
        # Now us gdat tp convert the maps
        os.system(gdalstr + step1dir + "/wflow_riverlength_fact.map" + " " +
                  step2dir + "/wflow_riverlength_fact.map")
        os.system(gdalstr + step1dir + "/demavg.map" + " " + step2dir +
                  "/wflow_dem.map")
        os.system(gdalstr + step1dir + "/demavg.map" + " " + step2dir +
                  "/wflow_demmin.map")
        os.system(gdalstr + step1dir + "/demavg.map" + " " + step2dir +
                  "/wflow_demmax.map")
        os.system(gdalstr + step1dir + "/gauges.map" + " " + step2dir +
                  "/wflow_gauges.map")
        os.system(gdalstr + step1dir + "/rivers.map" + " " + step2dir +
                  "/wflow_river.map")
        os.system(gdalstr + step1dir + "/streamorder.map" + " " + step2dir +
                  "/wflow_streamorder.map")
        os.system(gdalstr + step1dir + "/gauges.map" + " " + step2dir +
                  "/wflow_outlet.map")
        os.system(gdalstr + step1dir + "/scatch.map" + " " + step2dir +
                  "/wflow_catchment.map")
        os.system(gdalstr + step1dir + "/ldd.map" + " " + step2dir +
                  "/wflow_ldd.map")
        os.system(gdalstr + step1dir + "/scatch.map" + " " + step2dir +
                  "/wflow_subcatch.map")

        if lu_water:
            os.system(gdalstr + lu_water + " " + step2dir + "/WaterFrac.map")

        if lu_paved:
            os.system(gdalstr + lu_paved + " " + step2dir + "/PathFrac.map")

        try:
            lumap = config.get("files", "landuse")
        except:
            print("no landuse map...creating uniform map")
            # clone=pcr.readmap(step2dir + "/wflow_dem.map")
            pcr.setclone(step2dir + "/wflow_dem.map")
            pcr.report(pcr.nominal(1), step2dir + "/wflow_landuse.map")
        else:
            os.system("resample --clone " + step2dir + "/wflow_dem.map " +
                      lumap + " " + step2dir + "/wflow_landuse.map")

        try:
            soilmap = config.get("files", "soil")
        except:
            print("no soil map..., creating uniform map")
            pcr.setclone(step2dir + "/wflow_dem.map")
            pcr.report(pcr.nominal(1), step2dir + "/wflow_soil.map")
        else:
            os.system("resample --clone " + step2dir + "/wflow_dem.map " +
                      soilmap + " " + step2dir + "/wflow_soil.map")

    ##################################
    # Step 2 starts here
    ##################################

    pcr.setclone(step2dir + "/cutout.map")

    strRiver = int(configget(config, "settings", "riverorder_step2", "4"))

    corevolume = float(configget(config, "settings", "corevolume", "1E35"))
    catchmentprecipitation = float(
        configget(config, "settings", "catchmentprecipitation", "1E35"))
    corearea = float(configget(config, "settings", "corearea", "1E35"))
    outflowdepth = float(
        configget(config, "settings", "lddoutflowdepth", "1E35"))
    lddmethod = configget(config, "settings", "lddmethod", "dem")
    lddglobaloption = configget(config, "settings", "lddglobaloption",
                                "lddout")
    pcr.setglobaloption(lddglobaloption)

    nrrow = round(abs(Yul - Ylr) / csize)
    nrcol = round(abs(Xlr - Xul) / csize)
    mapstr = ("mapattr -s -S -R " + str(nrrow) + " -C " + str(nrcol) + " -l " +
              str(csize) + " -x " + str(Xul) + " -y " + str(Yul) +
              " -P yb2t " + step2dir + "/cutout.map")

    os.system(mapstr)
    pcr.setclone(step2dir + "/cutout.map")

    lu_water = configget(config, "files", "lu_water", "")
    lu_paved = configget(config, "files", "lu_paved", "")

    if lu_water:
        os.system("resample --clone " + step2dir + "/cutout.map " + lu_water +
                  " " + step2dir + "/wflow_waterfrac.map")

    if lu_paved:
        os.system("resample --clone " + step2dir + "/cutout.map " + lu_paved +
                  " " + step2dir + "/PathFrac.map")

    #
    try:
        lumap = config.get("files", "landuse")
    except:
        print("no landuse map...creating uniform map")
        clone = pcr.readmap(step2dir + "/cutout.map")
        pcr.report(pcr.nominal(clone), step2dir + "/wflow_landuse.map")
    else:
        os.system("resample --clone " + step2dir + "/cutout.map " + lumap +
                  " " + step2dir + "/wflow_landuse.map")

    try:
        soilmap = config.get("files", "soil")
    except:
        print("no soil map..., creating uniform map")
        clone = pcr.readmap(step2dir + "/cutout.map")
        pcr.report(pcr.nominal(clone), step2dir + "/wflow_soil.map")
    else:
        os.system("resample --clone " + step2dir + "/cutout.map " + soilmap +
                  " " + step2dir + "/wflow_soil.map")

    resamplemaps(step1dir, step2dir)

    dem = pcr.readmap(step2dir + "/wflow_dem.map")
    demmin = pcr.readmap(step2dir + "/wflow_demmin.map")
    demmax = pcr.readmap(step2dir + "/wflow_demmax.map")
    catchcut = pcr.readmap(step2dir + "/catchment_cut.map")
    # now apply the area of interest (catchcut) to the DEM
    # dem=pcr.ifthen(catchcut >=1 , dem)
    #

    # See if there is a shape file of the river to burn in
    try:
        rivshp = config.get("files", "river")
    except:
        print("no river file specified")
        riverburn = pcr.readmap(step2dir + "/wflow_riverburnin.map")
    else:
        print("river file speficied.....")
        rivshpattr = config.get("files", "riverattr")
        pcr.report(dem * 0.0, step2dir + "/nilmap.map")
        thestr = ("gdal_translate -of GTiff " + step2dir + "/nilmap.map " +
                  step2dir + "/wflow_riverburnin.tif")
        os.system(thestr)
        os.system("gdal_rasterize -burn 1 -l " + rivshpattr + " " + rivshp +
                  " " + step2dir + "/wflow_riverburnin.tif")
        thestr = ("gdal_translate -of PCRaster " + step2dir +
                  "/wflow_riverburnin.tif " + step2dir +
                  "/wflow_riverburnin.map")
        os.system(thestr)
        riverburn = pcr.readmap(step2dir + "/wflow_riverburnin.map")
        # ldddem = pcr.ifthenelse(riverburn >= 1.0, dem -1000 , dem)

    # Only burn within the original catchment
    riverburn = pcr.ifthen(pcr.scalar(catchcut) >= 1, riverburn)
    # Now setup a very high wall around the catchment that is scale
    # based on the distance to the catchment so that it slopes away from the
    # catchment
    if lddmethod != "river":
        print("Burning in highres-river ...")
        disttocatch = pcr.spread(pcr.nominal(catchcut), 0.0, 1.0)
        demmax = pcr.ifthenelse(
            pcr.scalar(catchcut) >= 1.0,
            demmax,
            demmax + (pcr.celllength() * 100.0) / disttocatch,
        )
        pcr.setglobaloption("unitcell")
        demregional = pcr.windowaverage(demmin, 100)
        demburn = pcr.cover(
            pcr.ifthen(pcr.boolean(riverburn), demregional - 100.0), demmax)
    else:
        print("using average dem..")
        demburn = dem

    ldd = tr.lddcreate_save(
        step2dir + "/ldd.map",
        demburn,
        True,
        outflowdepth=outflowdepth,
        corevolume=corevolume,
        catchmentprecipitation=catchmentprecipitation,
        corearea=corearea,
    )

    # Find catchment (overall)
    outlet = tr.find_outlet(ldd)
    sub = pcr.subcatch(ldd, outlet)
    pcr.report(sub, step2dir + "/wflow_catchment.map")
    pcr.report(outlet, step2dir + "/wflow_outlet.map")

    # make river map
    strorder = pcr.streamorder(ldd)
    pcr.report(strorder, step2dir + "/wflow_streamorder.map")

    river = pcr.ifthen(pcr.boolean(strorder >= strRiver), strorder)
    pcr.report(river, step2dir + "/wflow_river.map")

    # make subcatchments
    # os.system("col2map --clone " + step2dir + "/cutout.map gauges.col " + step2dir + "/wflow_gauges.map")
    exec("X=tr.array(" + gauges_x + ")")
    exec("Y=tr.array(" + gauges_y + ")")

    pcr.setglobaloption("unittrue")

    outlmap = tr.points_to_map(dem, X, Y, 0.5)
    pcr.report(outlmap, step2dir + "/wflow_gauges_.map")

    if snapgaugestoriver:
        print("Snapping gauges to river")
        pcr.report(outlmap, step2dir + "/wflow_orggauges.map")
        outlmap = tr.snaptomap(outlmap, river)

    outlmap = pcr.ifthen(outlmap > 0, outlmap)
    pcr.report(outlmap, step2dir + "/wflow_gauges.map")

    scatch = pcr.subcatch(ldd, outlmap)
    pcr.report(scatch, step2dir + "/wflow_subcatch.map")
Example #32
0
def pcr_inun(dem, ids, h_bounds, ids_coastline,
                resistance=0.,  water_perc=None, zero_resistance_waterp=1.0,
                cellres=1, dist_method='eucledian', ldd=None):
    """ planar inundation routine per segment

    :param dem:             pcr dem
    :param ids:             local ids of boundary conditions, starting a 1 (not zero!)
    :param h_bounds:        water level boundary at diva segment
    :param ids_coastline:   pcraster map with coastal segments ids
    :param resistance:      constant or pcrmap unit km-1; (default 0: no resistance is calculated)
    :param cellres:         cell resolution in km, varies with latitude degrees
    :param ldd:             pcraster map with local drainage direction to calculate resistance along ldd;
                            if None (default) resistance is calculated using 'plain' nearest neighbour


    :return:                pcrmap with flood depth
    """
    pcr.setglobaloption("unitcell")
    if resistance > 0:
        coastline = pcr.cover(pcr.ifthenelse(pcr.scalar(ids_coastline) > 0, pcr.boolean(1), 0), pcr.boolean(0))
        mask = pcr.ifthen(dem > -9999, pcr.scalar(1))
        if dist_method == 'ldd':
            # Distance to coast along ldd
            dist2coast0 = pcr.ldddist(ldd, coastline, cellres)
            # find edge of area with distances -> water divide
            dist2coast_mask = pcr.cover(pcr.ifthenelse(dist2coast0 > 0, pcr.boolean(0), pcr.boolean(1)),
                                        pcr.boolean(1))
            start = pcr.ifthenelse(
                ((pcr.window4total(pcr.scalar(dist2coast_mask)) > 0) & (dist2coast_mask == pcr.boolean(0))) |
                coastline,
                pcr.boolean(1), pcr.boolean(0))
            # continue distance beyond water divide with eucledian dist
            dist2coast1 = pcr.spread(start, dist2coast0, cellres*mask)
            dist2coast = pcr.ifthenelse(dist2coast_mask, dist2coast1, dist2coast0)

        elif dist_method == 'eucledian':
            # dist to coast using nearest neighbor
            if water_perc is None:
                dist2coast = pcr.spread(coastline, 0, cellres*mask)
            else:
                # zero resistance for cells with water_perc >= zero_resistance_waterp
                zrw = float(zero_resistance_waterp)
                water_perc = pcr.ifthenelse(water_perc >= zrw,
                                            pcr.scalar(1),
                                            water_perc / zrw)
                dist2coast = pcr.spread(coastline, 0, cellres*mask*(1 - water_perc))

        dem_adjust = dem + pcr.cover(dist2coast, 0) * pcr.scalar(resistance)   # raise the elevation using a damping factor
    else:
        dem_adjust = dem
        dist2coast = pcr.scalar(1)

    fld_depth = pcr.ifthen(dem > -9999, pcr.scalar(0))

    for i, h in zip(ids, h_bounds):
        coast_segment = pcr.ifthenelse(ids_coastline == i, pcr.boolean(1), pcr.boolean(0))

        # find area below flood_level
        fld_prone = pcr.ifthenelse(dem_adjust <= pcr.scalar(float(h)), pcr.boolean(1), pcr.boolean(0))
        # make contiguous groups of cells which are below flood level
        fld_clump = pcr.clump(fld_prone)
        # find flooded area connected to diva segment
        fld_coast = pcr.ifthenelse(pcr.areamaximum(pcr.scalar(fld_clump) * pcr.scalar(coast_segment), fld_clump) > 0,
                                   pcr.boolean(1), pcr.boolean(0))
        # get max fld depth map
        fld_depth = pcr.max(fld_depth, pcr.ifthenelse(fld_coast, pcr.scalar(pcr.scalar(float(h)) - dem_adjust), 0))

    return fld_depth, dist2coast, dem_adjust