Example #1
0
def subcatch_stream(ldd, stream, threshold):
    """
    Derive catchments based upon strahler threshold
    Input:
        ldd -- pcraster object direction, local drain directions
        stream -- pcraster object direction, streamorder
        threshold -- integer, strahler threshold, subcatchments ge threshold are
                 derived
    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))
    return stream_ge, subcatch
Example #2
0
 def returnFloodedFraction(self, volume):
     #-returns the flooded fraction given the flood volume and the associated water height
     # using a logistic smoother near intersections (K&K, 2007)
     #-find the match on the basis of the shortest distance to the available intersections or steps
     deltaXMin = self.floodVolume[self.nrEntries - 1]
     y_i = pcr.scalar(1.)
     k = [pcr.scalar(0.)] * 2
     mInt = pcr.scalar(0.)
     for iCnt in range(self.nrEntries - 1, 0, -1):
         #-find x_i for current volume and update match if applicable
         # also update slope and intercept
         deltaX = volume - self.floodVolume[iCnt]
         mask = pcr.abs(deltaX) < pcr.abs(deltaXMin)
         deltaXMin = pcr.ifthenelse(mask, deltaX, deltaXMin)
         y_i = pcr.ifthenelse(mask, self.areaFractions[iCnt], y_i)
         k[0] = pcr.ifthenelse(mask, self.kSlope[iCnt - 1], k[0])
         k[1] = pcr.ifthenelse(mask, self.kSlope[iCnt], k[1])
         mInt = pcr.ifthenelse(mask, self.mInterval[iCnt], mInt)
     #-all values returned, process data: calculate scaled deltaX and smoothed function
     # on the basis of the integrated logistic functions PHI(x) and 1-PHI(x)
     deltaX = deltaXMin
     deltaXScaled= pcr.ifthenelse(deltaX < 0.,pcr.scalar(-1.),1.)*\
      pcr.min(criterionKK,pcr.abs(deltaX/pcr.max(1.,mInt)))
     logInt = self.integralLogisticFunction(deltaXScaled)
     #-compute fractional flooded area and flooded depth
     floodedFraction= pcr.ifthenelse(volume > 0.,\
      pcr.ifthenelse(pcr.abs(deltaXScaled) < criterionKK,\
      y_i-k[0]*mInt*logInt[0]+k[1]*mInt*logInt[1],\
      y_i+pcr.ifthenelse(deltaX < 0.,k[0],k[1])*deltaX),0.)
     floodedFraction = pcr.max(0., pcr.min(1., floodedFraction))
     floodDepth = pcr.ifthenelse(floodedFraction > 0.,
                                 volume / (floodedFraction * self.cellArea),
                                 0.)
     return floodedFraction, floodDepth
Example #3
0
def detdrainlength(ldd, xl, yl):
    """
    Determines the drainaige length (DCL) for a non square grid

    Input:
        - ldd - drainage network
        - xl - length of cells in x direction
        - yl - length of cells in y direction

    Output:
        - DCL
    """
    # take into account non-square cells
    # if ldd is 8 or 2 use Ylength
    # if ldd is 4 or 6 use Xlength
    draindir = pcr.scalar(ldd)
    slantlength = pcr.sqrt(xl ** 2 + yl ** 2)
    drainlength = pcr.ifthenelse(
        draindir == 2,
        yl,
        pcr.ifthenelse(
            draindir == 8,
            yl,
            pcr.ifthenelse(
                draindir == 4, xl, pcr.ifthenelse(draindir == 6, xl, slantlength)
            ),
        ),
    )

    return drainlength
Example #4
0
    def getWaterBodyDimensions(self):

        # Lake properties max depth and total lake area
        lakeMaxDepth = ((3.0 * self.waterBodyStorage) /
                        (self.waterBodyShapeFactor**2))**(1. / 3.)
        lakeArea = (lakeMaxDepth * self.waterBodyShapeFactor)**2

        # reservoir properties max depth at outlet and total reservoir area
        reservoirMaxDepth = ((6.0 * self.waterBodyStorage) /
                             (self.waterBodyShapeFactor**2))**(1. / 3.)
        reservoirArea = 0.5 * (reservoirMaxDepth *
                               self.waterBodyShapeFactor)**2

        # dynamic waterbody area, cannot exceed static waterbody extent as defined by input
        self.dynamicArea = pcr.cover(pcr.ifthenelse(pcr.scalar(self.waterBodyTyp) == 1, lakeArea,\
                              pcr.ifthen(pcr.scalar(self.waterBodyTyp) == 2, reservoirArea)), 0.)

        self.dynamicArea = pcr.min(self.dynamicArea, self.waterBodyArea)

        # dynamic water fraction in gridcell
        self.dynamicFracWat = self.dynamicArea * self.waterBodyRelativeFrac / self.cellArea  #TODO check if this is correct

        self.dynamicFracWat = pcr.cover(
            pcr.min(pcr.max(self.dynamicFracWat, 0.), self.fracWat), 0.)
        self.dynamicFracWat = self.fracWat  #TODO remove this line
        self.dynamicFracWat = ifthen(self.landmask, self.dynamicFracWat)


        self.maxWaterDepth  = pcr.cover(pcr.ifthenelse(pcr.scalar(self.waterBodyTyp) == 1, lakeMaxDepth,\
                              pcr.ifthen(pcr.scalar(self.waterBodyTyp) == 2, reservoirMaxDepth)))
Example #5
0
def subcatch_stream(ldd, stream, threshold):
    """
    Derive catchments based upon strahler threshold
    Input:
        ldd -- pcraster object direction, local drain directions
        stream -- pcraster object direction, streamorder
        threshold -- integer, strahler threshold, subcatchments ge threshold are
                 derived
    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))
    return stream_ge, subcatch
Example #6
0
def detdrainwidth(ldd, xl, yl):
    """
    Determines width of drainage over DEM for a non square grid

    Input:
        - ldd - drainage network
        - xl - length of cells in x direction
        - yl - length of cells in y direction

    Output:
        - DCL
    """
    # take into account non-square cells
    # if ldd is 8 or 2 use Xlength
    # if ldd is 4 or 6 use Ylength
    draindir = pcr.scalar(ldd)
    slantwidth = (xl + yl) * 0.5
    drainwidth = pcr.ifthenelse(
        draindir == 2,
        xl,
        pcr.ifthenelse(
            draindir == 8,
            xl,
            pcr.ifthenelse(
                draindir == 4, yl, pcr.ifthenelse(draindir == 6, yl, slantwidth)
            ),
        ),
    )
    return drainwidth
Example #7
0
def detdrainwidth(ldd, xl, yl):
    """
    Determines width of drainage over DEM for a non square grid

    Input:
        - ldd - drainage network
        - xl - length of cells in x direction
        - yl - length of cells in y direction

    Output:
        - DCL
    """
    # take into account non-square cells
    # if ldd is 8 or 2 use Xlength
    # if ldd is 4 or 6 use Ylength
    draindir = pcr.scalar(ldd)
    slantwidth = (xl + yl) * 0.5
    drainwidth = pcr.ifthenelse(
        draindir == 2,
        xl,
        pcr.ifthenelse(
            draindir == 8,
            xl,
            pcr.ifthenelse(
                draindir == 4, yl, pcr.ifthenelse(draindir == 6, yl, slantwidth)
            ),
        ),
    )
    return drainwidth
	def returnFloodedFraction(self,volume):
		#-returns the flooded fraction given the flood volume and the associated water height
		# using a logistic smoother near intersections (K&K, 2007)
		#-find the match on the basis of the shortest distance to the available intersections or steps
		deltaXMin= self.floodVolume[self.nrEntries-1]
		y_i= pcr.scalar(1.)
		k= [pcr.scalar(0.)]*2
		mInt= pcr.scalar(0.)
		for iCnt in range(self.nrEntries-1,0,-1):
			#-find x_i for current volume and update match if applicable
			# also update slope and intercept
			deltaX= volume-self.floodVolume[iCnt]
			mask= pcr.abs(deltaX) < pcr.abs(deltaXMin)
			deltaXMin= pcr.ifthenelse(mask,deltaX,deltaXMin)
			y_i= pcr.ifthenelse(mask,self.areaFractions[iCnt],y_i)
			k[0]= pcr.ifthenelse(mask,self.kSlope[iCnt-1],k[0])
			k[1]= pcr.ifthenelse(mask,self.kSlope[iCnt],k[1])
			mInt= pcr.ifthenelse(mask,self.mInterval[iCnt],mInt)
		#-all values returned, process data: calculate scaled deltaX and smoothed function
		# on the basis of the integrated logistic functions PHI(x) and 1-PHI(x)
		deltaX= deltaXMin
		deltaXScaled= pcr.ifthenelse(deltaX < 0.,pcr.scalar(-1.),1.)*\
			pcr.min(criterionKK,pcr.abs(deltaX/pcr.max(1.,mInt)))
		logInt= self.integralLogisticFunction(deltaXScaled)
		#-compute fractional flooded area and flooded depth
		floodedFraction= pcr.ifthenelse(volume > 0.,\
			pcr.ifthenelse(pcr.abs(deltaXScaled) < criterionKK,\
			y_i-k[0]*mInt*logInt[0]+k[1]*mInt*logInt[1],\
			y_i+pcr.ifthenelse(deltaX < 0.,k[0],k[1])*deltaX),0.)
		floodedFraction= pcr.max(0.,pcr.min(1.,floodedFraction))
		floodDepth= pcr.ifthenelse(floodedFraction > 0.,volume/(floodedFraction*self.cellArea),0.)
		return floodedFraction, floodDepth
Example #9
0
def detdrainlength(ldd, xl, yl):
    """
    Determines the drainaige length (DCL) for a non square grid

    Input:
        - ldd - drainage network
        - xl - length of cells in x direction
        - yl - length of cells in y direction

    Output:
        - DCL
    """
    # take into account non-square cells
    # if ldd is 8 or 2 use Ylength
    # if ldd is 4 or 6 use Xlength
    draindir = pcr.scalar(ldd)
    slantlength = pcr.sqrt(xl ** 2 + yl ** 2)
    drainlength = pcr.ifthenelse(
        draindir == 2,
        yl,
        pcr.ifthenelse(
            draindir == 8,
            yl,
            pcr.ifthenelse(
                draindir == 4, xl, pcr.ifthenelse(draindir == 6, xl, slantlength)
            ),
        ),
    )

    return drainlength
Example #10
0
def SnowPackHBV(Snow, SnowWater, Precipitation, Temperature, TTI, TT, TTM,
                Cfmax, WHC):
    """
    HBV Type snowpack modelling using a Temperature degree factor. All correction
    factors (RFCF and SFCF) are set to 1. The refreezing efficiency factor is set to 0.05.

    :param Snow:
    :param SnowWater:
    :param Precipitation:
    :param Temperature:
    :param TTI:
    :param TT:
    :param TTM:
    :param Cfmax:
    :param WHC:
    :return: Snow,SnowMelt,Precipitation
    """

    RFCF = 1.0  # correction factor for rainfall
    CFR = 0.05000  # refreeing efficiency constant in refreezing of freewater in snow
    SFCF = 1.0  # correction factor for snowfall

    RainFrac = pcr.ifthenelse(
        1.0 * TTI == 0.0,
        pcr.ifthenelse(Temperature <= TT, pcr.scalar(0.0), pcr.scalar(1.0)),
        pcr.min((Temperature - (TT - TTI / 2)) / TTI, pcr.scalar(1.0)),
    )
    RainFrac = pcr.max(
        RainFrac,
        pcr.scalar(0.0))  # fraction of precipitation which falls as rain
    SnowFrac = 1 - RainFrac  # fraction of precipitation which falls as snow
    Precipitation = (SFCF * SnowFrac * Precipitation +
                     RFCF * RainFrac * Precipitation
                     )  # different correction for rainfall and snowfall

    SnowFall = SnowFrac * Precipitation  # snowfall depth
    RainFall = RainFrac * Precipitation  # rainfall depth
    PotSnowMelt = pcr.ifthenelse(
        Temperature > TTM, Cfmax * (Temperature - TTM),
        pcr.scalar(0.0))  # Potential snow melt, based on temperature
    PotRefreezing = pcr.ifthenelse(
        Temperature < TTM, Cfmax * CFR * (TTM - Temperature),
        0.0)  # Potential refreezing, based on temperature
    Refreezing = pcr.ifthenelse(Temperature < TTM,
                                pcr.min(PotRefreezing, SnowWater),
                                0.0)  # actual refreezing
    # No landuse correction here
    SnowMelt = pcr.min(PotSnowMelt, Snow)  # actual snow melt
    Snow = Snow + SnowFall + Refreezing - SnowMelt  # dry snow content
    SnowWater = SnowWater - Refreezing  # free water content in snow
    MaxSnowWater = Snow * WHC  # Max water in the snow
    SnowWater = (SnowWater + SnowMelt + RainFall
                 )  # Add all water and potentially supersaturate the snowpack
    RainFall = pcr.max(SnowWater - MaxSnowWater,
                       0.0)  # rain + surpluss snowwater
    SnowWater = SnowWater - RainFall

    return Snow, SnowWater, SnowMelt, RainFall, SnowFall
Example #11
0
def volume_spread(ldd,
                  hand,
                  subcatch,
                  volume,
                  volume_thres=0.,
                  area_multiplier=1.,
                  iterations=15):
    """
    Estimate 2D flooding from a 1D simulation per subcatchment reach
    Input:
        ldd -- pcraster object direction, local drain directions
        hand -- pcraster object float32, elevation data normalised to nearest drain
        subcatch -- pcraster object ordinal, subcatchments with IDs
        volume -- pcraster object float32, scalar flood volume (i.e. m3 volume outside the river bank within subcatchment)
        volume_thres=0. -- scalar threshold, at least this amount of m3 of volume should be present in a catchment
        area_multiplier=1. -- in case the maps are not in m2, set a multiplier other than 1. to convert
        iterations=15 -- number of iterations to use
    Output:
        inundation -- pcraster object float32, scalar inundation estimate
    """
    #initial values
    pcr.setglobaloption("unittrue")
    dem_min = pcr.areaminimum(hand,
                              subcatch)  # minimum elevation in subcatchments
    # pcr.report(dem_min, 'dem_min.map')
    dem_norm = hand - dem_min
    # pcr.report(dem_norm, 'dem_norm.map')
    # surface of each subcatchment
    surface = pcr.areaarea(subcatch) * area_multiplier
    pcr.report(surface, 'surface.map')

    error_abs = pcr.scalar(1e10)  # initial error (very high)
    volume_catch = pcr.areatotal(volume, subcatch)
    # pcr.report(volume_catch, 'volume_catch.map')

    depth_catch = volume_catch / surface
    pcr.report(depth_catch, 'depth_catch.map')

    dem_max = pcr.ifthenelse(volume_catch > volume_thres, pcr.scalar(32.),
                             pcr.scalar(0))  # bizarre high inundation depth
    dem_min = pcr.scalar(0.)
    for n in range(iterations):
        print('Iteration: {:02d}'.format(n + 1))
        #####while np.logical_and(error_abs > error_thres, dem_min < dem_max):
        dem_av = (dem_min + dem_max) / 2
        # pcr.report(dem_av, 'dem_av00.{:03d}'.format(n + 1))
        # compute value at dem_av
        average_depth_catch = pcr.areaaverage(pcr.max(dem_av - dem_norm, 0),
                                              subcatch)
        # pcr.report(average_depth_catch, 'depth_c0.{:03d}'.format(n + 1))
        error = pcr.cover((depth_catch - average_depth_catch) / depth_catch,
                          depth_catch * 0)
        # pcr.report(error, 'error000.{:03d}'.format(n + 1))
        dem_min = pcr.ifthenelse(error > 0, dem_av, dem_min)
        dem_max = pcr.ifthenelse(error <= 0, dem_av, dem_max)
    # error_abs = np.abs(error)  # TODO: not needed probably, remove
    inundation = pcr.max(dem_av - dem_norm, 0)
    return inundation
Example #12
0
def derive_HAND(dem,
                ldd,
                accuThreshold,
                rivers=None,
                basin=None,
                up_area=None):
    """
    Function derives Height-Above-Nearest-Drain.
    See http://www.sciencedirect.com/science/article/pii/S003442570800120X
    Input:
        dem -- pcraster object float32, elevation data
        ldd -- pcraster object direction, local drain directions
        accuThreshold -- upstream amount of cells as threshold for river
            delineation
        rivers=None -- you can provide a rivers layer here. Pixels that are
                        identified as river should have a value > 0, other
                        pixels a value of zero.
        basin=None -- set a boolean pcraster map where areas with True are estimated using the nearest drain in ldd distance
                        and areas with False by means of the nearest friction distance. Friction distance estimated using the
                        upstream area as weight (i.e. drains with a bigger upstream area have a lower friction)
                        the spreadzone operator is used in this case.
        up_area=None -- provide the upstream area (if not assigned a guesstimate is prepared, assuming the LDD covers a
                        full catchment area)
    Output:
        hand -- pcraster bject float32, height, normalised to nearest stream
        dist -- distance to nearest stream measured in cell lengths
            according to D8 directions
    """
    if rivers is None:
        # prepare stream from a strahler threshold
        stream = pcr.ifthenelse(
            pcr.accuflux(ldd, 1) >= accuThreshold, pcr.boolean(1),
            pcr.boolean(0))
    else:
        # convert stream network to boolean
        stream = pcr.boolean(pcr.cover(rivers, 0))
    # determine height in river (in DEM*100 unit as ordinal)
    height_river = pcr.ifthenelse(stream, pcr.ordinal(dem * 100), 0)
    if basin is None:
        up_elevation = pcr.scalar(pcr.subcatchment(ldd, height_river))
    else:
        # use basin to allocate areas outside basin to the nearest stream. Nearest is weighted by upstream area
        if up_area is None:
            up_area = pcr.accuflux(ldd, 1)
        up_area = pcr.ifthen(stream, up_area)  # mask areas outside streams
        friction = 1. / pcr.scalar(
            pcr.spreadzone(pcr.cover(pcr.ordinal(up_area), 0), 0, 0))
        # if basin, use nearest river within subcatchment, if outside basin, use weighted-nearest river
        up_elevation = pcr.ifthenelse(
            basin, pcr.scalar(pcr.subcatchment(ldd, height_river)),
            pcr.scalar(pcr.spreadzone(height_river, 0, friction)))
        # replace areas outside of basin by a spread zone calculation.
    hand = pcr.max(pcr.scalar(pcr.ordinal(dem * 100)) - up_elevation,
                   0) / 100  # convert back to float in DEM units
    # hand = (pcr.scalar(pcr.ordinal(dem*100))-up_elevation)/100  # convert back to float in DEM units
    dist = pcr.ldddist(ldd, stream, 1)  # compute horizontal distance estimate
    return hand, dist
def fractionXY(surface):
  #-returns the fraction of transport in the x- and y-directions
  # given a gradient in a surface
  aspect= pcr.aspect(surface)
  noAspect= pcr.nodirection(pcr.directional(aspect))
  sinAspect= pcr.sin(aspect)
  cosAspect= pcr.cos(aspect)
  fracX= pcr.ifthenelse(noAspect,0.,sinAspect/(pcr.abs(sinAspect)+pcr.abs(cosAspect)))
  fracY= pcr.ifthenelse(noAspect,0.,cosAspect/(pcr.abs(sinAspect)+pcr.abs(cosAspect)))
  return fracX,fracY
Example #14
0
def glacierHBV(GlacierFrac, 
                GlacierStore, 
                Snow, 
                Temperature, 
                TT, 
                Cfmax, 
                G_SIfrac,
                timestepsecs,
                basetimestep):
    """
    Run Glacier module and add the snowpack on-top of it.
    First, a fraction of the snowpack is converted into ice using the HBV-light
    model (fraction between 0.001-0.005 per day).
    Glacier melting is modelled using a Temperature degree factor and only
    occurs if the snow cover < 10 mm.


    :ivar GlacierFrac: Fraction of wflow cell covered by glaciers
    :ivar GlacierStore: Volume of the galcier in the cell in mm w.e.
    :ivar Snow: Snow pack on top of Glacier
    :ivar Temperature: Air temperature
    :ivar TT: Temperature threshold for ice melting
    :ivar Cfmax: Ice degree-day factor in mm/(°C/day)
    :ivar G_SIfrac: Fraction of the snow part turned into ice each timestep
    :ivar timestepsecs: Model timestep in seconds
    :ivar basetimestep: Model base timestep (86 400 seconds)

    :returns: Snow,Snow2Glacier,GlacierStore,GlacierMelt,
    """
    
    #Fraction of the snow transformed into ice (HBV-light model)
    Snow2Glacier = G_SIfrac * Snow

    Snow2Glacier = pcr.ifthenelse(
        GlacierFrac > 0.0, Snow2Glacier, pcr.scalar(0.0)
    )
    # Max conversion to 8mm/day
    Snow2Glacier = (
        pcr.min(Snow2Glacier, 8.0) * timestepsecs / basetimestep
    )

    Snow = Snow - (Snow2Glacier * GlacierFrac)
    GlacierStore = GlacierStore + Snow2Glacier

    PotMelt = pcr.ifthenelse(
        Temperature > TT, Cfmax * (Temperature - TT), pcr.scalar(0.0)
    )  # Potential snow melt, based on temperature

    GlacierMelt = pcr.ifthenelse(
        Snow < 10.0, pcr.min(PotMelt, GlacierStore), pcr.cover(0.0)
    )  # actual Glacier melt
    GlacierStore = GlacierStore - GlacierMelt  # dry snow content

    return Snow, Snow2Glacier, GlacierStore, GlacierMelt
Example #15
0
def glacierHBV(GlacierFrac, 
                GlacierStore, 
                Snow, 
                Temperature, 
                TT, 
                Cfmax, 
                G_SIfrac,
                timestepsecs,
                basetimestep):
    """
    Run Glacier module and add the snowpack on-top of it.
    First, a fraction of the snowpack is converted into ice using the HBV-light
    model (fraction between 0.001-0.005 per day).
    Glacier melting is modelled using a Temperature degree factor and only
    occurs if the snow cover < 10 mm.


    :ivar GlacierFrac: Fraction of wflow cell covered by glaciers
    :ivar GlacierStore: Volume of the galcier in the cell in mm w.e.
    :ivar Snow: Snow pack on top of Glacier
    :ivar Temperature: Air temperature
    :ivar TT: Temperature threshold for ice melting
    :ivar Cfmax: Ice degree-day factor in mm/(°C/day)
    :ivar G_SIfrac: Fraction of the snow part turned into ice each timestep
    :ivar timestepsecs: Model timestep in seconds
    :ivar basetimestep: Model base timestep (86 400 seconds)

    :returns: Snow,Snow2Glacier,GlacierStore,GlacierMelt,
    """
    
    #Fraction of the snow transformed into ice (HBV-light model)
    Snow2Glacier = G_SIfrac * Snow

    Snow2Glacier = pcr.ifthenelse(
        GlacierFrac > 0.0, Snow2Glacier, pcr.scalar(0.0)
    )
    # Max conversion to 8mm/day
    Snow2Glacier = (
        pcr.min(Snow2Glacier, 8.0 * (timestepsecs / basetimestep))
    )

    Snow = Snow - (Snow2Glacier * GlacierFrac)
    GlacierStore = GlacierStore + Snow2Glacier

    PotMelt = pcr.ifthenelse(
        Temperature > TT, Cfmax * (Temperature - TT), pcr.scalar(0.0)
    )  # Potential snow melt, based on temperature

    GlacierMelt = pcr.ifthenelse(
        Snow < 10.0, pcr.min(PotMelt, GlacierStore), pcr.cover(0.0)
    )  # actual Glacier melt
    GlacierStore = GlacierStore - GlacierMelt  # dry snow content

    return Snow, Snow2Glacier, GlacierStore, GlacierMelt
Example #16
0
def rainfall_interception_modrut(
    Precipitation, PotEvap, CanopyStorage, CanopyGapFraction, Cmax
):
    """
    Interception according to a modified Rutter model. The model is solved
    explicitly and there is no drainage below Cmax.
    
    Returns:
        - NetInterception: P - TF - SF (may be different from the actual wet canopy evaporation)
        - ThroughFall:
        - StemFlow:
        - LeftOver: Amount of potential eveporation not used
        - Interception: Actual wet canopy evaporation in this thimestep
        - CanopyStorage: Canopy storage at the end of the timestep
    
    """

    ##########################################################################
    # Interception according to a modified Rutter model with hourly timesteps#
    ##########################################################################

    p = CanopyGapFraction
    pt = 0.1 * p

    # Amount of P that falls on the canopy
    Pfrac = pcr.max((1 - p - pt), 0) * Precipitation

    # S cannot be larger than Cmax, no gravity drainage below that
    DD = pcr.ifthenelse(CanopyStorage > Cmax, CanopyStorage - Cmax, 0.0)
    CanopyStorage = CanopyStorage - DD

    # Add the precipitation that falls on the canopy to the store
    CanopyStorage = CanopyStorage + Pfrac

    # Now do the Evap, make sure the store does not get negative
    dC = -1 * pcr.min(CanopyStorage, PotEvap)
    CanopyStorage = CanopyStorage + dC

    LeftOver = PotEvap + dC
    # Amount of evap not used

    # Now drain the canopy storage again if needed...
    D = pcr.ifthenelse(CanopyStorage > Cmax, CanopyStorage - Cmax, 0.0)
    CanopyStorage = CanopyStorage - D

    # Calculate throughfall
    ThroughFall = DD + D + p * Precipitation
    StemFlow = Precipitation * pt

    # Calculate interception, this is NET Interception
    NetInterception = Precipitation - ThroughFall - StemFlow
    Interception = -dC

    return NetInterception, ThroughFall, StemFlow, LeftOver, Interception, CanopyStorage
Example #17
0
def rainfall_interception_modrut(
    Precipitation, PotEvap, CanopyStorage, CanopyGapFraction, Cmax
):
    """
    Interception according to a modified Rutter model. The model is solved
    explicitly and there is no drainage below Cmax.
    
    Returns:
        - NetInterception: P - TF - SF (may be different from the actual wet canopy evaporation)
        - ThroughFall:
        - StemFlow:
        - LeftOver: Amount of potential eveporation not used
        - Interception: Actual wet canopy evaporation in this thimestep
        - CanopyStorage: Canopy storage at the end of the timestep
    
    """

    ##########################################################################
    # Interception according to a modified Rutter model with hourly timesteps#
    ##########################################################################

    p = CanopyGapFraction
    pt = 0.1 * p

    # Amount of P that falls on the canopy
    Pfrac = pcr.max((1 - p - pt), 0) * Precipitation

    # S cannot be larger than Cmax, no gravity drainage below that
    DD = pcr.ifthenelse(CanopyStorage > Cmax, CanopyStorage - Cmax, 0.0)
    CanopyStorage = CanopyStorage - DD

    # Add the precipitation that falls on the canopy to the store
    CanopyStorage = CanopyStorage + Pfrac

    # Now do the Evap, make sure the store does not get negative
    dC = -1 * pcr.min(CanopyStorage, PotEvap)
    CanopyStorage = CanopyStorage + dC

    LeftOver = PotEvap + dC
    # Amount of evap not used

    # Now drain the canopy storage again if needed...
    D = pcr.ifthenelse(CanopyStorage > Cmax, CanopyStorage - Cmax, 0.0)
    CanopyStorage = CanopyStorage - D

    # Calculate throughfall
    ThroughFall = DD + D + p * Precipitation
    StemFlow = Precipitation * pt

    # Calculate interception, this is NET Interception
    NetInterception = Precipitation - ThroughFall - StemFlow
    Interception = -dC

    return NetInterception, ThroughFall, StemFlow, LeftOver, Interception, CanopyStorage
	def kinAlphaComposite(self,watStor,mask):
		#-given the total water storage and the mask specifying the occurrence of
		# floodplain conditions, retrns the Q-A relationship for the kinematic
		# wave and the associated parameters
		floodplainStorage= pcr.ifthen(mask,watStor)
		floodFrac, floodZ, dynamicWetA, dynamicAlphaQ= self.kinAlphaDynamic(floodplainStorage)
		staticWetA, staticAlphaQ= self.kinAlphaStatic(watStor)
		floodFrac= pcr.ifthenelse(mask,floodFrac,0.)
		floodZ= pcr.ifthenelse(mask,floodZ,0.)
		wetA= pcr.ifthenelse(mask,dynamicWetA,staticWetA)
		alphaQ= pcr.ifthenelse(mask,dynamicAlphaQ,staticAlphaQ)
		return floodFrac,floodZ,wetA,alphaQ
Example #19
0
def volume_spread(ldd,
                  hand,
                  subcatch,
                  volume,
                  volume_thres=0.,
                  cell_surface=1.,
                  iterations=15,
                  logging=logging,
                  order=0):
    """
    Estimate 2D flooding from a 1D simulation per subcatchment reach
    Input:
        ldd -- pcraster object direction, local drain directions
        hand -- pcraster object float32, elevation data normalised to nearest drain
        subcatch -- pcraster object ordinal, subcatchments with IDs
        volume -- pcraster object float32, scalar flood volume (i.e. m3 volume outside the river bank within subcatchment)
        volume_thres=0. -- scalar threshold, at least this amount of m3 of volume should be present in a catchment
        area_multiplier=1. -- in case the maps are not in m2, set a multiplier other than 1. to convert
        iterations=15 -- number of iterations to use
    Output:
        inundation -- pcraster object float32, scalar inundation estimate
    """
    #initial values
    pcr.setglobaloption("unitcell")
    dem_min = pcr.areaminimum(hand,
                              subcatch)  # minimum elevation in subcatchments
    dem_norm = hand - dem_min
    # surface of each subcatchment
    surface = pcr.areaarea(subcatch) * pcr.areaaverage(
        cell_surface, subcatch)  # area_multiplier
    error_abs = pcr.scalar(1e10)  # initial error (very high)
    volume_catch = pcr.areatotal(volume, subcatch)
    depth_catch = volume_catch / surface  # meters water disc averaged over subcatchment
    # ilt(depth_catch, 'depth_catch_{:02d}.map'.format(order))
    # pcr.report(volume, 'volume_{:02d}.map'.format(order))
    dem_max = pcr.ifthenelse(volume_catch > volume_thres, pcr.scalar(32.),
                             pcr.scalar(0))  # bizarre high inundation depth
    dem_min = pcr.scalar(0.)
    for n in range(iterations):
        logging.debug('Iteration: {:02d}'.format(n + 1))
        #####while np.logical_and(error_abs > error_thres, dem_min < dem_max):
        dem_av = (dem_min + dem_max) / 2
        # compute value at dem_av
        average_depth_catch = pcr.areaaverage(pcr.max(dem_av - dem_norm, 0),
                                              subcatch)
        error = pcr.cover((depth_catch - average_depth_catch) / depth_catch,
                          depth_catch * 0)
        dem_min = pcr.ifthenelse(error > 0, dem_av, dem_min)
        dem_max = pcr.ifthenelse(error <= 0, dem_av, dem_max)
    inundation = pcr.max(dem_av - dem_norm, 0)
    pcr.setglobaloption('unittrue')
    return inundation
Example #20
0
def derive_HAND(dem, ldd, accuThreshold, rivers=None, basin=None, up_area=None, neg_HAND=None):
    """
    Function derives Height-Above-Nearest-Drain.
    See http://www.sciencedirect.com/science/article/pii/S003442570800120X
    Input:
        dem -- pcraster object float32, elevation data
        ldd -- pcraster object direction, local drain directions
        accuThreshold -- upstream amount of cells as threshold for river
            delineation
        rivers=None -- you can provide a rivers layer here. Pixels that are
                        identified as river should have a value > 0, other
                        pixels a value of zero.
        basin=None -- set a boolean pcraster map where areas with True are estimated using the nearest drain in ldd distance
                        and areas with False by means of the nearest friction distance. Friction distance estimated using the
                        upstream area as weight (i.e. drains with a bigger upstream area have a lower friction)
                        the spreadzone operator is used in this case.
        up_area=None -- provide the upstream area (if not assigned a guesstimate is prepared, assuming the LDD covers a
                        full catchment area)
        neg_HAND=None -- if set to 1, HAND maps can have negative values when elevation outside of stream is lower than
                        stream (for example when there are natural embankments)
    Output:
        hand -- pcraster bject float32, height, normalised to nearest stream
        dist -- distance to nearest stream measured in cell lengths
            according to D8 directions
    """
    if rivers is None:
        # prepare stream from a strahler threshold
        stream = pcr.ifthenelse(pcr.accuflux(ldd, 1) >= accuThreshold,
                                pcr.boolean(1), pcr.boolean(0))
    else:
        # convert stream network to boolean
        stream = pcr.boolean(pcr.cover(rivers, 0))
    # determine height in river (in DEM*100 unit as ordinal)
    height_river = pcr.ifthenelse(stream, pcr.ordinal(dem*100), 0)
    if basin is None:
        up_elevation = pcr.scalar(pcr.subcatchment(ldd, height_river))
    else:
        # use basin to allocate areas outside basin to the nearest stream. Nearest is weighted by upstream area
        if up_area is None:
            up_area = pcr.accuflux(ldd, 1)
        up_area = pcr.ifthen(stream, up_area)  # mask areas outside streams
        friction = 1./pcr.scalar(pcr.spreadzone(pcr.cover(pcr.ordinal(up_area), 0), 0, 0))
        # if basin, use nearest river within subcatchment, if outside basin, use weighted-nearest river
        up_elevation = pcr.ifthenelse(basin, pcr.scalar(pcr.subcatchment(ldd, height_river)), pcr.scalar(pcr.spreadzone(height_river, 0, friction)))
        # replace areas outside of basin by a spread zone calculation.
    # make negative HANDS also possible
    if neg_HAND == 1:
        hand = (pcr.scalar(pcr.ordinal(dem*100))-up_elevation)/100  # convert back to float in DEM units
    else:
        hand = pcr.max(pcr.scalar(pcr.ordinal(dem*100))-up_elevation, 0)/100  # convert back to float in DEM units
    dist = pcr.ldddist(ldd, stream, 1)  # compute horizontal distance estimate
    return hand, dist
Example #21
0
 def kinAlphaComposite(self, watStor, mask):
     #-given the total water storage and the mask specifying the occurrence of
     # floodplain conditions, retrns the Q-A relationship for the kinematic
     # wave and the associated parameters
     floodplainStorage = pcr.ifthen(mask, watStor)
     floodFrac, floodZ, dynamicWetA, dynamicAlphaQ = self.kinAlphaDynamic(
         floodplainStorage)
     staticWetA, staticAlphaQ = self.kinAlphaStatic(watStor)
     floodFrac = pcr.ifthenelse(mask, floodFrac, 0.)
     floodZ = pcr.ifthenelse(mask, floodZ, 0.)
     wetA = pcr.ifthenelse(mask, dynamicWetA, staticWetA)
     alphaQ = pcr.ifthenelse(mask, dynamicAlphaQ, staticAlphaQ)
     return floodFrac, floodZ, wetA, alphaQ
Example #22
0
  def testIfThenElse(self):
    pcraster.setclone("and_Expr1.map")
    exceptionThrown = False
    try:
      result = pcraster.ifthenelse(1.0 == 2.0, 3.0, 4.0)
    except RuntimeError as exception:
      message = str(exception)
      self.assertTrue(message.find("conversion function to pick a data type") != -1)
      exceptionThrown = True
    self.assertTrue(exceptionThrown)

    result = pcraster.ifthenelse(pcraster.boolean(1.0 == 2.0), \
         pcraster.scalar(3.0), pcraster.scalar(4.0))
    self.assertEqual(pcraster.cellvalue(result, 1)[0], 4.0)
Example #23
0
  def testIfThenElse(self):
    pcraster.setclone("and_Expr1.map")
    exceptionThrown = False
    try:
      result = pcraster.ifthenelse(1.0 == 2.0, 3.0, 4.0)
    except RuntimeError as exception:
      message = str(exception)
      self.assert_(message.find("conversion function to pick a data type") != -1)
      exceptionThrown = True
    self.assert_(exceptionThrown)

    result = pcraster.ifthenelse(pcraster.boolean(1.0 == 2.0), \
         pcraster.scalar(3.0), pcraster.scalar(4.0))
    self.assertEqual(pcraster.cellvalue(result, 1)[0], 4.0)
Example #24
0
def dayLength(doy,lat):
    """ daylength fraction of day  """
    lat = lat * pcr.scalar(math.pi) /  180.0
    M_PI_2 = pcr.spatial(pcr.scalar(math.pi / 2.0))
    dec = pcr.sin( (6.224111 + 0.017202  * doy) *  180. / math.pi)
    dec = pcr.scalar(0.39785 * pcr.sin ((4.868961 + .017203 *  doy + 0.033446 * pcr.sin (dec*   180 / math.pi)) *  180 / math.pi))
    dec = pcr.scalar(pcr.asin(dec))
    lat = pcr.ifthenelse(pcr.abs(lat) > M_PI_2, (M_PI_2 - pcr.scalar(0.01)) * pcr.ifthenelse(lat > 0,  pcr.scalar(1.0), pcr.scalar(-1.0))  ,lat )
    arg = pcr.tan(dec ) *  pcr.tan(lat * 180.0 / math.pi  ) * -1.0
    h = pcr.scalar( pcr.acos(arg ) )
    h = h / 180. * math.pi
    h = pcr.ifthenelse(arg > 1.0, 0.0,h) # /* sun stays below horizon */
    h = pcr.ifthenelse(arg <  -1.0 ,math.pi,h) # /* sun stays above horizon */
    return (h /  math.pi)
Example #25
0
def volume_spread(ldd, hand, subcatch, volume, volume_thres=0., area_multiplier=1., iterations=15):
    """
    Estimate 2D flooding from a 1D simulation per subcatchment reach
    Input:
        ldd -- pcraster object direction, local drain directions
        hand -- pcraster object float32, elevation data normalised to nearest drain
        subcatch -- pcraster object ordinal, subcatchments with IDs
        volume -- pcraster object float32, scalar flood volume (i.e. m3 volume outside the river bank within subcatchment)
        volume_thres=0. -- scalar threshold, at least this amount of m3 of volume should be present in a catchment
        area_multiplier=1. -- in case the maps are not in m2, set a multiplier other than 1. to convert
        iterations=15 -- number of iterations to use
    Output:
        inundation -- pcraster object float32, scalar inundation estimate
    """
    #initial values
    pcr.setglobaloption("unittrue")
    dem_min = pcr.areaminimum(hand, subcatch)  # minimum elevation in subcatchments
    # pcr.report(dem_min, 'dem_min.map')
    dem_norm = hand - dem_min
    # pcr.report(dem_norm, 'dem_norm.map')
    # surface of each subcatchment
    surface = pcr.areaarea(subcatch)*area_multiplier
    pcr.report(surface, 'surface.map')

    error_abs = pcr.scalar(1e10)  # initial error (very high)
    volume_catch = pcr.areatotal(volume, subcatch)
    # pcr.report(volume_catch, 'volume_catch.map')

    depth_catch = volume_catch/surface
    pcr.report(depth_catch, 'depth_catch.map')

    dem_max = pcr.ifthenelse(volume_catch > volume_thres, pcr.scalar(32.),
                             pcr.scalar(0))  # bizarre high inundation depth
    dem_min = pcr.scalar(0.)
    for n in range(iterations):
        print('Iteration: {:02d}'.format(n + 1))
        #####while np.logical_and(error_abs > error_thres, dem_min < dem_max):
        dem_av = (dem_min + dem_max)/2
        # pcr.report(dem_av, 'dem_av00.{:03d}'.format(n + 1))
        # compute value at dem_av
        average_depth_catch = pcr.areaaverage(pcr.max(dem_av - dem_norm, 0), subcatch)
        # pcr.report(average_depth_catch, 'depth_c0.{:03d}'.format(n + 1))
        error = pcr.cover((depth_catch-average_depth_catch)/depth_catch, depth_catch*0)
        # pcr.report(error, 'error000.{:03d}'.format(n + 1))
        dem_min = pcr.ifthenelse(error > 0, dem_av, dem_min)
        dem_max = pcr.ifthenelse(error <= 0, dem_av, dem_max)
    # error_abs = np.abs(error)  # TODO: not needed probably, remove
    inundation = pcr.max(dem_av - dem_norm, 0)
    return inundation
 def getFWaterPotential(self):
     # calculates the reduction factor (0-1) for the stomatal conductance, i.e. stomatal
     # conductance in Penman will be the maximum stomatal conductance multiplied by
     # this reduction factor (see penman script)
     # the reduction factor is a linear function of soil moisture content, zero at
     # or below wilting point and one at or above field capacity, and a linear function inbetween
     fWaterPotentialTmp = (self.soilMoistureThick - self.wiltingPointThick) \
                            / self.maximumAvailableForVegetationUptakeThick
     fWaterPotentialTmpWilt = pcr.ifthenelse(
         self.soilMoistureThick < self.wiltingPointThick, pcr.scalar(0),
         fWaterPotentialTmp)
     self.fWaterPotential = pcr.ifthenelse(
         self.soilMoistureThick > self.limitingPointThick, pcr.scalar(1),
         fWaterPotentialTmpWilt)
     return self.fWaterPotential
Example #27
0
    def downscaleTemperature(self,
                             currTimeStep,
                             useFactor=False,
                             maxCorrelationCriteria=-0.75,
                             zeroCelciusInKelvin=273.15):

        tmpSlope = 1.000 * vos.netcdf2PCRobjClone(\
                           self.temperLapseRateNC, 'temperature',\
                           currTimeStep.month, useDoy = "Yes",\
                           cloneMapFileName=self.cloneMap,\
                           LatitudeLongitude = True)
        tmpSlope = pcr.min(0., tmpSlope)  # must be negative
        tmpCriteria = vos.netcdf2PCRobjClone(\
                      self.temperatCorrelNC, 'temperature',\
                      currTimeStep.month, useDoy = "Yes",\
                      cloneMapFileName=self.cloneMap,\
                      LatitudeLongitude = True)
        tmpSlope = pcr.ifthenelse(tmpCriteria < maxCorrelationCriteria,\
                   tmpSlope, 0.0)
        tmpSlope = pcr.cover(tmpSlope, 0.0)

        if useFactor == True:
            temperatureInKelvin = self.temperature + zeroCelciusInKelvin
            factor = pcr.max(0.0,
                             temperatureInKelvin + tmpSlope * self.anomalyDEM)
            factor = factor / \
                     pcr.areaaverage(factor, self.meteoDownscaleIds)
            factor = pcr.cover(factor, 1.0)
            self.temperature = factor * temperatureInKelvin - zeroCelciusInKelvin
        else:
            self.temperature = self.temperature + tmpSlope * self.anomalyDEM
Example #28
0
def snaptomap(points, mmap):
    """
    Snap the points in _points_ to nearest non missing
    values in _mmap_. Can be used to move gauge locations
    to the nearest rivers.

    Input:
        - points - map with points to move
        - mmap - map with points to move to

    Return:
        - map with shifted points
    """
    points = pcr.cover(points, 0)
    # Create unique id map of mmap cells
    unq = pcr.nominal(pcr.cover(pcr.uniqueid(pcr.defined(mmap)), pcr.scalar(0.0)))
    # Now fill holes in mmap map with lues indicating the closes mmap cell.
    dist_cellid = pcr.scalar(pcr.spreadzone(unq, 0, 1))
    # Get map with values at location in points with closes mmap cell
    dist_cellid = pcr.ifthenelse(points > 0, dist_cellid, 0)
    # Spread this out
    dist_fill = pcr.spreadzone(pcr.nominal(dist_cellid), 0, 1)
    # Find the new (moved) locations
    npt = pcr.uniqueid(pcr.boolean(pcr.ifthen(dist_fill == unq, unq)))
    # Now recreate the original value in the points maps
    ptcover = pcr.spreadzone(pcr.cover(points, 0), 0, 1)
    # Now get the org point value in the pt map
    nptorg = pcr.ifthen(npt > 0, ptcover)

    return nptorg
Example #29
0
    def downscalePrecipitation(self,
                               currTimeStep,
                               useFactor=True,
                               minCorrelationCriteria=0.85):

        preSlope = 0.001 * vos.netcdf2PCRobjClone(\
                           self.precipLapseRateNC, 'precipitation',\
                           currTimeStep.month, useDoy = "Yes",\
                           cloneMapFileName=self.cloneMap,\
                           LatitudeLongitude = True)
        preSlope = pcr.cover(preSlope, 0.0)
        preSlope = pcr.max(0., preSlope)

        preCriteria = vos.netcdf2PCRobjClone(\
                     self.precipitCorrelNC, 'precipitation',\
                     currTimeStep.month, useDoy = "Yes",\
                     cloneMapFileName=self.cloneMap,\
                     LatitudeLongitude = True)
        preSlope = pcr.ifthenelse(preCriteria > minCorrelationCriteria,\
                   preSlope, 0.0)
        preSlope = pcr.cover(preSlope, 0.0)

        if useFactor == True:
            factor = pcr.max(0.,
                             self.precipitation + preSlope * self.anomalyDEM)
            factor = factor / \
                     pcr.areaaverage(factor, self.meteoDownscaleIds)
            factor = pcr.cover(factor, 1.0)
            self.precipitation = factor * self.precipitation
        else:
            self.precipitation = self.precipitation + preSlope * self.anomalyDEM

        self.precipitation = pcr.max(0.0, self.precipitation)
Example #30
0
    def _report(self, data, identifier, timestamp):
        """
        Report function to store an attribue maps. In the traditional PCRaster 
        the report function writes a map straight to a location on disk, with
        a directory structure and filename which is representative of the attribute
        and timestep at which the reporting takes place. This can cause some 
        problems thougg. For example, a model reports 8 attributes, and the model
        has 24 timesteps. This will result in 192 map files, each of which (due to the
        PCRaster file format) is uncompressed, does not have detailed georeference
        information, does not contain overviews for quick zooming out, and is in 
        the wrong projection (that of the model, rather than web mercator that we
        need).

        In GEMS we choose a slightly different approach and use GeoTiff as the 
        storage mechanism. The variable self._report_layers contains the model 
        outputs and has the following structure:

        {
            '<attribute_name>' : [ (<data_array>, <utc_timestamp>), (...), (...) ]
        }

        This way, accessing self._report_layers['snow_depth'] will return an array
        of tuples, of which each tuple contains a numpy array and a timestamp.

        To get a list of the reported attributes we can simply use list(self._report_layers)

        Every time an attribute is reported it is added to this variable, and 
        at the end of the model run the _report_postprocess() is called, which turns
        each reported attribute into a separate geotiff file where the bands in
        the geotiff file correspond to one of the timesteps. Performing operations
        on these stacked geotiffs (such as creating overviews, requesting subsections,
        slices, or reprojecting) is much more efficient than on separate files.
        """
        try:
            if identifier in self.reporting:
                logger.debug("Reporting map '%s' (datatype:%s timestep:%d timestamp:%s)"%(identifier, self.reporting[identifier]["datatype"], self.timestep, self.timestamp))
                # Crop by the mask. Set all data outside mask to nodata value
                data = ifthenelse(self._mask, data, -9999)            
                # Convert to numpy array. The numpy array will be added to stack
                # of maps, one for each timestep.
                data = pcr2numpy(data, -9999)
                #
                #Todo: implement some kind of clamp functionality here. if 'clamp' is set to true 
                #      on the symbolizer for this output attribute, set all values
                #      above the max to the max value, and all below the min to the 
                #      min value. Allow overriding this in the model's report function like:
                #      report(data,'map', clamp=True) and then use pcraster/numpy to clamp the data.
                #
                (rows,cols) = data.shape
                if identifier not in list(self._report_layers):
                    self._report_layers.update({identifier:[]})
                self._report_layers[identifier].append((data, timestamp))
            else:
                logger.error("Don't know how to report '%s', please specify in the 'reporting' section of your model configuration."%(identifier))
        except:
            logger.error("An exception occurred while trying to report '%s'"%(identifier))
            return False
        else:
            logger.debug(" - Reporting map '%s' completed."%(identifier))
            return True
Example #31
0
def snaptomap(points, mmap):
    """
    Snap the points in _points_ to nearest non missing
    values in _mmap_. Can be used to move gauge locations
    to the nearest rivers.

    Input:
        - points - map with points to move
        - mmap - map with points to move to

    Return:
        - map with shifted points
    """
    points = pcr.cover(points, 0)
    # Create unique id map of mmap cells
    unq = pcr.nominal(pcr.cover(pcr.uniqueid(pcr.defined(mmap)), pcr.scalar(0.0)))
    # Now fill holes in mmap map with lues indicating the closes mmap cell.
    dist_cellid = pcr.scalar(pcr.spreadzone(unq, 0, 1))
    # Get map with values at location in points with closes mmap cell
    dist_cellid = pcr.ifthenelse(points > 0, dist_cellid, 0)
    # Spread this out
    dist_fill = pcr.spreadzone(pcr.nominal(dist_cellid), 0, 1)
    # Find the new (moved) locations
    npt = pcr.uniqueid(pcr.boolean(pcr.ifthen(dist_fill == unq, unq)))
    # Now recreate the original value in the points maps
    ptcover = pcr.spreadzone(pcr.cover(points, 0), 0, 1)
    # Now get the org point value in the pt map
    nptorg = pcr.ifthen(npt > 0, ptcover)

    return nptorg
Example #32
0
def getValDivZero(x,y,y_lim=smallNumber,z_def= 0.):
  #-returns the result of a division that possibly involves a zero
  # denominator; in which case, a default value is substituted:
  # x/y= z in case y > y_lim,
  # x/y= z_def in case y <= y_lim, where y_lim -> 0.
  # z_def is set to zero if not otherwise specified
  return pcr.ifthenelse(y > y_lim,x/pcr.max(y_lim,y),z_def)
Example #33
0
def getValDivZero(x,y,y_lim=smallNumber,z_def= 0.):
  #-returns the result of a division that possibly involves a zero
  # denominator; in which case, a default value is substituted:
  # x/y= z in case y > y_lim,
  # x/y= z_def in case y <= y_lim, where y_lim -> 0.
  # z_def is set to zero if not otherwise specified
  return pcr.ifthenelse(y > y_lim,x/pcr.max(y_lim,y),z_def)
Example #34
0
def satPressure(airT):
    """ calculates saturated vp from airt temperature Murray (1967) """
    # airT      - air temperature [degree C] */
    satPressure = pcr.ifthenelse(
        airT >= 0.0, 0.61078 * pcr.exp(17.26939 * airT / (airT + 237.3)),
        0.61078 * pcr.exp(21.87456 * airT / (airT + 265.5)))
    return satPressure
def stackAverage(path,Root,StackStart,StackEnd):
	#calculates the average from a stack of maps, missing maps are skipped
	#Initialization
	MV= pcr.scalar(-999)
	NCount= pcr.scalar(0)
	SumStack= pcr.scalar(0)
	for StackNumber in range(StackStart,StackEnd):
		try:
			InMap= pcr.readmap(generateNameT(os.path.join(path,Root),StackNumber))
		except:
			InMap= MV;
		InMap= pcr.cover(InMap,MV)
		SumStack= SumStack+InMap
		NCount= NCount+pcr.ifthenelse(InMap <> MV,pcr.scalar(1),pcr.scalar(0))
	AvgStack= pcr.ifthenelse(NCount>0,SumStack/NCount,MV)
	return AvgStack
Example #36
0
def volume_spread(ldd, hand, subcatch, volume, volume_thres=0., cell_surface=1., iterations=15, logging=logging, order=0, neg_HAND=None):
    """
    Estimate 2D flooding from a 1D simulation per subcatchment reach
    Input:
        ldd -- pcraster object direction, local drain directions
        hand -- pcraster object float32, elevation data normalised to nearest drain
        subcatch -- pcraster object ordinal, subcatchments with IDs
        volume -- pcraster object float32, scalar flood volume (i.e. m3 volume outside the river bank within subcatchment)
        volume_thres=0. -- scalar threshold, at least this amount of m3 of volume should be present in a catchment
        area_multiplier=1. -- in case the maps are not in m2, set a multiplier other than 1. to convert
        iterations=15 -- number of iterations to use
        neg_HAND -- if set to 1, HAND maps can have negative values when elevation outside of stream is lower than
        stream (for example when there are natural embankments)
    Output:
        inundation -- pcraster object float32, scalar inundation estimate
    """
    #initial values
    pcr.setglobaloption("unitcell")
    dem_min = pcr.areaminimum(hand, subcatch)  # minimum elevation in subcatchments
    dem_norm = hand - dem_min
    # surface of each subcatchment
    surface = pcr.areaarea(subcatch)*pcr.areaaverage(cell_surface, subcatch) # area_multiplier
    error_abs = pcr.scalar(1e10)  # initial error (very high)
    volume_catch = pcr.areatotal(volume, subcatch)
    depth_catch = volume_catch/surface  # meters water disc averaged over subcatchment
    # ilt(depth_catch, 'depth_catch_{:02d}.map'.format(order))
    # pcr.report(volume, 'volume_{:02d}.map'.format(order))
    if neg_HAND == 1:
        dem_max = pcr.ifthenelse(volume_catch > volume_thres, pcr.scalar(32.),
                             pcr.scalar(-32.))  # bizarre high inundation depth☻
        dem_min = pcr.scalar(-32.)
    else:
        dem_max = pcr.ifthenelse(volume_catch > volume_thres, pcr.scalar(32.),
                             pcr.scalar(0.))  # bizarre high inundation depth☻
        dem_min = pcr.scalar(0.)
    for n in range(iterations):
        logging.debug('Iteration: {:02d}'.format(n + 1))
        #####while np.logical_and(error_abs > error_thres, dem_min < dem_max):
        dem_av = (dem_min + dem_max)/2
        # compute value at dem_av
        average_depth_catch = pcr.areaaverage(pcr.max(dem_av - dem_norm, 0), subcatch)
        error = pcr.cover((depth_catch-average_depth_catch)/depth_catch, depth_catch*0)
        dem_min = pcr.ifthenelse(error > 0, dem_av, dem_min)
        dem_max = pcr.ifthenelse(error <= 0, dem_av, dem_max)
    inundation = pcr.max(dem_av - dem_norm, 0)
    pcr.setglobaloption('unittrue')
    return inundation
Example #37
0
def agriZone_Ep(self, k):
    """
    - Potential evaporation is decreased by energy used for interception evaporation    
    - Formula for evaporation based on LP
    - Outgoing fluxes are determined based on (value in previous timestep + inflow) 
    and if this leads to negative storage, the outgoing fluxes are corrected to rato --> Eu is 
    no longer taken into account for this correction
    - Qa u is determined from overflow from Sa
    - Code for ini-file: 2
    """
    JarvisCoefficients.calcEp(self, k)
    self.PotEvaporation = pcr.cover(pcr.ifthenelse(self.EpHour >= 0, self.EpHour, 0), 0)

    self.Qa = pcr.max(self.Pe - (self.samax[k] - self.Sa_t[k]), 0)
    self.Sa[k] = self.Sa_t[k] + (self.Pe - self.Qa)
    self.SaN = pcr.min(self.Sa[k] / self.samax2, 1)
    self.SuN = self.Su[k] / self.sumax[k]

    self.Ea1 = pcr.max((self.PotEvaporation - self.Ei), 0) * pcr.min(
        self.Sa[k] / (self.samax[k] * self.LP[k]), 1
    )

    self.Fa1 = self.Fmin[k] + (self.Fmax[k] - self.Fmin[k]) * e ** (
        -self.decF[k] * self.SuN
    )
    self.Sa[k] = self.Sa_t[k] + (self.Pe - self.Qa) - self.Fa1 - self.Ea1

    self.Sa_diff = pcr.ifthenelse(self.Sa[k] < 0, self.Sa[k], 0)
    self.Fa = (
        self.Fa1
        + (self.Fa1 / pcr.ifthenelse(self.Fa1 + self.Ea1 > 0, self.Fa1 + self.Ea1, 1))
        * self.Sa_diff
    )
    self.Ea = (
        self.Ea1
        + (self.Ea1 / pcr.ifthenelse(self.Fa1 + self.Ea1 > 0, self.Fa1 + self.Ea1, 1))
        * self.Sa_diff
    )
    self.Sa[k] = self.Sa_t[k] + (self.Pe - self.Qa) - self.Ea - self.Fa
    self.Sa[k] = pcr.ifthenelse(self.Sa[k] < 0, 0, self.Sa[k])
    self.Sa_diff2 = pcr.ifthen(self.Sa[k] < 0, self.Sa[k])

    self.wbSa_[k] = self.Pe - self.Ea - self.Qa - self.Fa - self.Sa[k] + self.Sa_t[k]

    self.Ea_[k] = self.Ea
    self.Qa_[k] = self.Qa
    self.Fa_[k] = self.Fa
Example #38
0
def derive_HAND(dem, ldd, accuThreshold, rivers=None, basin=None):
    """
    Function derives Height-Above-Nearest-Drain.
    See http://www.sciencedirect.com/science/article/pii/S003442570800120X
    Input:
        dem -- pcraster object float32, elevation data
        ldd -- pcraster object direction, local drain directions
        accuThreshold -- upstream amount of cells as threshold for river
            delineation
        rivers=None -- you can provide a rivers layer here. Pixels that are
                        identified as river should have a value > 0, other
                        pixels a value of zero.
        basin=None -- set a boolean pcraster map where areas with True are estimated using the nearest drain in ldd distance
                        and areas with False by means of the nearest friction distance. Friction distance estimated using the
                        upstream area as weight (i.e. drains with a bigger upstream area have a lower friction)
                        the spreadzone operator is used in this case.
    Output:
        hand -- pcraster bject float32, height, normalised to nearest stream
        dist -- distance to nearest stream measured in cell lengths
            according to D8 directions
    """
    if rivers is None:
        stream = pcr.ifthenelse(
            pcr.accuflux(ldd, 1) >= accuThreshold, pcr.boolean(1), pcr.boolean(0)
        )
    else:
        stream = pcr.boolean(pcr.cover(rivers, 0))

    height_river = pcr.ifthenelse(stream, pcr.ordinal(dem * 100), 0)
    if basin is None:
        up_elevation = pcr.scalar(pcr.subcatchment(ldd, height_river))
    else:
        drainage_surf = pcr.ifthen(rivers, pcr.accuflux(ldd, 1))
        weight = 1.0 / pcr.scalar(
            pcr.spreadzone(pcr.cover(pcr.ordinal(drainage_surf), 0), 0, 0)
        )
        up_elevation = pcr.ifthenelse(
            basin,
            pcr.scalar(pcr.subcatchment(ldd, height_river)),
            pcr.scalar(pcr.spreadzone(height_river, 0, weight)),
        )
        # replace areas outside of basin by a spread zone calculation.
    hand = pcr.max(pcr.scalar(pcr.ordinal(dem * 100)) - up_elevation, 0) / 100
    dist = pcr.ldddist(ldd, stream, 1)

    return hand, dist
Example #39
0
def derive_HAND(dem, ldd, accuThreshold, rivers=None, basin=None):
    """
    Function derives Height-Above-Nearest-Drain.
    See http://www.sciencedirect.com/science/article/pii/S003442570800120X
    Input:
        dem -- pcraster object float32, elevation data
        ldd -- pcraster object direction, local drain directions
        accuThreshold -- upstream amount of cells as threshold for river
            delineation
        rivers=None -- you can provide a rivers layer here. Pixels that are
                        identified as river should have a value > 0, other
                        pixels a value of zero.
        basin=None -- set a boolean pcraster map where areas with True are estimated using the nearest drain in ldd distance
                        and areas with False by means of the nearest friction distance. Friction distance estimated using the
                        upstream area as weight (i.e. drains with a bigger upstream area have a lower friction)
                        the spreadzone operator is used in this case.
    Output:
        hand -- pcraster bject float32, height, normalised to nearest stream
        dist -- distance to nearest stream measured in cell lengths
            according to D8 directions
    """
    if rivers is None:
        stream = pcr.ifthenelse(
            pcr.accuflux(ldd, 1) >= accuThreshold, pcr.boolean(1), pcr.boolean(0)
        )
    else:
        stream = pcr.boolean(pcr.cover(rivers, 0))

    height_river = pcr.ifthenelse(stream, pcr.ordinal(dem * 100), 0)
    if basin is None:
        up_elevation = pcr.scalar(pcr.subcatchment(ldd, height_river))
    else:
        drainage_surf = pcr.ifthen(rivers, pcr.accuflux(ldd, 1))
        weight = 1.0 / pcr.scalar(
            pcr.spreadzone(pcr.cover(pcr.ordinal(drainage_surf), 0), 0, 0)
        )
        up_elevation = pcr.ifthenelse(
            basin,
            pcr.scalar(pcr.subcatchment(ldd, height_river)),
            pcr.scalar(pcr.spreadzone(height_river, 0, weight)),
        )
        # replace areas outside of basin by a spread zone calculation.
    hand = pcr.max(pcr.scalar(pcr.ordinal(dem * 100)) - up_elevation, 0) / 100
    dist = pcr.ldddist(ldd, stream, 1)

    return hand, dist
Example #40
0
    def set_satDegUpp000005(self, observed_satDegUpp000005):

        # ratio between observation and model
        ratio_between_observation_and_model = pcr.ifthenelse(self.model.landSurface.satDegUpp000005> 0.0, 
                                                             observed_satDegUpp000005 / \
                                                             self.model.landSurface.satDegUpp000005, 0.0) 
        
        # updating upper soil states for all lad cover types
        for coverType in self.model.landSurface.coverTypes:
            
            # correcting upper soil state (storUpp000005)
            self.model.landSurface.landCoverObj[coverType].storUpp000005 *= ratio_between_observation_and_model
            
            # if model value = 0.0, storUpp000005 is calculated based on storage capacity (model parameter) and observed saturation degree   
            self.model.landSurface.landCoverObj[coverType].storUpp000005  = pcr.ifthenelse(self.model.landSurface.satDegUpp000005 > 0.0,\
                                                                                           self.model.landSurface.landCoverObj[coverType].storUpp000005,\
                                                                                           observed_satDegUpp000005 * self.model.landSurface.parameters.storCapUpp000005) 
def create_city_map(ESA_CCI_land_use_map_filename, city_class_id):
    #Create cities map from land use map
    land_use_map = pcr.readmap(ESA_CCI_land_use_map_filename)
    cities = pcr.ifthenelse(land_use_map == city_class_id, pcr.boolean(1),
                            pcr.boolean(0))
    pcr.report(
        cities,
        os.path.join(os_output_folder, "cities_" + CASE_STUDY_NAME + ".map"))
    return
Example #42
0
 def testIfThenElse(self):
   pcraster.setclone("and_Expr1.map")
   exceptionThrown = False
   try:
     result = pcraster.ifthenelse(1.0 == 2.0, 3.0, 4.0)
   except RuntimeError, exception:
     message = str(exception)
     self.assert_(string.find(message, "conversion function to pick a data type") != -1)
     exceptionThrown = True
def stackAverage(path, Root, StackStart, StackEnd):
    #calculates the average from a stack of maps, missing maps are skipped
    #Initialization
    MV = pcr.scalar(-999)
    NCount = pcr.scalar(0)
    SumStack = pcr.scalar(0)
    for StackNumber in range(StackStart, StackEnd):
        try:
            InMap = pcr.readmap(
                generateNameT(os.path.join(path, Root), StackNumber))
        except:
            InMap = MV
        InMap = pcr.cover(InMap, MV)
        SumStack = SumStack + InMap
        NCount = NCount + pcr.ifthenelse(InMap <> MV, pcr.scalar(1),
                                         pcr.scalar(0))
    AvgStack = pcr.ifthenelse(NCount > 0, SumStack / NCount, MV)
    return AvgStack
Example #44
0
def agriZone_Ep_Sa_beta(self, k):
    """
    - Potential evaporation is decreased by energy used for interception evaporation    
    - Formula for evaporation based on LP
    - Outgoing fluxes are determined based on (value in previous timestep + inflow) 
    and if this leads to negative storage, the outgoing fluxes are corrected to rato --> Eu is 
    no longer taken into account for this correction
    - Qa u is determined from overflow from Sa --> incorporation of beta function
    - Fa is based on storage in Sa
    - Code for ini-file: 6
    """

    JarvisCoefficients.calcEp(self, k)
    self.PotEvaporation = pcr.cover(
        pcr.ifthenelse(self.EpHour >= 0, self.EpHour, 0), 0)

    self.samax2 = self.samax[k] * pcr.scalar(self.catchArea)
    self.Qaadd = pcr.max(self.Sa_t[k] + self.Pe - self.samax2, 0)

    self.Sa[k] = self.Sa_t[k] + (self.Pe - self.Qaadd)
    self.SaN = pcr.min(pcr.max(self.Sa[k] / self.samax2, 0), 1)
    self.SuN = self.Su[k] / self.sumax[k]

    self.Ea1 = pcr.max((self.PotEvaporation - self.Ei), 0) * pcr.min(
        self.Sa[k] / (self.samax2 * self.LP[k]), 1)
    self.Qa1 = (self.Pe - self.Qaadd) * (1 - (1 - self.SaN)**self.beta[k])
    self.Fa1 = pcr.ifthenelse(
        self.SaN > 0,
        self.Fmin[k] + (self.Fmax[k] - self.Fmin[k]) * e**(-self.decF[k] *
                                                           (1 - self.SaN)),
        0,
    )
    self.Sa[k] = self.Sa_t[k] + (self.Pe -
                                 self.Qaadd) - self.Qa1 - self.Fa1 - self.Ea1

    self.Sa_diff = pcr.ifthenelse(self.Sa[k] < 0, self.Sa[k], 0)
    self.Qa = (self.Qa1 +
               (self.Qa1 / pcr.ifthenelse(self.Fa1 + self.Ea1 + self.Qa1 > 0,
                                          self.Fa1 + self.Ea1 + self.Qa1, 1)) *
               self.Sa_diff)
    self.Fa = (self.Fa1 +
               (self.Fa1 / pcr.ifthenelse(self.Fa1 + self.Ea1 + self.Qa1 > 0,
                                          self.Fa1 + self.Ea1 + self.Qa1, 1)) *
               self.Sa_diff)
    self.Ea = (self.Ea1 +
               (self.Ea1 / pcr.ifthenelse(self.Fa1 + self.Ea1 + self.Qa1 > 0,
                                          self.Fa1 + self.Ea1 + self.Qa1, 1)) *
               self.Sa_diff)
    self.Sa[k] = self.Sa_t[k] + (self.Pe -
                                 self.Qaadd) - self.Ea - self.Fa - self.Qa
    self.Sa[k] = pcr.ifthenelse(self.Sa[k] < 0, 0, self.Sa[k])
    self.Sa_diff2 = pcr.ifthen(self.Sa[k] < 0, self.Sa[k])

    self.wbSa_[k] = (self.Pe - self.Ea - self.Qa - self.Qaadd - self.Fa -
                     self.Sa[k] + self.Sa_t[k])

    self.Ea_[k] = self.Ea
    self.Qa_[k] = self.Qa + self.Qaadd
    self.Fa_[k] = self.Fa
Example #45
0
def remove_fxw(fixed_weirs, removal_area):
    """
    Erase fixed weirs within the removal area. Line elements that get split 
    by the removal are relabeled.
    -------------
    Parameters
        fixed_weirs: Fixed weir DataFrame with Point geometry
        removal_area: Scalar map area, removal area indicated with -9999.
    
    Returns a fixed weir DataFrame.
    """
    # add label details as columns
    labels = fixed_weirs.label.str.split(':', expand=True)
    labels.columns = ['label_nr', 'label_type']
    fixed_weirs = pd.concat([fixed_weirs, labels], axis=1)

    # add reference value: 'selected' = 0:inside, 1:outside
    label_map = pcr.ifthenelse(pcr.defined(removal_area), pcr.scalar(0),
                               pcr.scalar(1))
    labeled_points = update_z(fixed_weirs.loc[:, list('abc')], label_map)
    fixed_weirs.loc[:, 'selected'] = labeled_points.z
    # 'parts' increases with 1 at every change from 1 to 0 and 0 to 1 in 'selected'
    fixed_weirs['parts'] = (1 + fixed_weirs.selected.diff().abs().cumsum())
    fixed_weirs.fillna(0, inplace=True)

    # take the minimum value of 'parts' for each fixed weir and subtract
    # from the cumulative value to reset the counter per fixed weir
    nr_parts_cum = fixed_weirs.groupby(by='label').min().parts
    nr_parts_cum = nr_parts_cum.fillna(0).reset_index()

    fxw2 = pd.merge(fixed_weirs,
                    nr_parts_cum,
                    on='label',
                    suffixes=['_l', '_r'])
    fxw2['parts'] = (1 + fxw2.parts_l - fxw2.parts_r)
    fxw2['new_label'] = fxw2.apply(lambda x: '{0}_{1}:{2}'.format(x.label_nr,
                                                           str(int(x.parts)),\
                                                           str(x.label_type)),\
                                                           axis=1)

    # clean up
    points_per_part = fxw2.loc[:,['new_label', 'selected']]\
                           .groupby('new_label')\
                           .count().reset_index()
    points_per_part.columns = ['new_label', 'nr_points']
    fxw3 = pd.merge(fxw2,
                    points_per_part,
                    on='new_label',
                    suffixes=['_l', '_r'])
    fxw_out = fxw3[(fxw3.nr_points > 1) & (fxw3.selected == 1)]
    fxw_out.drop(['label', 'label_nr', 'label_type', 'selected',\
                  'parts_l', 'parts_r', 'parts', 'nr_points'],\
                   axis = 1, inplace=True)
    fxw_out.rename(columns={'new_label': 'label'}, inplace=True)
    fxw_out.index = range(len(fxw_out))  # to overwrite duplicate indices
    return fxw_out
Example #46
0
def estimate_iterations_kin_wave(Q, Beta, alpha, timestepsecs, dx, mv):

    celerity = pcr.ifthenelse(Q > 0.0, 1.0 / (alpha * Beta * Q**(Beta - 1)),
                              0.0)
    courant = (timestepsecs / dx) * celerity
    np_courant = pcr.pcr2numpy(courant, mv)
    np_courant[np_courant == mv] = np.nan
    it_kin = max(int(np.ceil(1.25 * (np.nanpercentile(np_courant, 95)))), 1)

    return it_kin
Example #47
0
    def initial(self):
        """ initial part of the evapo water module
        """

        # ************************************************************
        # ***** EVAPORATION
        # ************************************************************
        self.var.EvaCumM3 = MaskInfo.instance().in_zero()
        # water use cumulated amount
        # water use substep amount
        settings = LisSettings.instance()
        option = settings.options
        binding = settings.binding
        maskinfo = MaskInfo.instance()
        if option['openwaterevapo']:
            LakeMask = loadmap('LakeMask', pcr=True)
            lmask = ifthenelse(LakeMask != 0, self.var.LddStructuresKinematic,
                               5)
            LddEva = lddrepair(lmask)
            lddC = compressArray(LddEva)
            inAr = decompress(np.arange(maskinfo.info.mapC[0], dtype="int32"))
            self.var.downEva = (compressArray(downstream(
                LddEva, inAr))).astype("int32")
            # each upstream pixel gets the id of the downstream pixel
            self.var.downEva[lddC == 5] = maskinfo.info.mapC[0]
            self.var.maxNoEva = int(loadmap('maxNoEva'))
            # all pits gets a high number
            # still to test if this works

            # ldd only inside lakes for calculating evaporation

            if option['varfractionwater']:

                self.var.diffmaxwater = loadmap(
                    'FracMaxWater') - self.var.WaterFraction

                # Fraction of maximum extend of water  - fraction of water in lakes and rivers

                varWNo = [
                    1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 370
                ]
                self.var.varW = []  # variable fraction of water
                self.var.varW1 = []

                self.var.varW1.append(12)
                j = 0
                for i in range(1, 367):
                    if i >= varWNo[j + 1]: j += 1
                    self.var.varW1.append(j)

                for i in range(12):
                    varWName = generateName(binding['WFractionMaps'],
                                            varWNo[i])
                    self.var.varW.append(
                        loadLAI(binding['WFractionMaps'], varWName, i))
Example #48
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 #49
0
def rainfall_interception_gash(Cmax,
                               EoverR,
                               CanopyGapFraction,
                               Precipitation,
                               CanopyStorage,
                               maxevap=9999):
    """
    Interception according to the Gash model (For daily timesteps). 
    """
    # TODO:  add other rainfall interception method (lui)
    # TODO: Include subdaily Gash model
    # TODO: add LAI variation in year
    # Hack for stemflow

    pt = 0.1 * CanopyGapFraction

    P_sat = pcr.max(
        pcr.scalar(0.0),
        pcr.cover(
            (-Cmax / EoverR) * pcr.ln(1.0 - (EoverR /
                                             (1.0 - CanopyGapFraction - pt))),
            pcr.scalar(0.0),
        ),
    )

    # large storms P > P_sat
    largestorms = Precipitation > P_sat

    Iwet = pcr.ifthenelse(
        largestorms,
        ((1 - CanopyGapFraction - pt) * P_sat) - Cmax,
        Precipitation * (1 - CanopyGapFraction - pt),
    )
    Isat = pcr.ifthenelse(largestorms, (EoverR) * (Precipitation - P_sat), 0.0)
    Idry = pcr.ifthenelse(largestorms, Cmax, 0.0)
    Itrunc = 0

    StemFlow = pt * Precipitation

    ThroughFall = Precipitation - Iwet - Idry - Isat - Itrunc - StemFlow
    Interception = Iwet + Idry + Isat + Itrunc

    # Non corect for area without any Interception (say open water Cmax -- zero)
    CmaxZero = Cmax <= 0.0
    ThroughFall = pcr.ifthenelse(CmaxZero, Precipitation, ThroughFall)
    Interception = pcr.ifthenelse(CmaxZero, pcr.scalar(0.0), Interception)
    StemFlow = pcr.ifthenelse(CmaxZero, pcr.scalar(0.0), StemFlow)

    # Now corect for maximum potential evap
    OverEstimate = pcr.ifthenelse(Interception > maxevap,
                                  Interception - maxevap, pcr.scalar(0.0))
    Interception = pcr.min(Interception, maxevap)
    # Add surpluss to the thoughdfall
    ThroughFall = ThroughFall + OverEstimate

    return ThroughFall, Interception, StemFlow, CanopyStorage
Example #50
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 #51
0
def rainfall_interception_gash(
    Cmax, EoverR, CanopyGapFraction, Precipitation, CanopyStorage, maxevap=9999
):
    """
    Interception according to the Gash model (For daily timesteps). 
    """
    # TODO:  add other rainfall interception method (lui)
    # TODO: Include subdaily Gash model
    # TODO: add LAI variation in year
    # Hack for stemflow

    pt = 0.1 * CanopyGapFraction

    P_sat = pcr.max(
        pcr.scalar(0.0),
        pcr.cover(
            (-Cmax / EoverR) * pcr.ln(1.0 - (EoverR / (1.0 - CanopyGapFraction - pt))),
            pcr.scalar(0.0),
        ),
    )

    # large storms P > P_sat
    largestorms = Precipitation > P_sat

    Iwet = pcr.ifthenelse(
        largestorms,
        ((1 - CanopyGapFraction - pt) * P_sat) - Cmax,
        Precipitation * (1 - CanopyGapFraction - pt),
    )
    Isat = pcr.ifthenelse(largestorms, (EoverR) * (Precipitation - P_sat), 0.0)
    Idry = pcr.ifthenelse(largestorms, Cmax, 0.0)
    Itrunc = 0

    StemFlow = pt * Precipitation

    ThroughFall = Precipitation - Iwet - Idry - Isat - Itrunc - StemFlow
    Interception = Iwet + Idry + Isat + Itrunc

    # Non corect for area without any Interception (say open water Cmax -- zero)
    CmaxZero = Cmax <= 0.0
    ThroughFall = pcr.ifthenelse(CmaxZero, Precipitation, ThroughFall)
    Interception = pcr.ifthenelse(CmaxZero, pcr.scalar(0.0), Interception)
    StemFlow = pcr.ifthenelse(CmaxZero, pcr.scalar(0.0), StemFlow)

    # Now corect for maximum potential evap
    OverEstimate = pcr.ifthenelse(
        Interception > maxevap, Interception - maxevap, pcr.scalar(0.0)
    )
    Interception = pcr.min(Interception, maxevap)
    # Add surpluss to the thoughdfall
    ThroughFall = ThroughFall + OverEstimate

    return ThroughFall, Interception, StemFlow, CanopyStorage
Example #52
0
def pt_flow_in_river(ldd, river):
    """
    Returns all points (True) that flow into the mak river (boolean map with river set to True)

    :param ldd: Drainage network
    :param river: Map of river (True River, False non-river)
    :return ifmap: map with infrlo points into the river (True)
    :return ctach: catchment of each of the inflow points
    """

    dspts = pcr.downstream(ldd, pcr.cover(river, 0))
    dspts = pcr.ifthenelse(pcr.cover(river, 0) == 1, 0, dspts)

    catch = pcr.subcatchment(ldd, pcr.nominal(pcr.uniqueid(dspts)))

    return dspts, catch
	def initial(self):
		#####################
		# * initial section #
		#####################
		#-constants
		# betaQ [-]: constant of kinematic wave momentum equation
		self.betaQ= 0.6
		#-channel LDD
		self.channelLDD= pcr.ifthenelse(self.waterBodies.distribution != 0,\
			pcr.ldd(5),self.LDD)
		#-channel area and storage
		self.channelArea= self.channelWidth*self.channelLength
		self.channelStorageCapacity= pcr.ifthenelse(self.waterBodies.distribution == 0,\
			self.channelArea*self.channelDepth,pcr.scalar(0.))
		#-basin outlets
		self.basinOutlet= pcr.pit(self.LDD) != 0
		#-read initial conditions
		self.Q= clippedRead.get(self.QIniMap)
		self.actualStorage= clippedRead.get(self.actualStorageIniMap)
		self.actualStorage= pcr.ifthenelse(self.waterBodies.distribution != 0,\
			pcr.ifthenelse(self.waterBodies.location != 0,\
				pcr.areatotal(self.actualStorage,self.waterBodies.distribution),0),\
					self.actualStorage)   
		self.waterBodies.actualStorage= self.waterBodies.retrieveMapValue(self.actualStorage)
		#-update targets of average and bankful discharge
		self.waterBodies.averageQ= self.waterBodies.retrieveMapValue(self.averageQ)
		self.waterBodies.bankfulQ= self.waterBodies.retrieveMapValue(self.bankfulQ)
		#-return the parameters for the kinematic wave,
		# including alpha, wetted area, flood fraction, flood volume and depth
		# and the corresponding land area
		floodedFraction,floodedDepth,\
			self.wettedArea,self.alphaQ= self.kinAlphaComposite(self.actualStorage,self.floodplainMask)
		self.wettedArea= self.waterBodies.returnMapValue(self.wettedArea,\
			self.waterBodies.channelWidth+2.*self.waterBodies.updateWaterHeight())
		self.waterFraction= pcr.ifthenelse(self.waterBodies.distribution == 0,\
			pcr.max(self.waterFractionMask,floodedFraction),self.waterFractionMask)
		self.landFraction= pcr.max(0.,1.-self.waterFraction)
		#-update on velocity and check on Q - NOTE: does not work in case of reservoirs!
		self.flowVelocity= pcr.ifthenelse(self.wettedArea > 0,self.Q/self.wettedArea,0.)
		pcr.report(self.flowVelocity,pcrm.generateNameT(flowVelocityFileName,0).replace('.000','.ini'))
		#-setting initial values for specific runoff and surface water extraction
		self.landSurfaceQ= pcr.scalar(0.)
		self.potWaterSurfaceQ= pcr.scalar(0.)
		self.surfaceWaterExtraction= pcr.scalar(0.)
		#-budget check: setting initial values for cumulative discharge and 
		# net cumulative input, including initial storage [m3]   
		self.totalDischarge= pcr.scalar(0.)
		self.cumulativeDeltaStorage= pcr.catchmenttotal(self.actualStorage,self.LDD)
        time_index_in_netcdf_file = i_year - str_year + 1
        
        value_from_the_hydrological_year_1 = vos.netcdf2PCRobjClone(input_files['file_name']["hydrological_year_1"][var], \
                                                                    varDict.netcdf_short_name[var], time_index_in_netcdf_file,\
                                                                    useDoy = "Yes",
                                                                    cloneMapFileName  = clone_map_file,\
                                                                    LatitudeLongitude = True,\
                                                                    specificFillValue = None)
        
        value_from_the_hydrological_year_2 = vos.netcdf2PCRobjClone(input_files['file_name']["hydrological_year_2"][var], \
                                                                    varDict.netcdf_short_name[var], time_index_in_netcdf_file,\
                                                                    useDoy = "Yes",
                                                                    cloneMapFileName  = clone_map_file,\
                                                                    LatitudeLongitude = True,\
                                                                    specificFillValue = None)
        
        # merging two hydrological years 
        value_for_this_year = pcr.ifthenelse(pcr.scalar(hydro_year_type) == 1, value_from_the_hydrological_year_1, \
                                                                               value_from_the_hydrological_year_2)
        value_for_this_year = pcr.cover(value_for_this_year, 0.0)
        
        if landmask_only: value_for_this_year = pcr.ifthen(landmask, value_for_this_year)
        
        # report to a netcdf file
        ncFileName = output_files[var]['file_name']
        msg = "Saving to the netcdf file: " + str(ncFileName)
        logger.info(msg)
        time_stamp_used = datetime.datetime(i_year, 12, 31, 0)
        netcdf_report.data2NetCDF(ncFileName, varDict.netcdf_short_name[var], pcr.pcr2numpy(value_for_this_year, vos.MV), time_stamp_used)

                                           specificFillValue = None)
maximum_discharge = pcr.areamaximum(\
                  pcr.cover(maximum_discharge, 0.0), basin_map)
# - find the month with maximum discharge
maximum_month = pcr.spatial(pcr.scalar(1.0))
for i_month in range(1, 12 + 1):
    # read the climatology discharge time series
    discharge_for_this_month = vos.netcdf2PCRobjClone(input_files['climatologyDischargeMonthAvg'], \
                                                      "discharge", i_month,\
                                                      useDoy = "Yes",
                                                      cloneMapFileName  = clone_map_file,\
                                                      LatitudeLongitude = True,\
                                                      specificFillValue = None)
    # upscale it to the basin scale
    discharge_for_this_month = pcr.areamaximum(discharge_for_this_month, basin_map)
    maximum_month = pcr.ifthenelse(discharge_for_this_month == maximum_discharge, pcr.scalar(i_month), maximum_month)
pcr.report(maximum_month, "maximum_month.map")
    	
# defining the hydrological year type
msg = "Defining the type of hydrological year:"
logger.info(msg)
hydrological_year_type = pcr.spatial(pcr.nominal(1))
hydrological_year_type = pcr.ifthenelse(maximum_month ==  9, pcr.nominal(2), hydrological_year_type)
hydrological_year_type = pcr.ifthenelse(maximum_month == 10, pcr.nominal(2), hydrological_year_type)
hydrological_year_type = pcr.ifthenelse(maximum_month == 11, pcr.nominal(2), hydrological_year_type)
hydrological_year_type = pcr.cover(hydrological_year_type, pcr.nominal(1))
hydrological_year_type = pcr.ifthen(landmask, hydrological_year_type)
pcr.report(hydrological_year_type, "hydrological_year_type.map")
#~ pcr.aguila(hydrological_year_type)

Example #56
0
def getQAtBasinMouths(discharge, basinMouth):
    temp = pcr.ifthenelse(basinMouth != 0 , discharge * secondsPerDay(),0.)
    pcr.report(temp,"temp.map")
    return (getMapTotal(temp)  / 1e9)
    
    # loop the file list to get the correct file
    for pcraster_file in input_pcraster_files:
        if historical_results:
            if os.path.basename(pcraster_file).startswith(return_period):
                selected_pcraster_file = pcraster_file
                map_for_this_return_period = pcr.readmap(selected_pcraster_file)
        else:
            if return_period in pcraster_file:
                selected_pcraster_file = pcraster_file
                map_for_this_return_period = pcr.readmap(selected_pcraster_file)
    
    print selected_pcraster_file
    map_for_this_return_period = pcr.cover(map_for_this_return_period, 0.0)
    
    if i_return_period > 0:
        check_map = pcr.ifthenelse(map_for_this_return_period >= previous_map, pcr.scalar(0.0), pcr.scalar(-1.0))
        
        minimum_value, maximum_value, average_value = vos.getMinMaxMean(check_map)
        
        msg  = ""
        msg += "\n"
        msg += "\n"
        msg += "Checkting that the values in the file %s are equal to or bigger than the file %s : Min %f Max %f Mean %f" %(selected_pcraster_file, previous_file, minimum_value, maximum_value, average_value)
        msg += "\n"
        msg += "\n"
        print(msg)
    
    previous_map = map_for_this_return_period
    previous_file = selected_pcraster_file
Example #58
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)
Example #59
0
def agriZone_Ep_Sa_beta_Fvar(self, k):
    """
    - Potential evaporation is decreased by energy used for interception evaporation    
    - Formula for evaporation based on LP
    - Outgoing fluxes are determined based on (value in previous timestep + inflow) 
    and if this leads to negative storage, the outgoing fluxes are corrected to rato --> Eu is 
    no longer taken into account for this correction
    - Qa u is determined from overflow from Sa --> incorporation of beta function
    - Fa is based on storage in Sa
    - Code for ini-file: 8
    """

    JarvisCoefficients.calcEp(self, k)
    self.PotEvaporation = self.EpHour

    self.samax2 = self.samax[k] * pcr.scalar(self.catchArea)
    self.Qaadd = pcr.max(self.Sa_t[k] + self.Pe - self.samax2, 0)

    self.Sa[k] = self.Sa_t[k] + (self.Pe - self.Qaadd)
    self.SaN = pcr.min(self.Sa[k] / self.samax2, 1)
    self.SuN = self.Su[k] / self.sumax[k]

    self.Ea1 = pcr.max((self.PotEvaporation - self.Ei), 0) * pcr.min(
        self.Sa[k] / (self.samax2 * self.LP[k]), 1
    )
    self.Qa1 = (self.Pe - self.Qaadd) * (1 - (1 - self.SaN) ** self.beta[k])
    self.Fa1 = self.cropG * pcr.ifthenelse(
        self.SaN > 0,
        self.Fmin[k]
        + (self.Fmax[k] - self.Fmin[k]) * e ** (-self.decF[k] * (1 - self.SaN)),
        0,
    )
    self.Sa[k] = self.Sa_t[k] + (self.Pe - self.Qaadd) - self.Qa1 - self.Fa1 - self.Ea1

    self.Sa_diff = pcr.ifthenelse(self.Sa[k] < 0, self.Sa[k], 0)
    self.Qa = (
        self.Qa1
        + (
            self.Qa1
            / pcr.ifthenelse(
                self.Fa1 + self.Ea1 + self.Qa1 > 0, self.Fa1 + self.Ea1 + self.Qa1, 1
            )
        )
        * self.Sa_diff
    )
    self.Fa = (
        self.Fa1
        + (
            self.Fa1
            / pcr.ifthenelse(
                self.Fa1 + self.Ea1 + self.Qa1 > 0, self.Fa1 + self.Ea1 + self.Qa1, 1
            )
        )
        * self.Sa_diff
    )
    self.Ea = (
        self.Ea1
        + (
            self.Ea1
            / pcr.ifthenelse(
                self.Fa1 + self.Ea1 + self.Qa1 > 0, self.Fa1 + self.Ea1 + self.Qa1, 1
            )
        )
        * self.Sa_diff
    )
    self.Sa[k] = self.Sa_t[k] + (self.Pe - self.Qaadd) - self.Ea - self.Fa - self.Qa
    self.Sa[k] = pcr.ifthenelse(self.Sa[k] < 0, 0, self.Sa[k])
    self.Sa_diff2 = pcr.ifthen(self.Sa[k] < 0, self.Sa[k])

    self.wbSa_[k] = (
        self.Pe - self.Ea - self.Qa - self.Qaadd - self.Fa - self.Sa[k] + self.Sa_t[k]
    )

    self.Ea_[k] = self.Ea
    self.Qa_[k] = self.Qa + self.Qaadd
    self.Fa_[k] = self.Fa
logger.info(msg)
landmask_30sec = pcr.defined(pcr.readmap(landmask_30sec_file))
landmask_used  = pcr.ifthen(landmask_30sec, landmask_30sec)

# boolean maps to mask out permanent water bodies (lakes and reservoirs):
reservoirs_30sec_file = "/projects/0/aqueduct/users/edwinsut/data/reservoirs_and_lakes_30sec/grand_reservoirs_v1_1.boolean.map"
msg = "Set the (high resolution) reservoirs based on the file: " + str(reservoirs_30sec_file)
logger.info(msg)
reservoirs_30sec = pcr.cover(pcr.readmap(reservoirs_30sec_file), pcr.boolean(0.0))
lakes_30sec_file      = "/projects/0/aqueduct/users/edwinsut/data/reservoirs_and_lakes_30sec/glwd1_lakes.boolean.map"
msg = "Set the (high resolution) lakes based on the file: " + str(lakes_30sec_file)
logger.info(msg)
lakes_30sec = pcr.cover(pcr.readmap(lakes_30sec_file), pcr.boolean(0.0))
#
# cells that do not belong lakes and reservoirs
non_permanent_water_bodies = pcr.ifthenelse(reservoirs_30sec, pcr.boolean(0.0), pcr.boolean(1.0))
non_permanent_water_bodies = pcr.ifthen(non_permanent_water_bodies, non_permanent_water_bodies)
non_permanent_water_bodies = pcr.ifthenelse(     lakes_30sec, pcr.boolean(0.0), non_permanent_water_bodies)
non_permanent_water_bodies = pcr.ifthen(non_permanent_water_bodies, non_permanent_water_bodies)
#~ pcr.aguila(non_permanent_water_bodies)

# Convert pcraster files to a netcdt file:
msg = "Convert pcraster maps to a netcdf file."
logger.info(msg)

# netcdf general setup:
netcdf_setup = {}
netcdf_setup['format']          = "NETCDF4"
netcdf_setup['zlib']            = False
netcdf_setup['institution']     = "Department of Physical Geography, Utrecht University"
netcdf_setup['title'      ]     = "PCR-GLOBWB 2 output (post-processed for the Aqueduct Flood Analyzer): Flood Inundation Depth (above surface level)."