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
Esempio n. 2
0
def agriZone_Ep_Sa_cropG(self, k):
    """
    - Potential evaporation is decreased by energy used for interception evaporation    
    - Formula for evaporation based on LP
    - Outgoing fluxes are determined based on (value in previous timestep + inflow) 
    and if this leads to negative storage, the outgoing fluxes are corrected to rato --> Eu is 
    no longer taken into account for this correction
    - Qa u is determined from overflow from Sa
    - Fa is based on storage in Sa
    - Code for ini-file: 4
    """
    JarvisCoefficients.calcEp(self, k)
    self.PotEvaporation = pcr.cover(pcr.ifthenelse(self.EpHour >= 0, self.EpHour, 0), 0)

    self.samax2 = self.samax[k] * self.cropG
    self.Qaadd = pcr.max(self.Sa_t[k] - self.samax2, 0)

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

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

    self.Fa1 = pcr.ifthenelse(
        self.SaN > 0,
        self.Fmin[k]
        + (self.Fmax[k] - self.Fmin[k]) * e ** (-self.decF[k] * (1 - self.SaN)),
        0,
    )
    self.Sa[k] = self.Sa_t[k] + (self.Pe - self.Qa) - self.Fa1 - self.Ea1

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

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

    self.Ea_[k] = self.Ea
    self.Qa_[k] = self.Qa
    self.Fa_[k] = self.Fa
Esempio n. 3
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
Esempio n. 4
0
def rainfall_interception_hbv(Rainfall, PotEvaporation, Cmax, InterceptionStorage):
    """
    Returns:
    TF, Interception, IntEvap,InterceptionStorage
    """
    Interception = pcr.min(
        Rainfall, Cmax - InterceptionStorage
    )  #: Interception in mm/timestep

    InterceptionStorage = (
        InterceptionStorage + Interception
    )  #: Current interception storage
    TF = Rainfall - Interception
    IntEvap = pcr.min(
        InterceptionStorage, PotEvaporation
    )  #: Evaporation from interception storage
    InterceptionStorage = InterceptionStorage - IntEvap

    return TF, Interception, IntEvap, InterceptionStorage
Esempio n. 5
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
Esempio n. 6
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
Esempio n. 7
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
Esempio n. 8
0
    def getICs(self, iniItems, iniConditions=None):

        # print iniItems.groundwaterOptions['storGroundwaterFossilIni']

        # initial condition for storGroundwater (unit: m)
        if iniConditions == None:  # when the model just start
            self.storGroundwater = vos.readPCRmapClone(
                iniItems.groundwaterOptions['storGroundwaterIni'],
                self.cloneMap, self.tmpDir, self.inputDir)
            self.avgAbstraction = vos.readPCRmapClone(
                iniItems.groundwaterOptions['avgTotalGroundwaterAbstractionIni'],
                self.cloneMap, self.tmpDir, self.inputDir)
        else:                     # during/after spinUp
            self.storGroundwater = iniConditions['groundwater']['storGroundwater']
            self.avgAbstraction = iniConditions['groundwater']['avgTotalGroundwaterAbstractionIni']

        # initial condition for storGroundwaterFossil (unit: m)
        #
        # Note that storGroundwaterFossil should not be depleted during the spin-up.
        #
        if iniItems.groundwaterOptions['storGroundwaterFossilIni'] != "Maximum":
            #logger.info("Using a pre-defined initial condition for fossil groundwater storage.")
            self.storGroundwaterFossil = vos.readPCRmapClone(
                iniItems.groundwaterOptions['storGroundwaterFossilIni'],
                self.cloneMap, self.tmpDir, self.inputDir)
        #
        if self.limitFossilGroundwaterAbstraction and iniItems.groundwaterOptions['storGroundwaterFossilIni'] != "Maximum":
            #logger.info("The pre-defined initial condition for fossil groundwater is limited by fossilWaterCap (full capacity).")
            self.storGroundwaterFossil = pcr.min(
                self.storGroundwaterFossil, self.fossilWaterCap)
        #
        if self.limitFossilGroundwaterAbstraction and iniItems.groundwaterOptions['storGroundwaterFossilIni'] == "Maximum":
            #logger.info("Assuming 'full' fossilWaterCap as the initial condition for fossil groundwater storage.")
            self.storGroundwaterFossil = self.fossilWaterCap

        # make sure that active storGroundwater and avgAbstraction cannot be negative
        #
        self.storGroundwater = pcr.cover(self.storGroundwater, 0.0)
        self.storGroundwater = pcr.max(0., self.storGroundwater)
        self.storGroundwater = pcr.ifthen(self.landmask,
                                          self.storGroundwater)
        #
        self.avgAbstraction = pcr.cover(self.avgAbstraction, 0.0)
        self.avgAbstraction = pcr.max(0., self.avgAbstraction)
        self.avgAbstraction = pcr.ifthen(self.landmask,
                                         self.avgAbstraction)

        # storGroundwaterFossil can be negative (particularly if limitFossilGroundwaterAbstraction == False)
        self.storGroundwaterFossil = pcr.ifthen(self.landmask,
                                                self.storGroundwaterFossil)
Esempio n. 9
0
    def getLakeOutflow(self,
                       avgChannelDischarge,
                       length_of_time_step=vos.secondsPerDay()):

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

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

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

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

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

        return (lakeOutflow)
    def lateralFlow(self):
        self.calculateLateralFlow()
        self.soilMoistureThick = self.soilMoistureThick - self.lateralFlowFluxAmount + pcr.upstream(
            self.ldd, self.lateralFlowFluxAmount)
        self.upwardSeepageAmount = pcr.max(
            pcr.scalar(0.0), self.soilMoistureThick - self.soilPorosityThick)
        self.soilMoistureThick = pcr.min(self.soilMoistureThick,
                                         self.soilPorosityThick)

        self.upwardSeepageFlux = self.amountToFlux(self.upwardSeepageAmount)
        self.totalUpwardSeepageInUpstreamArea()
        self.totalSoilMoistureThickInUpstreamArea()
        self.totalSoilMoistureFractionInUpstreamArea()
        self.totalSaturatedThickInUpstreamArea()
        return self.upwardSeepageFlux
    def abstractWater(self, potentialAbstractionFlux):
        # DJ add check on potentialAbstractionFlux >= 0
        self.calculateMaximumAbstractionThick()
        potentialAbstractionFluxAmount = self.fluxToAmount(
            potentialAbstractionFlux)
        self.actualAbstractionFluxAmount = pcr.min(
            self.maximumAbstractionThick, potentialAbstractionFluxAmount)
        self.soilMoistureThick = self.soilMoistureThick - self.actualAbstractionFluxAmount

        # conversions
        self.actualAbstractionFlux = self.amountToFlux(
            self.actualAbstractionFluxAmount)

        # for a report
        self.totalActualAbstractionInUpstreamArea()

        return self.actualAbstractionFlux
Esempio n. 12
0
def agriZone_Jarvis(self, k):
    """
    - Potential evaporation is decreased by energy used for interception evaporation    
    - Formula for evaporation based on Jarvis stress functions
    - Outgoing fluxes are determined based on (value in previous timestep + inflow) 
    and if this leads to negative storage, the outgoing fluxes are corrected to rato --> Eu is 
    no longer taken into account for this correction
    - Qa u is determined from overflow from Sa
    - Code for ini-file: 1
    """
    self.Qa = pcr.max(self.Pe - (self.samax[k] - self.Sa_t[k]), 0)
    self.Sa[k] = self.Sa_t[k] + (self.Pe - self.Qa)
    self.SaN = pcr.min(self.Sa[k] / self.samax2, 1)
    self.SuN = self.Su[k] / self.sumax[k]

    JarvisCoefficients.calcEu(
        self, k, 1
    )  # calculation of Ea based on Jarvis stress functions
    self.Ea1 = self.Eu

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

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

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

    self.Ea_[k] = self.Ea
    self.Qa_[k] = self.Qa
    self.Fa_[k] = self.Fa
 def mapFilling(self, map_with_MV, map_without_MV, method = "window_average"):
 
     # ----- method 1: inverse distance method (but too slow)
     if method == "inverse_distance":
         logger.info('Extrapolation using "inverse distance" in progress!')
         #
         # - interpolation mask for cells without values
         interpolatedMask = pcr.ifthenelse(\
                            pcr.defined(map_with_MV),\
                            pcr.boolean(0),\
                            pcr.boolean(1),)
         map_with_MV_intrpl = pcr.inversedistance(interpolatedMask, \
                                                map_with_MV, 2, 1.50, 25)
     #
     else: # method 2: using window average
         logger.info('Extrapolation using "modified window average" in progress!')
         #
         map_with_MV_intrpl = 0.70 * pcr.windowaverage(map_with_MV, 1.50) + \
                              0.25 * pcr.windowaverage(map_with_MV, 2.00) + \
                              0.05 * pcr.windowaverage(map_with_MV, 2.50) + \
                              pcr.scalar(0.0)
     #
     # - interpolated values are only introduced in cells with MV 
     map_with_MV_intrpl = pcr.cover(map_with_MV, map_with_MV_intrpl)
     #
     # - calculating weight factor:
     weight_factor = pcr.scalar(pcr.defined(map_with_MV))
     weight_factor = pcr.windowaverage(0.70*weight_factor, 1.50) +\
                     pcr.windowaverage(0.25*weight_factor, 2.00) +\
                     pcr.windowaverage(0.05*weight_factor, 2.50)
     weight_factor = pcr.min(1.0, weight_factor)
     weight_factor = pcr.max(0.0, weight_factor)
     weight_factor = pcr.cover(weight_factor, 0.0)
     #
     # merge with weight factor
     merged_map = weight_factor  * map_with_MV_intrpl + \
           (1.0 - weight_factor) * map_without_MV
     #
     # retain the original values and make sure that all values are covered
     filled_map = pcr.cover(map_with_MV, merged_map)
     filled_map = pcr.cover(filled_map, map_without_MV)
 
     logger.info('Extrapolation is done!')
     return filled_map
	def kinAlphaDynamic(self,watStor):
		#-given the total water storage in the cell, returns the Q-A relationship
		# for the kinematic wave and required parameters
		floodVol= pcr.max(0,watStor-self.channelStorageCapacity)
		floodFrac, floodZ= self.returnFloodedFraction(floodVol)
		#-wetted perimeter, cross-sectional area and
		# corresponding mannings' n
		wetA= watStor/self.channelLength
		#-wetted perimeter, alpha and composite manning's n
		wetPFld= pcr.max(0.,floodFrac*self.cellArea/self.channelLength-\
			self.channelWidth)+2.*floodZ
		wetPCh= self.channelWidth+\
			2.*pcr.min(self.channelDepth,watStor/self.channelArea)
		wetP= wetPFld+wetPCh
		manQ= (wetPCh/wetP*self.channelManN**1.5+\
			wetPFld/wetP*self.floodplainManN**1.5)**(2./3.)
		alphaQ= (manQ*wetP**(2./3.)*self.channelGradient**-0.5)**self.betaQ
		#-returning variables of interest: flooded fraction, cross-sectional area
		# and alphaQ
		return floodFrac,floodZ,wetA,alphaQ
Esempio n. 15
0
 def kinAlphaDynamic(self, watStor):
     #-given the total water storage in the cell, returns the Q-A relationship
     # for the kinematic wave and required parameters
     floodVol = pcr.max(0, watStor - self.channelStorageCapacity)
     floodFrac, floodZ = self.returnFloodedFraction(floodVol)
     #-wetted perimeter, cross-sectional area and
     # corresponding mannings' n
     wetA = watStor / self.channelLength
     #-wetted perimeter, alpha and composite manning's n
     wetPFld= pcr.max(0.,floodFrac*self.cellArea/self.channelLength-\
      self.channelWidth)+2.*floodZ
     wetPCh= self.channelWidth+\
      2.*pcr.min(self.channelDepth,watStor/self.channelArea)
     wetP = wetPFld + wetPCh
     manQ= (wetPCh/wetP*self.channelManN**1.5+\
      wetPFld/wetP*self.floodplainManN**1.5)**(2./3.)
     alphaQ = (manQ * wetP**(2. / 3.) *
               self.channelGradient**-0.5)**self.betaQ
     #-returning variables of interest: flooded fraction, cross-sectional area
     # and alphaQ
     return floodFrac, floodZ, wetA, alphaQ
Esempio n. 16
0
    def moveFromChannelToWaterBody(
        self,
        newStorageAtLakeAndReservoirs,
        timestepsToAvgDischarge,
        maxTimestepsToAvgDischargeShort,
        length_of_time_step=vos.secondsPerDay(),
    ):

        # new lake and/or reservoir storages (m3)
        newStorageAtLakeAndReservoirs = pcr.cover(
            pcr.areatotal(newStorageAtLakeAndReservoirs, self.waterBodyIds), 0.0
        )

        # incoming volume (m3)
        self.inflow = newStorageAtLakeAndReservoirs - self.waterBodyStorage

        # inflowInM3PerSec (m3/s)
        inflowInM3PerSec = self.inflow / length_of_time_step

        # updating (short term) average inflow (m3/s) ;
        # - needed to constrain lake outflow:
        #
        temp = pcr.max(
            1.0,
            pcr.min(
                maxTimestepsToAvgDischargeShort,
                self.timestepsToAvgDischarge
                - 1.0
                + length_of_time_step / vos.secondsPerDay(),
            ),
        )
        deltaInflow = inflowInM3PerSec - self.avgInflow
        R = deltaInflow * (length_of_time_step / vos.secondsPerDay()) / temp
        self.avgInflow = self.avgInflow + R
        self.avgInflow = pcr.max(0.0, self.avgInflow)
        #
        # for the reference, see the "weighted incremental algorithm" in http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance

        # updating waterBodyStorage (m3)
        self.waterBodyStorage = newStorageAtLakeAndReservoirs
Esempio n. 17
0
    def moveFromChannelToWaterBody(
            self,
            newStorageAtLakeAndReservoirs,
            timestepsToAvgDischarge,
            maxTimestepsToAvgDischargeShort,
            length_of_time_step=vos.secondsPerDay(),
    ):

        # new lake and/or reservoir storages (m3)
        newStorageAtLakeAndReservoirs = pcr.cover(
            pcr.areatotal(newStorageAtLakeAndReservoirs, self.waterBodyIds),
            0.0)

        # incoming volume (m3)
        self.inflow = newStorageAtLakeAndReservoirs - self.waterBodyStorage

        # inflowInM3PerSec (m3/s)
        inflowInM3PerSec = self.inflow / length_of_time_step

        # updating (short term) average inflow (m3/s) ;
        # - needed to constrain lake outflow:
        #
        temp = pcr.max(
            1.0,
            pcr.min(
                maxTimestepsToAvgDischargeShort,
                self.timestepsToAvgDischarge - 1.0 +
                length_of_time_step / vos.secondsPerDay(),
            ),
        )
        deltaInflow = inflowInM3PerSec - self.avgInflow
        R = deltaInflow * (length_of_time_step / vos.secondsPerDay()) / temp
        self.avgInflow = self.avgInflow + R
        self.avgInflow = pcr.max(0.0, self.avgInflow)
        #
        # for the reference, see the "weighted incremental algorithm" in http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance

        # updating waterBodyStorage (m3)
        self.waterBodyStorage = newStorageAtLakeAndReservoirs
Esempio n. 18
0
def agriZone_Jarvis(self, k):
    """
    - Potential evaporation is decreased by energy used for interception evaporation    
    - Formula for evaporation based on Jarvis stress functions
    - Outgoing fluxes are determined based on (value in previous timestep + inflow) 
    and if this leads to negative storage, the outgoing fluxes are corrected to rato --> Eu is 
    no longer taken into account for this correction
    - Qa u is determined from overflow from Sa
    - Code for ini-file: 1
    """
    self.Qa = pcr.max(self.Pe - (self.samax[k] - self.Sa_t[k]), 0)
    self.Sa[k] = self.Sa_t[k] + (self.Pe - self.Qa)
    self.SaN = pcr.min(self.Sa[k] / self.samax2, 1)
    self.SuN = self.Su[k] / self.sumax[k]

    JarvisCoefficients.calcEu(
        self, k, 1)  # calculation of Ea based on Jarvis stress functions
    self.Ea1 = self.Eu

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

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

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

    self.Ea_[k] = self.Ea
    self.Qa_[k] = self.Qa
    self.Fa_[k] = self.Fa
def inverse_gumbel(p_zero, loc, scale, return_period):
    """
    This function computes values for a given return period using the zero probability, location and shape
    parameters given. 
    """

    p = pcr.scalar(1. - 1./return_period)
    
    # p_residual is the probability density function of the population consisting of any values above zero
    p_residual = pcr.min(pcr.max((p - p_zero) / (1.0 - p_zero), 0.0), 1.0) 

    #~ # - alternative equation found on:  https://repos.deltares.nl/repos/Hydrology/trunk/GLOFRIS/src/rp_bias_corr.py (see the method inv_gumbel)
    #~ p_residual = np.minimum(np.maximum((p-p_zero)/(1-p_zero), 0), np.float64(1-1./1e9))  # I think this is the correct equation"""
    
    reduced_variate = -pcr.ln(-pcr.ln(p_residual))

    flvol = reduced_variate * scale + loc

    # infinite numbers can occur. reduce these to zero!
    # if any values become negative due to the statistical extrapolation, fix them to zero (may occur if the sample size for fitting was small and a small return period is requested)
    flvol = pcr.max(0.0, pcr.cover(flvol, 0.0))

    return flvol
Esempio n. 20
0
    def dem_lowering(self, msr, area_polluted):
        """Calculate the cost and standard deviation of lowering the DEM."""

        if msr.settings.loc['msr_type', 1] in ['sidechannel', 'lowering']:
            # Determine the total volumetric difference over the measure area
            # Assume that polluted area is < 0.5 m deep, see doc and Middelkoop.
            dh_tot = self.ref_dem - msr.dem
            dh_polluted = pcr.ifthen(area_polluted, pcr.min(0.5, dh_tot))
            #            pcr.aguila(dh_polluted)
            dV_tot = dh_tot * pcr.cellarea()
            dV_polluted = dh_polluted * pcr.cellarea()
            volume_tot = area_total_value(dV_tot, msr.area)
            volume_polluted = area_total_value(dV_polluted, area_polluted)
        else:
            volume_tot = 0
            volume_polluted = 0
        # Return cost and standard deviation as a dataframe
        cost_ew = self.cost_input.iloc[0:3, 0:2]
        cost_init = volume_tot * cost_ew.drop('flpl_low_polluted')
        cost_polluted = volume_polluted * cost_ew.loc['flpl_low_polluted', :]
        cost_out = cost_init.copy()
        cost_out = cost_out.append(cost_polluted)
        return cost_out
    def estimate_bottom_of_bank_storage(self):

        # influence zone depth (m)
        influence_zone_depth = 0.5

        # bottom_elevation > flood_plain elevation - influence zone
        bottom_of_bank_storage = self.dem_floodplain - influence_zone_depth

        #~ # bottom_elevation > river bed
        #~ bottom_of_bank_storage = pcr.max(self.dem_riverbed, bottom_of_bank_storage)

        # bottom_elevation > its downstream value
        bottom_of_bank_storage = pcr.max(bottom_of_bank_storage, \
                                 pcr.cover(pcr.downstream(self.lddMap, bottom_of_bank_storage), bottom_of_bank_storage))

        # bottom_elevation >= 0.0 (must be higher than sea level)
        bottom_of_bank_storage = pcr.max(0.0, bottom_of_bank_storage)

        # reducing noise
        bottom_of_bank_storage = pcr.max(bottom_of_bank_storage,\
                                 pcr.windowaverage(bottom_of_bank_storage, 3.0 * pcr.clone().cellSize()))

        # bottom_elevation < dem_average
        bottom_of_bank_storage = pcr.min(bottom_of_bank_storage,
                                         self.dem_average)
        bottom_of_bank_storage = pcr.cover(bottom_of_bank_storage,
                                           self.dem_average)

        # TODO: Check again this concept.

        # TODO: We may want to improve this concept - by incorporating the following
        # - smooth bottom_elevation
        # - upstream areas in the mountainous regions and above perrenial stream starting points may also be drained (otherwise water will accumulate)
        # - bottom_elevation > minimum elevation that is estimated from the maximum of S3 from the PCR-GLOBWB simulation

        return bottom_of_bank_storage
Esempio n. 22
0
    def __init__(self, iniItems, landmask):
        object.__init__(self)
        
        # cloneMap, temporary directory for the resample process, temporary directory for the modflow process, absolute path for input directory, landmask
        self.cloneMap        = iniItems.cloneMap
        self.tmpDir          = iniItems.tmpDir
        self.tmp_modflow_dir = iniItems.tmp_modflow_dir
        self.inputDir        = iniItems.globalOptions['inputDir']
        self.landmask        = landmask
        
        # configuration from the ini file
        self.iniItems = iniItems
                
        # topography properties: read several variables from the netcdf file
        for var in ['dem_minimum','dem_maximum','dem_average','dem_standard_deviation',\
                    'slopeLength','orographyBeta','tanslope',\
                    'dzRel0000','dzRel0001','dzRel0005',\
                    'dzRel0010','dzRel0020','dzRel0030','dzRel0040','dzRel0050',\
                    'dzRel0060','dzRel0070','dzRel0080','dzRel0090','dzRel0100']:
            vars(self)[var] = vos.netcdf2PCRobjCloneWithoutTime(self.iniItems.modflowParameterOptions['topographyNC'], \
                                                                var, self.cloneMap)
            vars(self)[var] = pcr.cover(vars(self)[var], 0.0)

        # channel properties: read several variables from the netcdf file
        for var in ['lddMap','cellAreaMap','gradient','bankfull_width',
                    'bankfull_depth','dem_floodplain','dem_riverbed']:
            vars(self)[var] = vos.netcdf2PCRobjCloneWithoutTime(self.iniItems.modflowParameterOptions['channelNC'], \
                                                                var, self.cloneMap)
            vars(self)[var] = pcr.cover(vars(self)[var], 0.0)
        
        # minimum channel width
        minimum_channel_width = 0.5                                               # TODO: Define this one in the configuration file
        self.bankfull_width = pcr.max(minimum_channel_width, self.bankfull_width)
        
        #~ # cell fraction if channel water reaching the flood plan               # NOT USED YET 
        #~ self.flood_plain_fraction = self.return_innundation_fraction(pcr.max(0.0, self.dem_floodplain - self.dem_minimum))
        
        # coefficient of Manning
        self.manningsN = vos.readPCRmapClone(self.iniItems.modflowParameterOptions['manningsN'],\
                                             self.cloneMap,self.tmpDir,self.inputDir)
        
        # minimum channel gradient
        minGradient   = 0.00005                                                   # TODO: Define this one in the configuration file
        self.gradient = pcr.max(minGradient, pcr.cover(self.gradient, minGradient))

        # correcting lddMap
        self.lddMap = pcr.ifthen(pcr.scalar(self.lddMap) > 0.0, self.lddMap)
        self.lddMap = pcr.lddrepair(pcr.ldd(self.lddMap))
        
        # channelLength = approximation of channel length (unit: m)  # This is approximated by cell diagonal. 
        cellSizeInArcMin      = np.round(pcr.clone().cellSize()*60.)               # FIXME: This one will not work if you use the resolution: 0.5, 1.5, 2.5 arc-min
        verticalSizeInMeter   = cellSizeInArcMin*1852.                            
        horizontalSizeInMeter = self.cellAreaMap/verticalSizeInMeter
        self.channelLength    = ((horizontalSizeInMeter)**(2)+\
                                 (verticalSizeInMeter)**(2))**(0.5)
        
        # option for lakes and reservoir
        self.onlyNaturalWaterBodies = False
        if self.iniItems.modflowParameterOptions['onlyNaturalWaterBodies'] == "True": self.onlyNaturalWaterBodies = True

        # groundwater linear recession coefficient (day-1) ; the linear reservoir concept is still being used to represent fast response flow  
        #                                                                                                                  particularly from karstic aquifer in mountainous regions                    
        self.recessionCoeff = vos.netcdf2PCRobjCloneWithoutTime(self.iniItems.modflowParameterOptions['groundwaterPropertiesNC'],\
                                                                 'recessionCoeff', self.cloneMap)
        self.recessionCoeff = pcr.cover(self.recessionCoeff,0.00)       
        self.recessionCoeff = pcr.min(1.0000,self.recessionCoeff)       
        #
        if 'minRecessionCoeff' in iniItems.modflowParameterOptions.keys():
            minRecessionCoeff = float(iniItems.modflowParameterOptions['minRecessionCoeff'])
        else:
            minRecessionCoeff = 1.0e-4                                       # This is the minimum value used in Van Beek et al. (2011). 
        self.recessionCoeff = pcr.max(minRecessionCoeff,self.recessionCoeff)      
        
        # aquifer saturated conductivity (m/day)
        self.kSatAquifer = vos.netcdf2PCRobjCloneWithoutTime(self.iniItems.modflowParameterOptions['groundwaterPropertiesNC'],\
                                                             'kSatAquifer', self.cloneMap)
        self.kSatAquifer = pcr.cover(self.kSatAquifer,pcr.mapmaximum(self.kSatAquifer))       
        self.kSatAquifer = pcr.max(0.001,self.kSatAquifer)
        # TODO: Define the minimum value as part of the configuration file
        
        # aquifer specific yield (dimensionless)
        self.specificYield = vos.netcdf2PCRobjCloneWithoutTime(self.iniItems.modflowParameterOptions['groundwaterPropertiesNC'],\
                                                               'specificYield', self.cloneMap)
        self.specificYield = pcr.cover(self.specificYield,pcr.mapmaximum(self.specificYield))       
        self.specificYield = pcr.max(0.010,self.specificYield)         # TODO: TO BE CHECKED: The resample process of specificYield     
        self.specificYield = pcr.min(1.000,self.specificYield)       
        # TODO: Define the minimum value as part of the configuration file

        # estimate of thickness (unit: m) of accesible groundwater 
        totalGroundwaterThickness = vos.netcdf2PCRobjCloneWithoutTime(self.iniItems.modflowParameterOptions['estimateOfTotalGroundwaterThicknessNC'],\
                                    'thickness', self.cloneMap)
        # extrapolation 
        totalGroundwaterThickness = pcr.cover(totalGroundwaterThickness,\
                                    pcr.windowaverage(totalGroundwaterThickness, 1.0))
        totalGroundwaterThickness = pcr.cover(totalGroundwaterThickness,\
                                    pcr.windowaverage(totalGroundwaterThickness, 1.5))
        totalGroundwaterThickness = pcr.cover(totalGroundwaterThickness, 0.0)
        #
        # set minimum thickness
        minimumThickness = pcr.scalar(float(\
                           self.iniItems.modflowParameterOptions['minimumTotalGroundwaterThickness']))
        totalGroundwaterThickness = pcr.max(minimumThickness, totalGroundwaterThickness)
        #
        # set maximum thickness: 250 m.   # TODO: Define this one as part of the ini file
        maximumThickness = 250.
        self.totalGroundwaterThickness = pcr.min(maximumThickness, totalGroundwaterThickness)
        # TODO: Define the maximum value as part of the configuration file

        # surface water bed thickness  (unit: m)
        bed_thickness  = 0.1              # TODO: Define this as part of the configuration file
        # surface water bed resistance (unit: day)
        bed_resistance = bed_thickness / (self.kSatAquifer) 
        minimum_bed_resistance = 1.0      # TODO: Define this as part of the configuration file
        self.bed_resistance = pcr.max(minimum_bed_resistance,\
                                              bed_resistance,)
        
        # option to ignore capillary rise
        self.ignoreCapRise = True
        if self.iniItems.modflowParameterOptions['ignoreCapRise'] == "False": self.ignoreCapRise = False
        
        # a variable to indicate if the modflow has been called or not
        self.modflow_has_been_called = False
        
        # list of the convergence criteria for HCLOSE (unit: m)
        # - Deltares default's value is 0.001 m                         # check this value with Jarno
        self.criteria_HCLOSE = [0.001, 0.005, 0.01, 0.02, 0.05, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0]  
        self.criteria_HCLOSE = sorted(self.criteria_HCLOSE)
        
        # list of the convergence criteria for RCLOSE (unit: m3)
        # - Deltares default's value for their 25 and 250 m resolution models is 10 m3  # check this value with Jarno
        cell_area_assumption = verticalSizeInMeter * float(pcr.cellvalue(pcr.mapmaximum(horizontalSizeInMeter),1)[0])
        self.criteria_RCLOSE = [10., 10.* cell_area_assumption/(250.*250.), 10.* cell_area_assumption/(25.*25.)]
        self.criteria_RCLOSE = sorted(self.criteria_RCLOSE)

        # initiate the index for HCLOSE and RCLOSE
        self.iteration_HCLOSE = 0
        self.iteration_RCLOSE = 0
        
        # initiate old style reporting                                  # TODO: remove this!
        self.initiate_old_style_groundwater_reporting(iniItems)
Esempio n. 23
0
    def set_river_package(self, discharge, currTimeStep):

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

        if need_to_define_surface_water_bed:

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

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

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

        logger.info("Initializing pcraster modflow.")

        # initialise
        self.pcr_modflow = None
        self.pcr_modflow = pcr.initialise(pcr.clone())

        # grid specification - two layer model
        top_layer_2 = self.dem_average
        # - thickness of layer 1 is at least 10% of totalGroundwaterThickness            # TODO: Change this using Inge's thickness of confining layer.
        bottom_layer_2 = self.dem_average - 0.10 * self.totalGroundwaterThickness
        # - thickness of layer 1 should be until 5 m below the river bed
        bottom_layer_2 = pcr.min(self.dem_riverbed - 5.0, bottom_layer_2)
        # - make sure that the minimum thickness of layer 2 is at least 5.0 m
        thickness_of_layer_2 = pcr.max(5.0, top_layer_2 - bottom_layer_2)
        bottom_layer_2 = top_layer_2 - thickness_of_layer_2
        # - thickness of layer 1 is at least 5.0 m
        thickness_of_layer_1 = pcr.max(
            5.0, self.totalGroundwaterThickness - thickness_of_layer_2)
        bottom_layer_1 = bottom_layer_2 - thickness_of_layer_1
        self.pcr_modflow.createBottomLayer(bottom_layer_1, bottom_layer_2)
        self.pcr_modflow.addLayer(top_layer_2)

        # specification for the boundary condition (IBOUND, BAS package)
        # - active cells only in landmask
        # - constant head for outside the landmask
        ibound = pcr.ifthen(self.landmask, pcr.nominal(1))
        ibound = pcr.cover(ibound, pcr.nominal(-1))
        self.pcr_modflow.setBoundary(ibound, 1)  # upper layer
        self.pcr_modflow.setBoundary(ibound, 2)  # lower layer

        # specification for conductivities (BCF package)
        horizontal_conductivity = self.kSatAquifer  # unit: m/day
        # set the minimum value for transmissivity; (Deltares's default value: 10 m2/day)
        minimimumTransmissivity = 10.
        # - layer 2 (upper layer)
        horizontal_conductivity_layer_2 = pcr.max(minimimumTransmissivity, \
                                          horizontal_conductivity * thickness_of_layer_2) / thickness_of_layer_2
        vertical_conductivity_layer_2   = pcr.min(self.kSatAquifer, 0.00000000000000005) * self.cellAreaMap/\
                                          (pcr.clone().cellSize()*pcr.clone().cellSize())
        self.pcr_modflow.setConductivity(00, horizontal_conductivity_layer_2, \
                                             vertical_conductivity_layer_2, 2)
        # - layer 1 (lower layer)
        horizontal_conductivity_layer_1 = pcr.max(minimimumTransmissivity, \
                                          horizontal_conductivity * thickness_of_layer_1) / thickness_of_layer_1
        vertical_conductivity_layer_1 = vertical_conductivity_layer_2  # dummy values
        self.pcr_modflow.setConductivity(00, horizontal_conductivity_layer_1, \
                                             vertical_conductivity_layer_1, 1)

        # specification for storage coefficient
        # - correction due to the usage of lat/lon coordinates
        primary = pcr.cover(
            self.specificYield * self.cellAreaMap /
            (pcr.clone().cellSize() * pcr.clone().cellSize()), 0.0)
        primary = pcr.max(1e-20, primary)
        secondary = primary  # dummy values as we used layer type 00
        self.pcr_modflow.setStorage(primary, secondary, 1)
        self.pcr_modflow.setStorage(primary, secondary, 2)

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

    mv = -999.0

    inflow = pcr.ifthen(pcr.boolean(ReserVoirLocs), inflow)

    prec_av = pcr.ifthen(
        pcr.boolean(ReserVoirLocs), pcr.areaaverage(precip, ReservoirComplexAreas)
    )
    pet_av = pcr.ifthen(
        pcr.boolean(ReserVoirLocs), pcr.areaaverage(pet, ReservoirComplexAreas)
    )

    np_reslocs = pcr.pcr2numpy(ReserVoirLocs, 0.0)
    np_linkedreslocs = pcr.pcr2numpy(LinkedReserVoirLocs, 0.0)

    _outflow = []
    nr_loop = np.max([int(timestepsecs / 21600), 1])
    for n in range(0, nr_loop):
        np_waterlevel = pcr.pcr2numpy(waterlevel, np.nan)
        np_waterlevel_lower = np_waterlevel.copy()

        for val in np.unique(np_linkedreslocs):
            if val > 0:
                np_waterlevel_lower[np_linkedreslocs == val] = np_waterlevel[
                    np.where(np_reslocs == val)
                ]

        diff_wl = np_waterlevel - np_waterlevel_lower
        diff_wl[np.isnan(diff_wl)] = mv
        np_waterlevel_lower[np.isnan(np_waterlevel_lower)] = mv

        pcr_diff_wl = pcr.numpy2pcr(pcr.Scalar, diff_wl, mv)
        pcr_wl_lower = pcr.numpy2pcr(pcr.Scalar, np_waterlevel_lower, mv)

        storage_start = pcr.ifthenelse(
            ResStorFunc == 1,
            ResArea * waterlevel,
            lookupResFunc(ReserVoirLocs, waterlevel, sh, "0-1"),
        )

        outflow = pcr.ifthenelse(
            ResOutflowFunc == 1,
            lookupResRegMatr(ReserVoirLocs, waterlevel, hq, JDOY),
            pcr.ifthenelse(
                pcr_diff_wl >= 0,
                pcr.max(res_b * (waterlevel - ResThreshold) ** res_e, 0),
                pcr.min(-1 * res_b * (pcr_wl_lower - ResThreshold) ** res_e, 0),
            ),
        )

        np_outflow = pcr.pcr2numpy(outflow, np.nan)
        np_outflow_linked = np_reslocs * 0.0

        with np.errstate(invalid="ignore"):
            if np_outflow[np_outflow < 0] is not None:
                np_outflow_linked[
                    np.in1d(np_reslocs, np_linkedreslocs[np_outflow < 0]).reshape(
                        np_linkedreslocs.shape
                    )
                ] = np_outflow[np_outflow < 0]

        outflow_linked = pcr.numpy2pcr(pcr.Scalar, np_outflow_linked, 0.0)

        fl_nr_loop = float(nr_loop)
        storage = (
            storage_start
            + (inflow * timestepsecs / fl_nr_loop)
            + (prec_av / fl_nr_loop / 1000.0) * ResArea
            - (pet_av / fl_nr_loop / 1000.0) * ResArea
            - (pcr.cover(outflow, 0.0) * timestepsecs / fl_nr_loop)
            + (pcr.cover(outflow_linked, 0.0) * timestepsecs / fl_nr_loop)
        )

        waterlevel = pcr.ifthenelse(
            ResStorFunc == 1,
            waterlevel + (storage - storage_start) / ResArea,
            lookupResFunc(ReserVoirLocs, storage, sh, "1-0"),
        )

        np_outflow_nz = np_outflow * 0.0
        with np.errstate(invalid="ignore"):
            np_outflow_nz[np_outflow > 0] = np_outflow[np_outflow > 0]
        _outflow.append(np_outflow_nz)

    outflow_av_temp = np.average(_outflow, 0)
    outflow_av_temp[np.isnan(outflow_av_temp)] = mv
    outflow_av = pcr.numpy2pcr(pcr.Scalar, outflow_av_temp, mv)

    return waterlevel, outflow_av, prec_av, pet_av, storage
Esempio n. 27
0
    def update(self,landSurface,routing,currTimeStep):

        if self.debugWaterBalance:
            preStorGroundwater       = self.storGroundwater
            preStorGroundwaterFossil = self.storGroundwaterFossil
                
        # get riverbed infiltration from the previous time step (from routing)
        self.surfaceWaterInf  = routing.riverbedExchange/routing.cellArea     # m
        self.storGroundwater += self.surfaceWaterInf

        # get net recharge (percolation-capRise) and update storage:
        self.storGroundwater  = pcr.max(0.,\
                                self.storGroundwater + landSurface.gwRecharge)         
                        
        # potential groundwater abstraction (unit: m)
        potGroundwaterAbstract = landSurface.totalPotentialGrossDemand -\
                                 landSurface.allocSurfaceWaterAbstract 


        if self.usingAllocSegments == False or self.limitAbstraction:   
             
            # Note: For simplicity, no network for a run with limitAbstraction. 
        
            logger.info("Groundwater abstraction is only to satisfy local demand. No network for distributing groundwater.")

            # nonFossil groundwater abstraction (unit: m) to fulfill water demand 
            # - assumption: Groundwater is only abstracted to satisfy local demand.
            self.nonFossilGroundwaterAbs = \
                                           pcr.max(0.0,
                                           pcr.min(self.storGroundwater,\
                                           potGroundwaterAbstract)) 
            #
            self.allocNonFossilGroundwater = self.nonFossilGroundwaterAbs
        
        if self.usingAllocSegments and self.limitAbstraction == False:

            # Note: Incorporating distribution network of groundwater source is possible only if limitAbstraction = False.  

            logger.info("Using groundwater source allocation.")

            # gross/potential demand volume in each cell (unit: m3)
            cellVolGrossDemand = potGroundwaterAbstract*routing.cellArea
            
            # total gross demand volume in each segment/zone (unit: m3)
            segTtlGrossDemand  = pcr.areatotal(cellVolGrossDemand, self.allocSegments)
            
            # total available groundwater water volume in each cell - ignore small values (less than 1 m3)
            cellAvlGroundwater = pcr.max(0.00, self.storGroundwater* routing.cellArea)
            cellAvlGroundwater = pcr.rounddown( cellAvlGroundwater/1.)*1.
            
            # total available surface water volume in each segment/zone  (unit: m3)
            segAvlGroundwater  = pcr.areatotal(cellAvlGroundwater, self.allocSegments)
            segAvlGroundwater  = pcr.max(0.00,  segAvlGroundwater)
            
            # total actual surface water abstraction volume in each segment/zone (unit: m3)
            #
            # - not limited to available water - ignore small values (less than 1 m3)
            segActGroundwaterAbs = pcr.max(0.0,\
                                   pcr.rounddown(segTtlGrossDemand))
            # 
            # - limited to available water
            segActGroundwaterAbs = pcr.min(segAvlGroundwater, segActGroundwaterAbs)
            
            # actual surface water abstraction volume in each cell (unit: m3)
            volActGroundwaterAbstract = vos.getValDivZero(\
                                        cellAvlGroundwater, segAvlGroundwater, vos.smallNumber) * \
                                        segActGroundwaterAbs                                                 
            volActGroundwaterAbstract = pcr.min(cellAvlGroundwater , volActGroundwaterAbstract)              # unit: m3
            
            # actual non fossil groundwater abstraction volume in meter (unit: m)
            self.nonFossilGroundwaterAbs = pcr.ifthen(self.landmask, volActGroundwaterAbstract) /\
                                                                     routing.cellArea                        # unit: m
            
            # allocation non fossil groundwater abstraction volume to each cell (unit: m3)
            self.volAllocGroundwaterAbstract = vos.getValDivZero(\
                                               cellVolGrossDemand, segTtlGrossDemand, vos.smallNumber) *\
                                               segActGroundwaterAbs                                          # unit: m3 
            
            # allocation surface water abstraction in meter (unit: m)
            self.allocNonFossilGroundwater   = pcr.ifthen(self.landmask, self.volAllocGroundwaterAbstract)/\
                                                                         routing.cellArea                    # unit: m

            if self.debugWaterBalance == str('True'):
    
                abstraction = pcr.cover(pcr.areatotal(self.nonFossilGroundwaterAbs  *routing.cellArea, self.allocSegments)/self.segmentArea, 0.0)
                allocation  = pcr.cover(pcr.areatotal(self.allocNonFossilGroundwater*routing.cellArea, self.allocSegments)/self.segmentArea, 0.0)
            
                vos.waterBalanceCheck([abstraction],\
                                      [allocation],\
                                      [pcr.scalar(0.0)],\
                                      [pcr.scalar(0.0)],\
                                      'non fossil groundwater abstraction - allocation per zone/segment (PS: Error here may be caused by rounding error.)' ,\
                                       True,\
                                       "",threshold=5e-4)

        # update storGoundwater after self.nonFossilGroundwaterAbs
        self.storGroundwater  = pcr.max(0.,self.storGroundwater - self.nonFossilGroundwaterAbs)

        # unmetDemand (m), satisfied by fossil gwAbstractions           # TODO: Include desalinization
        self.unmetDemand = pcr.max(0.0,
                           potGroundwaterAbstract - \
                           self.allocNonFossilGroundwater)              # m (equal to zero if limitAbstraction = True)
        
        if self.limitAbstraction:
            logger.info("No fossil groundwater abstraction is allowed")
            # TODO: check that self.unmetDemand = 0.0

        # correcting unmetDemand with available fossil groundwater
        # Note: For simplicity, limitFossilGroundwaterAbstraction can only be combined with local source assumption
        if self.usingAllocSegments == False and self.limitFossilGroundwaterAbstraction:
            self.unmetDemand = pcr.min(pcr.max(0.0, self.storGroundwaterFossil), self.unmetDemand)

        # calculate the average groundwater abstraction (m/day) from the last 365 days:
        totalAbstraction    = self.unmetDemand + self.nonFossilGroundwaterAbs
        deltaAbstraction    = totalAbstraction - self.avgAbstraction  
        self.avgAbstraction = self.avgAbstraction +\
                                 deltaAbstraction/\
                              pcr.min(365., pcr.max(1.0, routing.timestepsToAvgDischarge))
        self.avgAbstraction = pcr.max(0.0, self.avgAbstraction)                                    

        # update storGroundwaterFossil after unmetDemand 
        self.storGroundwaterFossil -= self.unmetDemand
        
        # calculate baseflow and update storage:
        self.baseflow         = pcr.max(0.,\
                                pcr.min(self.storGroundwater,\
                                        self.recessionCoeff* \
                                        self.storGroundwater))
        self.storGroundwater  = pcr.max(0.,\
                                self.storGroundwater - self.baseflow)
        # PS: baseflow must be calculated at the end (to ensure the availability of storGroundwater to support nonFossilGroundwaterAbs)


        if self.debugWaterBalance:
            vos.waterBalanceCheck([self.surfaceWaterInf,\
                                   landSurface.gwRecharge],\
                                  [self.baseflow,\
                                   self.nonFossilGroundwaterAbs],\
                                  [  preStorGroundwater],\
                                  [self.storGroundwater],\
                                       'storGroundwater',\
                                   True,\
                                   currTimeStep.fulldate,threshold=1e-4)

        if self.debugWaterBalance:
            vos.waterBalanceCheck([pcr.scalar(0.0)],\
                                  [self.unmetDemand],\
                                  [  preStorGroundwaterFossil],\
                                  [self.storGroundwaterFossil],\
                                       'storGroundwaterFossil',\
                                   True,\
                                   currTimeStep.fulldate,threshold=1e-3)

        if self.debugWaterBalance and self.limitFossilGroundwaterAbstraction:
            vos.waterBalanceCheck([pcr.scalar(0.0)],\
                                  [self.unmetDemand],\
                                  [pcr.max(0.0,  preStorGroundwaterFossil)],\
                                  [pcr.max(0.0,self.storGroundwaterFossil)],\
                                       'storGroundwaterFossil (with limitFossilGroundwaterAbstraction)',\
                                   True,\
                                   currTimeStep.fulldate,threshold=1e-3)

        if self.debugWaterBalance and landSurface.limitAbstraction:
            vos.waterBalanceCheck([potGroundwaterAbstract],\
                                  [self.nonFossilGroundwaterAbs],\
                                  [pcr.scalar(0.)],\
                                  [pcr.scalar(0.)],\
                                  'non fossil groundwater abstraction',\
                                   True,\
                                   currTimeStep.fulldate,threshold=1e-4)

        if self.debugWaterBalance:
            vos.waterBalanceCheck([self.unmetDemand, self.allocNonFossilGroundwater, landSurface.allocSurfaceWaterAbstract],\
                                  [landSurface.totalPotentialGrossDemand],\
                                  [pcr.scalar(0.)],\
                                  [pcr.scalar(0.)],\
                                  'water demand allocation (from surface water, groundwater and unmetDemand)',\
                                   True,\
                                   currTimeStep.fulldate,threshold=1e-4)


        if self.report == True:
            timeStamp = datetime.datetime(currTimeStep.year,\
                                          currTimeStep.month,\
                                          currTimeStep.day,\
                                          0)
            # writing daily output to netcdf files
            timestepPCR = currTimeStep.timeStepPCR
            if self.outDailyTotNC[0] != "None":
                for var in self.outDailyTotNC:
                    self.netcdfObj.data2NetCDF(str(self.outNCDir)+"/"+ \
                                         str(var)+"_dailyTot.nc",\
                                         var,\
                          pcr2numpy(self.__getattribute__(var),vos.MV),\
                                         timeStamp,timestepPCR-1)

            # writing monthly output to netcdf files
            # -cummulative
            if self.outMonthTotNC[0] != "None":
                for var in self.outMonthTotNC:

                    # introduce variables at the beginning of simulation or
                    #     reset variables at the beginning of the month
                    if currTimeStep.timeStepPCR == 1 or \
                       currTimeStep.day == 1:\
                       vars(self)[var+'MonthTot'] = pcr.scalar(0.0)

                    # accumulating
                    vars(self)[var+'MonthTot'] += vars(self)[var]

                    # reporting at the end of the month:
                    if currTimeStep.endMonth == True: 
                        self.netcdfObj.data2NetCDF(str(self.outNCDir)+"/"+ \
                                         str(var)+"_monthTot.nc",\
                                         var,\
                          pcr2numpy(self.__getattribute__(var+'MonthTot'),\
                           vos.MV),timeStamp,currTimeStep.monthIdx-1)
            # -average
            if self.outMonthAvgNC[0] != "None":
                for var in self.outMonthAvgNC:
                    # only if a accumulator variable has not been defined: 
                    if var not in self.outMonthTotNC: 

                        # introduce accumulator at the beginning of simulation or
                        #     reset accumulator at the beginning of the month
                        if currTimeStep.timeStepPCR == 1 or \
                           currTimeStep.day == 1:\
                           vars(self)[var+'MonthTot'] = pcr.scalar(0.0)
                        # accumulating
                        vars(self)[var+'MonthTot'] += vars(self)[var]

                    # calculating average & reporting at the end of the month:
                    if currTimeStep.endMonth == True:
                        vars(self)[var+'MonthAvg'] = vars(self)[var+'MonthTot']/\
                                                     currTimeStep.day  
                        self.netcdfObj.data2NetCDF(str(self.outNCDir)+"/"+ \
                                         str(var)+"_monthAvg.nc",\
                                         var,\
                          pcr2numpy(self.__getattribute__(var+'MonthAvg'),\
                           vos.MV),timeStamp,currTimeStep.monthIdx-1)
            #
            # -last day of the month
            if self.outMonthEndNC[0] != "None":
                for var in self.outMonthEndNC:
                    # reporting at the end of the month:
                    if currTimeStep.endMonth == True: 
                        self.netcdfObj.data2NetCDF(str(self.outNCDir)+"/"+ \
                                         str(var)+"_monthEnd.nc",\
                                         var,\
                          pcr2numpy(self.__getattribute__(var),vos.MV),\
                                         timeStamp,currTimeStep.monthIdx-1)

            # writing yearly output to netcdf files
            # -cummulative
            if self.outAnnuaTotNC[0] != "None":
                for var in self.outAnnuaTotNC:

                    # introduce variables at the beginning of simulation or
                    #     reset variables at the beginning of the month
                    if currTimeStep.timeStepPCR == 1 or \
                       currTimeStep.doy == 1:\
                       vars(self)[var+'AnnuaTot'] = pcr.scalar(0.0)

                    # accumulating
                    vars(self)[var+'AnnuaTot'] += vars(self)[var]

                    # reporting at the end of the year:
                    if currTimeStep.endYear == True: 
                        self.netcdfObj.data2NetCDF(str(self.outNCDir)+"/"+ \
                                         str(var)+"_annuaTot.nc",\
                                         var,\
                          pcr2numpy(self.__getattribute__(var+'AnnuaTot'),\
                           vos.MV),timeStamp,currTimeStep.annuaIdx-1)
            # -average
            if self.outAnnuaAvgNC[0] != "None":
                for var in self.outAnnuaAvgNC:
                    # only if a accumulator variable has not been defined: 
                    if var not in self.outAnnuaTotNC: 
                        # introduce accumulator at the beginning of simulation or
                        #     reset accumulator at the beginning of the year
                        if currTimeStep.timeStepPCR == 1 or \
                           currTimeStep.doy == 1:\
                           vars(self)[var+'AnnuaTot'] = pcr.scalar(0.0)
                        # accumulating
                        vars(self)[var+'AnnuaTot'] += vars(self)[var]
                    #
                    # calculating average & reporting at the end of the year:
                    if currTimeStep.endYear == True:
                        vars(self)[var+'AnnuaAvg'] = vars(self)[var+'AnnuaTot']/\
                                                     currTimeStep.doy  
                        self.netcdfObj.data2NetCDF(str(self.outNCDir)+"/"+ \
                                         str(var)+"_annuaAvg.nc",\
                                         var,\
                          pcr2numpy(self.__getattribute__(var+'AnnuaAvg'),\
                           vos.MV),timeStamp,currTimeStep.annuaIdx-1)
            #
            # -last day of the year
            if self.outAnnuaEndNC[0] != "None":
                for var in self.outAnnuaEndNC:
                    # reporting at the end of the year:
                    if currTimeStep.endYear == True: 
                        self.netcdfObj.data2NetCDF(str(self.outNCDir)+"/"+ \
                                         str(var)+"_annuaEnd.nc",\
                                         var,\
                          pcr2numpy(self.__getattribute__(var),vos.MV),\
                                         timeStamp,currTimeStep.annuaIdx-1)
Esempio n. 28
0
    def getReservoirOutflow(self,\
        avgChannelDischarge,length_of_time_step,downstreamDemand):

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

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

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

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

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

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

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

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

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

        resvOutflow = pcr.ifthen(
            pcr.scalar(self.waterBodyIds) > 0., resvOutflow)
        resvOutflow = pcr.ifthen(
            pcr.scalar(self.waterBodyTyp) == 2, resvOutflow)
        return (resvOutflow)  # unit: m3
Esempio n. 29
0
    def readSoilMapOfFAO(self, iniItems, optionDict = None):

        # a dictionary/section of options that will be used
        if optionDict == None: optionDict = iniItems._sections["landSurfaceOptions"] #iniItems.landSurfaceOptions
        
        # soil variable names given either in the ini or netCDF file:
        soilParameters = ['airEntryValue1','airEntryValue2',       
                          'poreSizeBeta1','poreSizeBeta2',        
                          'resVolWC1','resVolWC2',            
                          'satVolWC1','satVolWC2',
                          'KSat1','KSat2',
                          'percolationImp']
        if optionDict['soilPropertiesNC'] == str(None):
            for var in soilParameters:
                input = optionDict[str(var)]
                vars(self)[var] = \
                               vos.readPCRmapClone(input,self.cloneMap,\
                                             self.tmpDir,self.inputDir)
                vars(self)[var] = pcr.scalar(vars(self)[var])

                if input == "percolationImp": vars(self)[var] = pcr.cover(vars(self)[var], 0.0)
                
                # extrapolation 
                # - TODO: Make a general extrapolation option as a function in the virtualOS.py 
                vars(self)[var] = pcr.cover(vars(self)[var],
                                  pcr.windowaverage(vars(self)[var], 0.75))
                vars(self)[var] = pcr.cover(vars(self)[var],
                                  pcr.windowaverage(vars(self)[var], 1.00))
                vars(self)[var] = pcr.cover(vars(self)[var],
                                  pcr.windowaverage(vars(self)[var], 1.00))
                vars(self)[var] = pcr.cover(vars(self)[var],
                                  pcr.windowaverage(vars(self)[var], 1.00))
                vars(self)[var] = pcr.cover(vars(self)[var],
                                  pcr.windowaverage(vars(self)[var], 1.00))
                vars(self)[var] = pcr.cover(vars(self)[var],
                                  pcr.windowaverage(vars(self)[var], 1.00))
                vars(self)[var] = pcr.cover(vars(self)[var], 0.0)

        else:
            soilPropertiesNC = vos.getFullPath(\
                               optionDict['soilPropertiesNC'],
                                                self.inputDir)
            for var in soilParameters:
                vars(self)[var] = vos.netcdf2PCRobjCloneWithoutTime(\
                                    soilPropertiesNC,var, \
                                    cloneMapFileName = self.cloneMap)

                if var == "percolationImp": vars(self)[var] = pcr.cover(vars(self)[var], 0.0)

                # extrapolation 
                # - TODO: Make a general extrapolation option as a function in the virtualOS.py 
                vars(self)[var] = pcr.cover(vars(self)[var],
                                  pcr.windowaverage(vars(self)[var], 0.75))
                vars(self)[var] = pcr.cover(vars(self)[var],
                                  pcr.windowaverage(vars(self)[var], 1.00))
                vars(self)[var] = pcr.cover(vars(self)[var],
                                  pcr.windowaverage(vars(self)[var], 1.00))
                vars(self)[var] = pcr.cover(vars(self)[var],
                                  pcr.windowaverage(vars(self)[var], 1.00))
                vars(self)[var] = pcr.cover(vars(self)[var],
                                  pcr.windowaverage(vars(self)[var], 1.00))
                vars(self)[var] = pcr.cover(vars(self)[var],
                                  pcr.windowaverage(vars(self)[var], 1.00))

                vars(self)[var] = pcr.cover(vars(self)[var], 0.01)
            
        # make sure that resVolWC1 <= satVolWC1
        self.resVolWC1 = pcr.min(self.resVolWC1, self.satVolWC1)
        self.resVolWC2 = pcr.min(self.resVolWC2, self.satVolWC2)
        
        if self.numberOfLayers == 2:
            self.satVolMoistContUpp = self.satVolWC1                         # saturated volumetric moisture content (m3.m-3)
            self.satVolMoistContLow = self.satVolWC2
            self.resVolMoistContUpp = self.resVolWC1                         # residual volumetric moisture content (m3.m-3)
            self.resVolMoistContLow = self.resVolWC2
            self.airEntryValueUpp   = self.airEntryValue1                    # air entry value (m) according to soil water retention curve of Clapp & Hornberger (1978)
            self.airEntryValueLow   = self.airEntryValue2
            self.poreSizeBetaUpp    = self.poreSizeBeta1                     # pore size distribution parameter according to Clapp & Hornberger (1978) 
            self.poreSizeBetaLow    = self.poreSizeBeta2
            self.kSatUpp            = self.KSat1                             # saturated hydraulic conductivity (m.day-1) 
            self.kSatLow            = self.KSat2

        if self.numberOfLayers == 3:
            self.satVolMoistContUpp000005 = self.satVolWC1     
            self.satVolMoistContUpp005030 = self.satVolWC1     
            self.satVolMoistContLow030150 = self.satVolWC2
            self.resVolMoistContUpp000005 = self.resVolWC1     
            self.resVolMoistContUpp005030 = self.resVolWC1     
            self.resVolMoistContLow030150 = self.resVolWC2
            self.airEntryValueUpp000005   = self.airEntryValue1
            self.airEntryValueUpp005030   = self.airEntryValue1
            self.airEntryValueLow030150   = self.airEntryValue2
            self.poreSizeBetaUpp000005    = self.poreSizeBeta1 
            self.poreSizeBetaUpp005030    = self.poreSizeBeta1 
            self.poreSizeBetaLow030150    = self.poreSizeBeta2
            self.kSatUpp000005            = self.KSat1         
            self.kSatUpp005030            = self.KSat1         
            self.kSatLow030150            = self.KSat2

        self.percolationImp = pcr.cover(self.percolationImp, 0.0)            # fractional area where percolation to groundwater store is impeded (dimensionless)

        # soil thickness and storage variable names 
        # as given either in the ini or netCDF file:
        soilStorages = ['firstStorDepth',      'secondStorDepth',      
                        'soilWaterStorageCap1','soilWaterStorageCap2'] 
        if optionDict['soilPropertiesNC'] == str(None):
            for var in soilStorages:
                input = optionDict[str(var)]
                temp = str(var)+'Inp'
                vars(self)[temp] = vos.readPCRmapClone(input,\
                                            self.cloneMap,
                                            self.tmpDir,self.inputDir)

                # extrapolation 
                # - TODO: Make a general extrapolation option as a function in the virtualOS.py 
                vars(self)[temp] = pcr.cover(vars(self)[temp],
                                   pcr.windowaverage(vars(self)[temp], 0.75))
                vars(self)[temp] = pcr.cover(vars(self)[temp],
                                   pcr.windowaverage(vars(self)[temp], 1.05))
                vars(self)[temp] = pcr.cover(vars(self)[temp],
                                   pcr.windowaverage(vars(self)[temp], 1.05))
                vars(self)[temp] = pcr.cover(vars(self)[temp],
                                   pcr.windowaverage(vars(self)[temp], 1.05))
                vars(self)[temp] = pcr.cover(vars(self)[temp],
                                   pcr.windowaverage(vars(self)[temp], 1.05))
                vars(self)[temp] = pcr.cover(vars(self)[temp],
                                   pcr.windowaverage(vars(self)[temp], 1.05))
                vars(self)[temp] = pcr.cover(vars(self)[temp], 0.0)

        else:
            soilPropertiesNC = vos.getFullPath(\
                               optionDict['soilPropertiesNC'],
                                                self.inputDir)
            for var in soilStorages:
                temp = str(var)+'Inp'
                vars(self)[temp] = vos.netcdf2PCRobjCloneWithoutTime(\
                                     soilPropertiesNC,var, \
                                     cloneMapFileName = self.cloneMap)
                # extrapolation 
                # - TODO: Make a general extrapolation option as a function in the virtualOS.py 
                vars(self)[temp] = pcr.cover(vars(self)[temp],
                                   pcr.windowaverage(vars(self)[temp], 0.75))
                vars(self)[temp] = pcr.cover(vars(self)[temp],
                                   pcr.windowaverage(vars(self)[temp], 1.05))
                vars(self)[temp] = pcr.cover(vars(self)[temp],
                                   pcr.windowaverage(vars(self)[temp], 1.05))
                vars(self)[temp] = pcr.cover(vars(self)[temp],
                                   pcr.windowaverage(vars(self)[temp], 1.05))
                vars(self)[temp] = pcr.cover(vars(self)[temp],
                                   pcr.windowaverage(vars(self)[temp], 1.05))
                vars(self)[temp] = pcr.cover(vars(self)[temp],
                                   pcr.windowaverage(vars(self)[temp], 1.05))
                vars(self)[temp] = pcr.cover(vars(self)[temp], 0.0)

        # layer thickness
        if self.numberOfLayers == 2:
            self.thickUpp = (0.30/0.30)*self.firstStorDepthInp
            self.thickLow = (1.20/1.20)*self.secondStorDepthInp
        if self.numberOfLayers == 3:
            self.thickUpp000005 = (0.05/0.30)*self.firstStorDepthInp
            self.thickUpp005030 = (0.25/0.30)*self.firstStorDepthInp
            self.thickLow030150 = (1.20/1.20)*self.secondStorDepthInp

        # soil storage
        if self.numberOfLayers == 2:
            #~ self.storCapUpp = (0.30/0.30)*self.soilWaterStorageCap1Inp
            #~ self.storCapLow = (1.20/1.20)*self.soilWaterStorageCap2Inp                     # 22 Feb 2014: We can calculate this based on thickness and porosity. 
            self.storCapUpp = self.thickUpp * \
                             (self.satVolMoistContUpp - self.resVolMoistContUpp)
            self.storCapLow = self.thickLow * \
                             (self.satVolMoistContLow - self.resVolMoistContLow)
            self.rootZoneWaterStorageCap = self.storCapUpp + \
                                           self.storCapLow                                    # This is called as WMAX in the original pcrcalc script. 
        if self.numberOfLayers == 3:
            self.storCapUpp000005 = self.thickUpp000005 * \
                             (self.satVolMoistContUpp000005 - self.resVolMoistContUpp000005)
            self.storCapUpp005030 = self.thickUpp005030 * \
                             (self.satVolMoistContUpp005030 - self.resVolMoistContUpp005030)
            self.storCapLow030150 = self.thickLow030150 * \
                             (self.satVolMoistContLow030150 - self.resVolMoistContLow030150)
            self.rootZoneWaterStorageCap = self.storCapUpp000005 + \
                                           self.storCapUpp005030 + \
                                           self.storCapLow030150
Esempio n. 30
0
def simplereservoir(
    storage,
    inflow,
    ResArea,
    maxstorage,
    target_perc_full,
    maximum_Q,
    demand,
    minimum_full_perc,
    ReserVoirLocs,
    precip,
    pet,
    ReservoirSimpleAreas,
    timestepsecs=86400,
):
    """

    :param storage: initial storage m^3
    :param inflow: inflow m^3/s
    :param maxstorage: maximum storage (above which water is spilled) m^3
    :param target_perc_full: target fraction full (of max storage) -
    :param maximum_Q: maximum Q to release m^3/s if below spillway
    :param demand: water demand (all combined) m^3/s
    :param minimum_full_perc: target minimum full fraction (of max storage) -
    :param ReserVoirLocs: map with reservoir locations
    :param timestepsecs: timestep of the model in seconds (default = 86400)
    :return: storage (m^3), outflow (m^3/s), PercentageFull (0-1), Release (m^3/sec)
    """

    inflow = pcr.ifthen(pcr.boolean(ReserVoirLocs), inflow)

    prec_av = pcr.cover(
        pcr.ifthen(
            pcr.boolean(ReserVoirLocs), pcr.areaaverage(precip, ReservoirSimpleAreas)
        ),
        pcr.scalar(0.0),
    )
    pet_av = pcr.cover(
        pcr.ifthen(
            pcr.boolean(ReserVoirLocs), pcr.areaaverage(pet, ReservoirSimpleAreas)
        ),
        pcr.scalar(0.0),
    )

    oldstorage = storage
    storage = (
        storage
        + (inflow * timestepsecs)
        + (prec_av / 1000.0) * ResArea
        - (pet_av / 1000.0) * ResArea
    )

    percfull = ((storage + oldstorage) * 0.5) / maxstorage
    # first determine minimum (environmental) flow using a simple sigmoid curve to scale for target level
    fac = sCurve(percfull, a=minimum_full_perc, c=30.0)
    demandRelease = pcr.min(fac * demand * timestepsecs, storage)
    storage = storage - demandRelease

    # Re-determine percfull
    percfull = ((storage + oldstorage) * 0.5) / maxstorage

    wantrel = pcr.max(0.0, storage - (maxstorage * target_perc_full))
    # Assume extra maximum Q if spilling
    overflowQ = (percfull - 1.0) * (storage - maxstorage)
    torelease = pcr.min(wantrel, overflowQ + maximum_Q * timestepsecs)
    storage = storage - torelease
    outflow = (torelease + demandRelease) / timestepsecs
    percfull = storage / maxstorage

    return storage, outflow, percfull, prec_av, pet_av, demandRelease / timestepsecs
                                       pcr.windowaverage(fraction_reserved_recharge, 0.5))
fraction_reserved_recharge = pcr.cover(fraction_reserved_recharge, \
                                       pcr.windowaverage(fraction_reserved_recharge, 0.5))
fraction_reserved_recharge = pcr.cover(fraction_reserved_recharge, \
                                       pcr.windowaverage(fraction_reserved_recharge, 0.5))
fraction_reserved_recharge = pcr.cover(fraction_reserved_recharge, \
                                       pcr.windowaverage(fraction_reserved_recharge, 0.5))
fraction_reserved_recharge = pcr.cover(fraction_reserved_recharge, \
                                       pcr.windowaverage(fraction_reserved_recharge, 0.5))
fraction_reserved_recharge = pcr.cover(fraction_reserved_recharge, \
                                       pcr.windowaverage(fraction_reserved_recharge, 0.5))
fraction_reserved_recharge = pcr.cover(fraction_reserved_recharge, 0.1)
# - set minimum value to 0.10
fraction_reserved_recharge = pcr.max(0.10, fraction_reserved_recharge)
# - set maximum value to 0.75
fraction_reserved_recharge = pcr.min(0.75, fraction_reserved_recharge)

# areal_groundwater_abstraction (unit: m/year)
#~ groundwater_abstraction = pcr.cover(pcr.readmap("/nfsarchive/edwin-emergency-backup-DO-NOT-DELETE/rapid/edwin/05min_runs_results/2015_04_27/non_natural_2015_04_27/global/analysis/avg_values_1990_to_2010/totalGroundwaterAbstraction_annuaTot_output_1990to2010.map"), 0.0)
groundwater_abstraction = pcr.scalar(0.0)
for year in range(start_year, end_year + 1, 1):
    date_input_in_string = str(year) + "-12-31"
    netcdf_file   = "/nfsarchive/edwin-emergency-backup-DO-NOT-DELETE/rapid/edwin/05min_runs_results/2015_04_27/non_natural_2015_04_27/global/netcdf/totalGroundwaterAbstraction_annuaTot_output_1981to2010.nc"
    variable_name = "total_groundwater_abstraction"
    groundwater_abstraction += vos.netcdf2PCRobjClone(ncFile = netcdf_file, varName = variable_name, dateInput = date_input_in_string,\
                                                      useDoy = None,
                                                      cloneMapFileName  = None,\
                                                      LatitudeLongitude = True,\
                                                      specificFillValue = None)
areal_groundwater_abstraction = pcr.cover(pcr.areatotal(groundwater_abstraction * cell_area, class_map)/pcr.areatotal(cell_area, class_map), 0.0)
Esempio n. 32
0
def complexreservoir(
    waterlevel,
    ReserVoirLocs,
    LinkedReserVoirLocs,
    ResArea,
    ResThreshold,
    ResStorFunc,
    ResOutflowFunc,
    sh,
    hq,
    res_b,
    res_e,
    inflow,
    precip,
    pet,
    ReservoirComplexAreas,
    JDOY,
    timestepsecs=86400,
):

    mv = -999.0

    inflow = pcr.ifthen(pcr.boolean(ReserVoirLocs), inflow)

    prec_av = pcr.ifthen(
        pcr.boolean(ReserVoirLocs), pcr.areaaverage(precip, ReservoirComplexAreas)
    )
    pet_av = pcr.ifthen(
        pcr.boolean(ReserVoirLocs), pcr.areaaverage(pet, ReservoirComplexAreas)
    )

    np_reslocs = pcr.pcr2numpy(ReserVoirLocs, 0.0)
    np_linkedreslocs = pcr.pcr2numpy(LinkedReserVoirLocs, 0.0)

    _outflow = []
    nr_loop = np.max([int(timestepsecs / 21600), 1])
    for n in range(0, nr_loop):
        np_waterlevel = pcr.pcr2numpy(waterlevel, np.nan)
        np_waterlevel_lower = np_waterlevel.copy()

        for val in np.unique(np_linkedreslocs):
            if val > 0:
                np_waterlevel_lower[np_linkedreslocs == val] = np_waterlevel[
                    np.where(np_reslocs == val)
                ]

        diff_wl = np_waterlevel - np_waterlevel_lower
        diff_wl[np.isnan(diff_wl)] = mv
        np_waterlevel_lower[np.isnan(np_waterlevel_lower)] = mv

        pcr_diff_wl = pcr.numpy2pcr(pcr.Scalar, diff_wl, mv)
        pcr_wl_lower = pcr.numpy2pcr(pcr.Scalar, np_waterlevel_lower, mv)

        storage_start = pcr.ifthenelse(
            ResStorFunc == 1,
            ResArea * waterlevel,
            lookupResFunc(ReserVoirLocs, waterlevel, sh, "0-1"),
        )

        outflow = pcr.ifthenelse(
            ResOutflowFunc == 1,
            lookupResRegMatr(ReserVoirLocs, waterlevel, hq, JDOY),
            pcr.ifthenelse(
                pcr_diff_wl >= 0,
                pcr.max(res_b * (waterlevel - ResThreshold) ** res_e, 0),
                pcr.min(-1 * res_b * (pcr_wl_lower - ResThreshold) ** res_e, 0),
            ),
        )

        np_outflow = pcr.pcr2numpy(outflow, np.nan)
        np_outflow_linked = np_reslocs * 0.0

        with np.errstate(invalid="ignore"):
            if np_outflow[np_outflow < 0] is not None:
                np_outflow_linked[
                    np.in1d(np_reslocs, np_linkedreslocs[np_outflow < 0]).reshape(
                        np_linkedreslocs.shape
                    )
                ] = np_outflow[np_outflow < 0]

        outflow_linked = pcr.numpy2pcr(pcr.Scalar, np_outflow_linked, 0.0)

        fl_nr_loop = float(nr_loop)
        storage = (
            storage_start
            + (inflow * timestepsecs / fl_nr_loop)
            + (prec_av / fl_nr_loop / 1000.0) * ResArea
            - (pet_av / fl_nr_loop / 1000.0) * ResArea
            - (pcr.cover(outflow, 0.0) * timestepsecs / fl_nr_loop)
            + (pcr.cover(outflow_linked, 0.0) * timestepsecs / fl_nr_loop)
        )

        waterlevel = pcr.ifthenelse(
            ResStorFunc == 1,
            waterlevel + (storage - storage_start) / ResArea,
            lookupResFunc(ReserVoirLocs, storage, sh, "1-0"),
        )

        np_outflow_nz = np_outflow * 0.0
        with np.errstate(invalid="ignore"):
            np_outflow_nz[np_outflow > 0] = np_outflow[np_outflow > 0]
        _outflow.append(np_outflow_nz)

    outflow_av_temp = np.average(_outflow, 0)
    outflow_av_temp[np.isnan(outflow_av_temp)] = mv
    outflow_av = pcr.numpy2pcr(pcr.Scalar, outflow_av_temp, mv)

    return waterlevel, outflow_av, prec_av, pet_av, storage
import pcraster as pcr
import netCDF4 as nc

# clone map
clone_map_file_name = "/projects/0/dfguu/data/hydroworld/PCRGLOBWB20/input5min/routing/lddsound_05min.map"
pcr.setclone(clone_map_file_name)

# aquifer thickness map:
aquifer_thickness_file_name = "/projects/0/dfguu/users/edwin/data/aquifer_properties/thickness_05min.map"
aquifer_thickness = pcr.readmap(aquifer_thickness_file_name)

# extent of confining layer
extent_of_confining_layer_file_name = "/home/edwin/data/inge_confining_layer_parameters/conflayers4.map"
confining_layer_extent = pcr.boolean(pcr.readmap(extent_of_confining_layer_file_name))

# thickness of confining layer = 10 percent from the first 250 m
confining_layer_thickness = pcr.ifthen(confining_layer_extent, pcr.min(250.0, aquifer_thickness)) * 0.10

# extrapolate
confining_layer_thickness = pcr.cover(confining_layer_thickness, pcr.windowaverage(pcr.cover(confining_layer_thickness, 0.0), 0.50))
confining_layer_thickness = pcr.cover(confining_layer_thickness, 0.0)
confining_layer_thickness_output_filename = "/home/edwin/data/inge_confining_layer_parameters/confining_layer_thickness_edwin.map"
pcr.report(confining_layer_thickness, confining_layer_thickness_output_filename)

# masking only to the landmask 
landmask_file_name = "/projects/0/dfguu/data/hydroworld/PCRGLOBWB20/input5min/routing/lddsound_05min.map"
landmask = pcr.defined(landmask_file_name)
confining_layer_thickness_masked_output_filename = "/home/edwin/data/inge_confining_layer_parameters/confining_layer_thickness_edwin.masked.map"
pcr.report(pcr.ifthen(landmask, confining_layer_thickness), confining_layer_thickness_masked_output_filename)
Esempio n. 34
0
    def getParameterFiles(
        self, currTimeStep, cellArea, ldd, initial_condition_dictionary=None
    ):

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        # cropping only in the landmask region:
        self.fracWat = pcr.ifthen(self.landmask, self.fracWat)
        self.waterBodyIds = pcr.ifthen(self.landmask, self.waterBodyIds)
        self.waterBodyOut = pcr.ifthen(self.landmask, self.waterBodyOut)
        self.waterBodyArea = pcr.ifthen(self.landmask, self.waterBodyArea)
        self.waterBodyTyp = pcr.ifthen(self.landmask, self.waterBodyTyp)
        self.waterBodyCap = pcr.ifthen(self.landmask, self.waterBodyCap)
        self.waterBodyStorage = pcr.ifthen(self.landmask, self.waterBodyStorage)
        self.avgInflow = pcr.ifthen(self.landmask, self.avgInflow)
        self.avgOutflow = pcr.ifthen(self.landmask, self.avgOutflow)
Esempio n. 35
0
    def __init__(self, iniItems,landmask,spinUp):
        object.__init__(self)
        
        self.cloneMap = iniItems.cloneMap
        self.tmpDir = iniItems.tmpDir
        self.inputDir = iniItems.globalOptions['inputDir']
        self.landmask = landmask

        # option to activate water balance check
        self.debugWaterBalance = True
        if iniItems.routingOptions['debugWaterBalance'] == "False":
            self.debugWaterBalance = False

        if iniItems.groundwaterOptions['groundwaterPropertiesNC'] == str(None):
            # assign the recession coefficient parameter(s)
            self.recessionCoeff = vos.readPCRmapClone(\
               iniItems.groundwaterOptions['recessionCoeff'],
               self.cloneMap,self.tmpDir,self.inputDir)
        else:       
            groundwaterPropertiesNC = vos.getFullPath(\
                                      iniItems.groundwaterOptions[\
                                         'groundwaterPropertiesNC'],
                                          self.inputDir)
            self.recessionCoeff = vos.netcdf2PCRobjCloneWithoutTime(\
                                  groundwaterPropertiesNC,'recessionCoeff',\
                                  cloneMapFileName = self.cloneMap)

        # groundwater recession coefficient (day-1)
        self.recessionCoeff = pcr.cover(self.recessionCoeff,0.00)       
        self.recessionCoeff = pcr.min(1.0000,self.recessionCoeff)       
        #
        if 'minRecessionCoeff' in iniItems.groundwaterOptions.keys():
            minRecessionCoeff = float(iniItems.groundwaterOptions['minRecessionCoeff'])
        else:
            minRecessionCoeff = 1.0e-4                                       # This is the minimum value used in Van Beek et al. (2011). 
        self.recessionCoeff = pcr.max(minRecessionCoeff,self.recessionCoeff)      
        
        if iniItems.groundwaterOptions['groundwaterPropertiesNC'] == str(None):
            # assign aquifer specific yield
            self.specificYield  = vos.readPCRmapClone(\
               iniItems.groundwaterOptions['specificYield'],
               self.cloneMap,self.tmpDir,self.inputDir)
        else:       
            self.specificYield = vos.netcdf2PCRobjCloneWithoutTime(\
                                 groundwaterPropertiesNC,'specificYield',\
                                 cloneMapFileName = self.cloneMap)

        self.specificYield  = pcr.cover(self.specificYield,0.0)       
        self.specificYield  = pcr.max(0.010,self.specificYield)         # TODO: TO BE CHECKED: The resample process of specificYield     
        self.specificYield  = pcr.min(1.000,self.specificYield)       

        if iniItems.groundwaterOptions['groundwaterPropertiesNC'] == str(None):
            # assign aquifer saturated conductivity
            self.kSatAquifer = vos.readPCRmapClone(\
               iniItems.groundwaterOptions['kSatAquifer'],
               self.cloneMap,self.tmpDir,self.inputDir)
        else:       
            self.kSatAquifer = vos.netcdf2PCRobjCloneWithoutTime(\
                               groundwaterPropertiesNC,'kSatAquifer',\
                               cloneMapFileName = self.cloneMap)

        self.kSatAquifer = pcr.cover(self.kSatAquifer,0.0)       
        self.kSatAquifer = pcr.max(0.010,self.kSatAquifer)       

        # limitAbstraction options
        self.limitAbstraction = False
        if iniItems.landSurfaceOptions['limitAbstraction'] == "True": self.limitAbstraction = True
        

        # option for limitting regional groundwater abstractions
        if iniItems.groundwaterOptions['pumpingCapacityNC'] != "None":

            logger.info('Limit for annual regional groundwater abstraction is used.')
            self.limitRegionalAnnualGroundwaterAbstraction = True
            self.pumpingCapacityNC = vos.getFullPath(\
                                     iniItems.groundwaterOptions['pumpingCapacityNC'],self.inputDir,False)
        else:
            logger.warning('NO LIMIT for regional groundwater (annual) pumping. It may result too high groundwater abstraction.')
            self.limitRegionalAnnualGroundwaterAbstraction = False
        
        # option for limitting fossil groundwater abstractions: 
        self.limitFossilGroundwaterAbstraction = False
        #
        # estimate of fossil groundwater capacity:
        if iniItems.groundwaterOptions['limitFossilGroundWaterAbstraction'] == "True": 

            logger.info('Fossil groundwater abstractions are allowed with LIMIT.')
            self.limitFossilGroundwaterAbstraction = True

            # estimate of thickness (unit: m) of accesible groundwater: shallow and deep 
            totalGroundwaterThickness = vos.readPCRmapClone(\
                                        iniItems.groundwaterOptions['estimateOfTotalGroundwaterThickness'],
                                        self.cloneMap,self.tmpDir,self.inputDir)
            # extrapolation 
            totalGroundwaterThickness = pcr.cover(totalGroundwaterThickness,
                                        pcr.windowaverage(totalGroundwaterThickness, 1.0))
            totalGroundwaterThickness = pcr.cover(totalGroundwaterThickness,
                                        pcr.windowaverage(totalGroundwaterThickness, 1.5))
            totalGroundwaterThickness = pcr.cover(totalGroundwaterThickness,
                                        pcr.windowaverage(totalGroundwaterThickness, 2.5))
            totalGroundwaterThickness = pcr.cover(totalGroundwaterThickness,
                                        pcr.windowaverage(totalGroundwaterThickness, 5.0))
            #
            totalGroundwaterThickness = pcr.cover(totalGroundwaterThickness, 0.0)
            #
            # set minimum thickness
            minimumThickness = pcr.scalar(float(\
                               iniItems.groundwaterOptions['minimumTotalGroundwaterThickness']))
            totalGroundwaterThickness = pcr.max(minimumThickness, totalGroundwaterThickness)
            #            
            # estimate of capacity (unit: m) of renewable groundwater (shallow)
            storGroundwaterCap =  pcr.cover(
                                  vos.readPCRmapClone(\
                                  iniItems.groundwaterOptions['estimateOfRenewableGroundwaterCapacity'],
                                  self.cloneMap,self.tmpDir,self.inputDir), 0.0)
            #
            # fossil groundwater capacity (unit: m)
            self.fossilWaterCap = pcr.ifthen(self.landmask,\
                                  pcr.max(0.0,\
                                  totalGroundwaterThickness*self.specificYield - storGroundwaterCap))

        # zones at which groundwater allocations are determined
        self.usingAllocSegments = False
        if iniItems.landSurfaceOptions['allocationSegmentsForGroundSurfaceWater']  != "None": self.usingAllocSegments = True
        
        # incorporating groundwater distribution network:
        if self.usingAllocSegments:

            self.allocSegments = vos.readPCRmapClone(\
             iniItems.landSurfaceOptions['allocationSegmentsForGroundSurfaceWater'],
             self.cloneMap,self.tmpDir,self.inputDir,isLddMap=False,cover=None,isNomMap=True)
            self.allocSegments = pcr.ifthen(self.landmask, self.allocSegments)

            cellArea = vos.readPCRmapClone(\
              iniItems.routingOptions['cellAreaMap'],
              self.cloneMap,self.tmpDir,self.inputDir)
            cellArea = pcr.ifthen(self.landmask, cellArea)              # TODO: integrate this one with the one coming from the routing module

            self.segmentArea = pcr.areatotal(pcr.cover(cellArea, 0.0), self.allocSegments)
            self.segmentArea = pcr.ifthen(self.landmask, self.segmentArea)
        
        # get initial conditions
        self.getICs(iniItems,spinUp)

        # initiate old style reporting                                  # TODO: remove this!
        self.initiate_old_style_groundwater_reporting(iniItems)
    def __init__(self, iniItems, landmask):
        object.__init__(self)

        # cloneMap, temporary directory, absolute path for input directory, landmask
        self.cloneMap = iniItems.cloneMap
        self.tmpDir = iniItems.tmpDir
        self.inputDir = iniItems.globalOptions['inputDir']
        self.landmask = landmask

        # configuration from the ini file
        self.iniItems = iniItems

        # topography properties: read several variables from the netcdf file
        for var in ['dem_minimum','dem_maximum','dem_average','dem_standard_deviation',\
                    'slopeLength','orographyBeta','tanslope',\
                    'dzRel0000','dzRel0001','dzRel0005',\
                    'dzRel0010','dzRel0020','dzRel0030','dzRel0040','dzRel0050',\
                    'dzRel0060','dzRel0070','dzRel0080','dzRel0090','dzRel0100']:
            vars(self)[var] = vos.netcdf2PCRobjCloneWithoutTime(self.iniItems.modflowParameterOptions['topographyNC'], \
                                                                var, self.cloneMap)
            vars(self)[var] = pcr.cover(vars(self)[var], 0.0)

        # channel properties: read several variables from the netcdf file
        for var in [
                'lddMap', 'cellAreaMap', 'gradient', 'bankfull_width',
                'bankfull_depth', 'dem_floodplain', 'dem_riverbed'
        ]:
            vars(self)[var] = vos.netcdf2PCRobjCloneWithoutTime(self.iniItems.modflowParameterOptions['channelNC'], \
                                                                var, self.cloneMap)
            vars(self)[var] = pcr.cover(vars(self)[var], 0.0)

        # minimum channel width
        minimum_channel_width = 0.1
        self.bankfull_width = pcr.max(minimum_channel_width,
                                      self.bankfull_width)

        #~ # cell fraction if channel water reaching the flood plan # NOT USED
        #~ self.flood_plain_fraction = self.return_innundation_fraction(pcr.max(0.0, self.dem_floodplain - self.dem_minimum))

        # coefficient of Manning
        self.manningsN = vos.readPCRmapClone(self.iniItems.modflowParameterOptions['manningsN'],\
                                             self.cloneMap,self.tmpDir,self.inputDir)

        # minimum channel gradient
        minGradient = 0.00005
        self.gradient = pcr.max(minGradient,
                                pcr.cover(self.gradient, minGradient))

        # correcting lddMap
        self.lddMap = pcr.ifthen(pcr.scalar(self.lddMap) > 0.0, self.lddMap)
        self.lddMap = pcr.lddrepair(pcr.ldd(self.lddMap))

        # channelLength = approximation of channel length (unit: m)  # This is approximated by cell diagonal.
        cellSizeInArcMin = np.round(pcr.clone().cellSize() * 60.)
        verticalSizeInMeter = cellSizeInArcMin * 1852.
        self.channelLength  = ((self.cellAreaMap/verticalSizeInMeter)**(2)+\
                                                (verticalSizeInMeter)**(2))**(0.5)

        # option for lakes and reservoir
        self.onlyNaturalWaterBodies = False
        if self.iniItems.modflowParameterOptions[
                'onlyNaturalWaterBodies'] == "True":
            self.onlyNaturalWaterBodies = True

        # groundwater linear recession coefficient (day-1) ; the linear reservoir concept is still being used to represent fast response flow
        #                                                                                                                  particularly from karstic aquifer in mountainous regions
        self.recessionCoeff = vos.netcdf2PCRobjCloneWithoutTime(self.iniItems.modflowParameterOptions['groundwaterPropertiesNC'],\
                                                                 'recessionCoeff', self.cloneMap)
        self.recessionCoeff = pcr.cover(self.recessionCoeff, 0.00)
        self.recessionCoeff = pcr.min(1.0000, self.recessionCoeff)
        #
        if 'minRecessionCoeff' in iniItems.modflowParameterOptions.keys():
            minRecessionCoeff = float(
                iniItems.modflowParameterOptions['minRecessionCoeff'])
        else:
            minRecessionCoeff = 1.0e-4  # This is the minimum value used in Van Beek et al. (2011).
        self.recessionCoeff = pcr.max(minRecessionCoeff, self.recessionCoeff)

        # aquifer saturated conductivity (m/day)
        self.kSatAquifer = vos.netcdf2PCRobjCloneWithoutTime(self.iniItems.modflowParameterOptions['groundwaterPropertiesNC'],\
                                                             'kSatAquifer', self.cloneMap)
        self.kSatAquifer = pcr.cover(self.kSatAquifer,
                                     pcr.mapmaximum(self.kSatAquifer))
        self.kSatAquifer = pcr.max(0.010, self.kSatAquifer)

        self.kSatAquifer *= 0.001

        # aquifer specific yield (dimensionless)
        self.specificYield = vos.netcdf2PCRobjCloneWithoutTime(self.iniItems.modflowParameterOptions['groundwaterPropertiesNC'],\
                                                               'specificYield', self.cloneMap)
        self.specificYield = pcr.cover(self.specificYield,
                                       pcr.mapmaximum(self.specificYield))
        self.specificYield = pcr.max(
            0.010, self.specificYield
        )  # TODO: TO BE CHECKED: The resample process of specificYield
        self.specificYield = pcr.min(1.000, self.specificYield)

        # estimate of thickness (unit: m) of accesible groundwater
        totalGroundwaterThickness = vos.netcdf2PCRobjCloneWithoutTime(self.iniItems.modflowParameterOptions['estimateOfTotalGroundwaterThicknessNC'],\
                                    'thickness', self.cloneMap)
        # extrapolation
        totalGroundwaterThickness = pcr.cover(totalGroundwaterThickness,\
                                    pcr.windowaverage(totalGroundwaterThickness, 1.0))
        totalGroundwaterThickness = pcr.cover(totalGroundwaterThickness,\
                                    pcr.windowaverage(totalGroundwaterThickness, 1.5))
        totalGroundwaterThickness = pcr.cover(totalGroundwaterThickness, 0.0)
        #
        # set minimum thickness
        minimumThickness = pcr.scalar(float(\
                           self.iniItems.modflowParameterOptions['minimumTotalGroundwaterThickness']))
        totalGroundwaterThickness = pcr.max(minimumThickness,
                                            totalGroundwaterThickness)
        #
        # set maximum thickness: 250 m.
        maximumThickness = 250.
        self.totalGroundwaterThickness = pcr.min(maximumThickness,
                                                 totalGroundwaterThickness)

        # river bed resistance (unit: day)
        self.bed_resistance = 1.0

        # option to ignore capillary rise
        self.ignoreCapRise = True
        if self.iniItems.modflowParameterOptions['ignoreCapRise'] == "False":
            self.ignoreCapRise = False

        # initiate old style reporting                                  # TODO: remove this!
        self.initiate_old_style_groundwater_reporting(iniItems)
Esempio n. 37
0
    def update(self,landSurface,routing,currTimeStep):

        logger.info("Updating groundwater")
        
        if self.debugWaterBalance:
            preStorGroundwater       = self.storGroundwater
            preStorGroundwaterFossil = self.storGroundwaterFossil
                
        # get riverbed infiltration from the previous time step (from routing)
        self.surfaceWaterInf  = routing.riverbedExchange/\
                                routing.cellArea               # unit: m
        self.storGroundwater += self.surfaceWaterInf

        # get net recharge (percolation-capRise) and update storage:
        self.storGroundwater  = pcr.max(0.,\
                                self.storGroundwater + landSurface.gwRecharge)         
                        
        # non fossil groundwater abstraction
        self.nonFossilGroundwaterAbs = landSurface.nonFossilGroundwaterAbs
        self.storGroundwater         = pcr.max(0.,\
                                       self.storGroundwater - self.nonFossilGroundwaterAbs) 
        
        # baseflow
        self.baseflow         = pcr.max(0.,\
                                pcr.min(self.storGroundwater,\
                                        self.recessionCoeff* \
                                        self.storGroundwater))
        self.storGroundwater  = pcr.max(0.,\
                                self.storGroundwater - self.baseflow)
        # PS: baseflow must be calculated at the end (to ensure the availability of storGroundwater to support nonFossilGroundwaterAbs)
        
        # fossil groundwater abstraction:
        self.fossilGroundwaterAbstr = landSurface.fossilGroundwaterAbstr
        self.storGroundwaterFossil -= self.fossilGroundwaterAbstr

        # fossil groundwater cannot be negative if limitFossilGroundwaterAbstraction is used
        if self.limitFossilGroundwaterAbstraction:
            self.storGroundwaterFossil = pcr.max(0.0, self.storGroundwaterFossil)

        # groundwater allocation (Note: This is done in the landSurface module)
        self.allocNonFossilGroundwater = landSurface.allocNonFossilGroundwater
        self.fossilGroundwaterAlloc    = landSurface.fossilGroundwaterAlloc
        
        # Note: The following variable (unmetDemand) is a bad name and used in the past. 
        #       Its definition is actually as follows: (the amount of demand that is satisfied/allocated from fossil groundwater) 
        self.unmetDemand = self.fossilGroundwaterAlloc

        # calculate the average total groundwater abstraction (m/day) from the last 365 days:
        totalAbstraction    = self.fossilGroundwaterAbstr + self.nonFossilGroundwaterAbs
        deltaAbstraction    = totalAbstraction - self.avgAbstraction  
        self.avgAbstraction = self.avgAbstraction +\
                                 deltaAbstraction/\
                              pcr.min(365., pcr.max(1.0, routing.timestepsToAvgDischarge))
        self.avgAbstraction = pcr.max(0.0, self.avgAbstraction)                                    

        # calculate the average non fossil groundwater allocation (m/day) 
        # - from the last 365 days:
        deltaAllocation     = self.allocNonFossilGroundwater  - self.avgNonFossilAllocation  
        self.avgNonFossilAllocation  = self.avgNonFossilAllocation +\
                                 deltaAllocation/\
                              pcr.min(365., pcr.max(1.0, routing.timestepsToAvgDischarge))
        self.avgNonFossilAllocation = pcr.max(0.0, self.avgNonFossilAllocation)
        # - from the last 7 days:
        deltaAllocationShort    = self.allocNonFossilGroundwater - self.avgNonFossilAllocationShort  
        self.avgNonFossilAllocationShort = self.avgNonFossilAllocationShort +\
                                     deltaAllocationShort/\
                                  pcr.min(7., pcr.max(1.0, routing.timestepsToAvgDischarge))
        self.avgNonFossilAllocationShort = pcr.max(0.0, self.avgNonFossilAllocationShort)                                    

        # calculate the average total (fossil + non fossil) groundwater allocation (m/day) 
        totalGroundwaterAllocation = self.allocNonFossilGroundwater + self.fossilGroundwaterAlloc
        # - from the last 365 days:
        deltaAllocation            = totalGroundwaterAllocation - self.avgAllocation 
        self.avgAllocation         = self.avgAllocation +\
                                        deltaAllocation/\
                                        pcr.min(365., pcr.max(1.0, routing.timestepsToAvgDischarge))
        self.avgAllocation         = pcr.max(0.0, self.avgAllocation)
        # - from the last 7 days:
        deltaAllocationShort       = totalGroundwaterAllocation - self.avgAllocationShort  
        self.avgAllocationShort    = self.avgAllocationShort +\
                                        deltaAllocationShort/\
                                        pcr.min(7., pcr.max(1.0, routing.timestepsToAvgDischarge))
        self.avgAllocationShort    = pcr.max(0.0, self.avgAllocationShort)

        if self.debugWaterBalance:
            vos.waterBalanceCheck([self.surfaceWaterInf,\
                                   landSurface.gwRecharge],\
                                  [self.baseflow,\
                                   self.nonFossilGroundwaterAbs],\
                                  [  preStorGroundwater],\
                                  [self.storGroundwater],\
                                       'storGroundwater',\
                                   True,\
                                   currTimeStep.fulldate,threshold=1e-4)

        if self.debugWaterBalance:
            vos.waterBalanceCheck([pcr.scalar(0.0)],\
                                  [self.fossilGroundwaterAbstr],\
                                  [  preStorGroundwaterFossil],\
                                  [self.storGroundwaterFossil],\
                                       'storGroundwaterFossil',\
                                   True,\
                                   currTimeStep.fulldate,threshold=1e-3)

        if self.debugWaterBalance:
            vos.waterBalanceCheck([landSurface.desalinationAllocation,\
                                   self.unmetDemand, \
                                   self.allocNonFossilGroundwater, \
                                   landSurface.allocSurfaceWaterAbstract],\
                                  [landSurface.totalPotentialGrossDemand],\
                                  [pcr.scalar(0.)],\
                                  [pcr.scalar(0.)],\
                                  'demand allocation (desalination, surface water, groundwater & unmetDemand. Error here may be due to rounding error.',\
                                   True,\
                                   currTimeStep.fulldate,threshold=1e-3)

        # old-style reporting                             
        self.old_style_groundwater_reporting(currTimeStep)              # TODO: remove this one
    def adusting_parameters(self, configuration, system_argument):

        # global pre-multipliers given in the argument:
        if len(system_argument) > 4:

            logger.info(
                "Adjusting some model parameters based on given values in the system argument."
            )

            # pre-multipliers for minSoilDepthFrac, kSat, recessionCoeff, storCap and degreeDayFactor
            multiplier_for_minSoilDepthFrac = float(
                system_argument[4]
            )  # linear scale                                        # Note that this one does NOT work for the changing WMIN or Joyce land cover options.
            multiplier_for_kSat = float(system_argument[5])  # log scale
            multiplier_for_recessionCoeff = float(
                system_argument[6])  # log scale
            multiplier_for_storCap = float(system_argument[7])  # linear scale
            multiplier_for_degreeDayFactor = float(
                system_argument[8])  # linear scale

            # pre-multiplier for the reference potential ET
            self.multiplier_for_refPotET = float(
                system_argument[9])  # linear scale

        # it is also possible to define prefactors via the ini/configuration file:
        # - this will be overwrite any previous given pre-multipliers
        if 'prefactorOptions' in configuration.allSections:

            logger.info(
                "Adjusting some model parameters based on given values in the ini/configuration file."
            )

            self.multiplier_for_refPotET = float(
                configuration.
                prefactorOptions['linear_multiplier_for_refPotET']
            )  # linear scale  # Note that this one does NOT work for the changing WMIN or Joyce land cover options.
            multiplier_for_degreeDayFactor = float(
                configuration.prefactorOptions[
                    'linear_multiplier_for_degreeDayFactor'])  # linear scale
            multiplier_for_minSoilDepthFrac = float(
                configuration.prefactorOptions[
                    'linear_multiplier_for_minSoilDepthFrac'])  # linear scale
            multiplier_for_kSat = float(
                configuration.prefactorOptions['log_10_multiplier_for_kSat']
            )  # log scale
            multiplier_for_storCap = float(
                configuration.prefactorOptions['linear_multiplier_for_storCap']
            )  # linear scale
            multiplier_for_recessionCoeff = float(
                configuration.prefactorOptions[
                    'log_10_multiplier_for_recessionCoeff'])  # log scale

        # saving global pre-multipliers to the log file:
        msg = "\n"
        msg += "\n"
        msg += "Multiplier values used: " + "\n"
        msg += "For minSoilDepthFrac           : " + str(
            multiplier_for_minSoilDepthFrac) + "\n"
        msg += "For kSat (log-scale)           : " + str(
            multiplier_for_kSat) + "\n"
        msg += "For recessionCoeff (log-scale) : " + str(
            multiplier_for_recessionCoeff) + "\n"
        msg += "For storCap                    : " + str(
            multiplier_for_storCap) + "\n"
        msg += "For degreeDayFactor            : " + str(
            multiplier_for_degreeDayFactor) + "\n"
        msg += "For refPotET                   : " + str(
            self.multiplier_for_refPotET) + "\n"
        logger.info(msg)
        # - also to a txt file
        f = open(
            "multiplier.txt", "w"
        )  # this will be stored in the "map" folder of the 'outputDir' (as we set the current working directory to this "map" folder, see configuration.py)
        f.write(msg)
        f.close()

        # set parameter "recessionCoeff" based on the given pre-multiplier
        # - also saving the adjusted parameter maps to pcraster files
        # - these will be stored in the "map" folder of the 'outputDir' (as we set the current working directory to this "map" folder, see configuration.py)
        # "recessionCoeff"
        # minimum value is zero and using log-scale
        self.model.groundwater.recessionCoeff = pcr.max(
            0.0, (10**(multiplier_for_recessionCoeff)) *
            self.model.groundwater.recessionCoeff)
        self.model.groundwater.recessionCoeff = pcr.min(
            1.0, self.model.groundwater.recessionCoeff)
        # report the map
        pcr.report(self.model.groundwater.recessionCoeff, "recessionCoeff.map")

        # set parameters "kSat", "storCap", "minSoilDepthFrac", and "degreeDayFactor" based on the given pre-multipliers
        for coverType in self.model.landSurface.coverTypes:

            # "degreeDayFactor"
            self.model.landSurface.landCoverObj[coverType].degreeDayFactor  = pcr.max(0.0, multiplier_for_degreeDayFactor  *\
                                                           self.model.landSurface.landCoverObj[coverType].degreeDayFactor)
            # report the map
            pcraster_filename = "degreeDayFactor" + "_" + coverType + ".map"
            pcr.report(
                self.model.landSurface.landCoverObj[coverType].degreeDayFactor,
                pcraster_filename)

            # "kSat" and "storCap" for 2 layer model
            if self.model.landSurface.numberOfSoilLayers == 2:

                # "kSat"
                # minimum value is zero and using-log-scale
                self.model.landSurface.landCoverObj[coverType].parameters.kSatUpp = \
                       pcr.max(0.0, (10**(multiplier_for_kSat)) * self.model.landSurface.landCoverObj[coverType].parameters.kSatUpp)
                self.model.landSurface.landCoverObj[coverType].parameters.kSatLow = \
                       pcr.max(0.0, (10**(multiplier_for_kSat)) * self.model.landSurface.landCoverObj[coverType].parameters.kSatLow)
                # report the maps
                pcraster_filename = "kSatUpp" + "_" + coverType + ".map"
                pcr.report(
                    self.model.landSurface.landCoverObj[coverType].parameters.
                    kSatUpp, pcraster_filename)
                pcraster_filename = "kSatLow" + "_" + coverType + ".map"
                pcr.report(
                    self.model.landSurface.landCoverObj[coverType].parameters.
                    kSatLow, pcraster_filename)

                # "storCap"
                # minimum value is zero
                self.model.landSurface.landCoverObj[coverType].parameters.storCapUpp = pcr.max(0.0, multiplier_for_storCap*\
                                                                                                    self.model.landSurface.landCoverObj[coverType].parameters.storCapUpp)
                self.model.landSurface.landCoverObj[coverType].parameters.storCapLow = pcr.max(0.0, multiplier_for_storCap*\
                                                                                                    self.model.landSurface.landCoverObj[coverType].parameters.storCapLow)
                # report the maps
                pcraster_filename = "storCapUpp" + "_" + coverType + ".map"
                pcr.report(
                    self.model.landSurface.landCoverObj[coverType].parameters.
                    storCapUpp, pcraster_filename)
                pcraster_filename = "storCapLow" + "_" + coverType + ".map"
                pcr.report(
                    self.model.landSurface.landCoverObj[coverType].parameters.
                    storCapLow, pcraster_filename)

            # "kSat" and "storCap" for 3 layer model
            if self.model.landSurface.numberOfSoilLayers == 3:

                # "kSat"
                # minimum value is zero and using-log-scale
                self.model.landSurface.landCoverObj[coverType].parameters.kSatUpp000005 = \
                       pcr.max(0.0, (10**(multiplier_for_kSat)) * self.model.landSurface.landCoverObj[coverType].parameters.kSatUpp000005)
                self.model.landSurface.landCoverObj[coverType].parameters.kSatUpp005030 = \
                       pcr.max(0.0, (10**(multiplier_for_kSat)) * self.model.landSurface.landCoverObj[coverType].parameters.kSatUpp005030)
                self.model.landSurface.landCoverObj[coverType].parameters.kSatLow030150 = \
                       pcr.max(0.0, (10**(multiplier_for_kSat)) * self.model.landSurface.landCoverObj[coverType].parameters.kSatLow030150)
                # report the maps
                pcraster_filename = "kSatUpp000005" + "_" + coverType + ".map"
                pcr.report(
                    self.model.landSurface.landCoverObj[coverType].parameters.
                    kSatUpp000005, pcraster_filename)
                pcraster_filename = "kSatUpp005030" + "_" + coverType + ".map"
                pcr.report(
                    self.model.landSurface.landCoverObj[coverType].parameters.
                    kSatUpp005030, pcraster_filename)
                pcraster_filename = "kSatLow030150" + "_" + coverType + ".map"
                pcr.report(
                    self.model.landSurface.landCoverObj[coverType].parameters.
                    kSatLow030150, pcraster_filename)

                # "storCap"
                # minimum value is zero
                self.model.landSurface.landCoverObj[coverType].parameters.storCapUpp000005 = pcr.max(0.0, multiplier_for_storCap*\
                                                                                                          self.model.landSurface.landCoverObj[coverType].parameters.storCapUpp000005)
                self.model.landSurface.landCoverObj[coverType].parameters.storCapUpp005030 = pcr.max(0.0, multiplier_for_storCap*\
                                                                                                          self.model.landSurface.landCoverObj[coverType].parameters.storCapUpp005030)
                self.model.landSurface.landCoverObj[coverType].parameters.storCapLow030150 = pcr.max(0.0, multiplier_for_storCap*\
                                                                                                          self.model.landSurface.landCoverObj[coverType].parameters.storCapLow030150)
                # report the maps
                pcraster_filename = "storCapUpp000005" + "_" + coverType + ".map"
                pcr.report(
                    self.model.landSurface.landCoverObj[coverType].parameters.
                    storCapUpp000005, pcraster_filename)
                pcraster_filename = "storCapUpp005030" + "_" + coverType + ".map"
                pcr.report(
                    self.model.landSurface.landCoverObj[coverType].parameters.
                    storCapUpp005030, pcraster_filename)
                pcraster_filename = "storCapLow030150" + "_" + coverType + ".map"
                pcr.report(
                    self.model.landSurface.landCoverObj[coverType].parameters.
                    storCapLow030150, pcraster_filename)

# re-calculate rootZoneWaterStorageCap as the consequence of the modification of "storCap"
# This is WMAX in the oldcalc script.
            if self.model.landSurface.numberOfSoilLayers == 2:
                self.model.landSurface.landCoverObj[coverType].parameters.rootZoneWaterStorageCap = self.model.landSurface.landCoverObj[coverType].parameters.storCapUpp +\
                                                                                                    self.model.landSurface.landCoverObj[coverType].parameters.storCapLow
            if self.model.landSurface.numberOfSoilLayers == 3:
                self.model.landSurface.landCoverObj[coverType].parameters.rootZoneWaterStorageCap = self.model.landSurface.landCoverObj[coverType].parameters.storCapUpp000005 +\
                                                                                                    self.model.landSurface.landCoverObj[coverType].parameters.storCapUpp005030 +\
                         self.model.landSurface.landCoverObj[coverType].parameters.storCapLow030150

# report the map
            pcraster_filename = "rootZoneWaterStorageCap" + "_" + coverType + ".map"
            pcr.report(
                self.model.landSurface.landCoverObj[coverType].parameters.
                rootZoneWaterStorageCap, pcraster_filename)

            # "minSoilDepthFrac"
            if multiplier_for_minSoilDepthFrac != 1.0:

                # minimum value is zero
                self.model.landSurface.landCoverObj[coverType].minSoilDepthFrac = pcr.max(0.0, multiplier_for_minSoilDepthFrac*\
                                                               self.model.landSurface.landCoverObj[coverType].minSoilDepthFrac)
                # for minSoilDepthFrac - values will be limited by maxSoilDepthFrac
                self.model.landSurface.landCoverObj[coverType].minSoilDepthFrac = pcr.min(\
                                                               self.model.landSurface.landCoverObj[coverType].minSoilDepthFrac,\
                                                               self.model.landSurface.landCoverObj[coverType].maxSoilDepthFrac)
                # maximum value is 1.0
                self.model.landSurface.landCoverObj[
                    coverType].minSoilDepthFrac = pcr.min(
                        1.0, self.model.landSurface.landCoverObj[coverType].
                        minSoilDepthFrac)
                # report the map
                pcraster_filename = "minSoilDepthFrac" + "_" + coverType + ".map"
                pcr.report(
                    self.model.landSurface.landCoverObj[coverType].
                    minSoilDepthFrac, pcraster_filename)

                # re-calculate arnoBeta (as the consequence of the modification of minSoilDepthFrac)
                self.model.landSurface.landCoverObj[coverType].arnoBeta = pcr.max(0.001,\
                     (self.model.landSurface.landCoverObj[coverType].maxSoilDepthFrac-1.)/(1.-self.model.landSurface.landCoverObj[coverType].minSoilDepthFrac)+\
                                               self.model.landSurface.landCoverObj[coverType].parameters.orographyBeta-0.01)
                self.model.landSurface.landCoverObj[coverType].arnoBeta = pcr.cover(pcr.max(0.001,\
                      self.model.landSurface.landCoverObj[coverType].arnoBeta), 0.001)
                # report the map
                pcraster_filename = "arnoBeta" + "_" + coverType + ".map"
                pcr.report(
                    self.model.landSurface.landCoverObj[coverType].arnoBeta,
                    pcraster_filename)

                # re-calculate rootZoneWaterStorageMin (as the consequence of the modification of minSoilDepthFrac)
                # This is WMIN in the oldcalc script.
                # WMIN (unit: m): minimum local soil water capacity within the grid-cell
                self.model.landSurface.landCoverObj[coverType].rootZoneWaterStorageMin = self.model.landSurface.landCoverObj[coverType].minSoilDepthFrac *\
                                                                                         self.model.landSurface.landCoverObj[coverType].parameters.rootZoneWaterStorageCap
                # report the map
                pcraster_filename = "rootZoneWaterStorageMin" + "_" + coverType + ".map"
                pcr.report(
                    self.model.landSurface.landCoverObj[coverType].
                    rootZoneWaterStorageMin, pcraster_filename)

                # re-calculate rootZoneWaterStorageRange (as the consequence of the modification of rootZoneWaterStorageRange and minSoilDepthFrac)
                # WMAX - WMIN (unit: m)
                self.model.landSurface.landCoverObj[coverType].rootZoneWaterStorageRange = self.model.landSurface.landCoverObj[coverType].parameters.rootZoneWaterStorageCap -\
                                                                                           self.model.landSurface.landCoverObj[coverType].rootZoneWaterStorageMin
                # report the map
                pcraster_filename = "rootZoneWaterStorageRange" + "_" + coverType + ".map"
                pcr.report(
                    self.model.landSurface.landCoverObj[coverType].
                    rootZoneWaterStorageRange, pcraster_filename)
Esempio n. 39
0
def simplereservoir(
    storage,
    inflow,
    ResArea,
    maxstorage,
    target_perc_full,
    maximum_Q,
    demand,
    minimum_full_perc,
    ReserVoirLocs,
    precip,
    pet,
    ReservoirSimpleAreas,
    timestepsecs=86400,
):
    """

    :param storage: initial storage m^3
    :param inflow: inflow m^3/s
    :param maxstorage: maximum storage (above which water is spilled) m^3
    :param target_perc_full: target fraction full (of max storage) -
    :param maximum_Q: maximum Q to release m^3/s if below spillway
    :param demand: water demand (all combined) m^3/s
    :param minimum_full_perc: target minimum full fraction (of max storage) -
    :param ReserVoirLocs: map with reservoir locations
    :param timestepsecs: timestep of the model in seconds (default = 86400)
    :return: storage (m^3), outflow (m^3/s), PercentageFull (0-1), Release (m^3/sec)
    """

    inflow = pcr.ifthen(pcr.boolean(ReserVoirLocs), inflow)

    prec_av = pcr.cover(
        pcr.ifthen(
            pcr.boolean(ReserVoirLocs), pcr.areaaverage(precip, ReservoirSimpleAreas)
        ),
        pcr.scalar(0.0),
    )
    pet_av = pcr.cover(
        pcr.ifthen(
            pcr.boolean(ReserVoirLocs), pcr.areaaverage(pet, ReservoirSimpleAreas)
        ),
        pcr.scalar(0.0),
    )

    oldstorage = storage
    storage = (
        storage
        + (inflow * timestepsecs)
        + (prec_av / 1000.0) * ResArea
        - (pet_av / 1000.0) * ResArea
    )

    percfull = ((storage + oldstorage) * 0.5) / maxstorage
    # first determine minimum (environmental) flow using a simple sigmoid curve to scale for target level
    fac = sCurve(percfull, a=minimum_full_perc, c=30.0)
    demandRelease = pcr.min(fac * demand * timestepsecs, storage)
    storage = storage - demandRelease

    # Re-determine percfull
    percfull = ((storage + oldstorage) * 0.5) / maxstorage

    wantrel = pcr.max(0.0, storage - (maxstorage * target_perc_full))
    # Assume extra maximum Q if spilling
    overflowQ = (percfull - 1.0) * (storage - maxstorage)
    torelease = pcr.min(wantrel, overflowQ + maximum_Q * timestepsecs)
    storage = storage - torelease
    outflow = (torelease + demandRelease) / timestepsecs
    percfull = storage / maxstorage

    return storage, outflow, percfull, prec_av, pet_av, demandRelease / timestepsecs
Esempio n. 40
0
    def getReservoirOutflow(
        self, avgChannelDischarge, length_of_time_step, downstreamDemand
    ):

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

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

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

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

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

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

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

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

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

        resvOutflow = pcr.ifthen(pcr.scalar(self.waterBodyIds) > 0.0, resvOutflow)
        resvOutflow = pcr.ifthen(pcr.scalar(self.waterBodyTyp) == 2, resvOutflow)
        return resvOutflow  # unit: m3
Esempio n. 41
0
    def __init__(self, iniItems,landmask,spinUp):
        object.__init__(self)
        
        self.cloneMap = iniItems.cloneMap
        self.tmpDir = iniItems.tmpDir
        self.inputDir = iniItems.globalOptions['inputDir']
        self.landmask = landmask

        # option to activate water balance check
        self.debugWaterBalance = True
        if iniItems.routingOptions['debugWaterBalance'] == "False":
            self.debugWaterBalance = False

        if iniItems.groundwaterOptions['groundwaterPropertiesNC'] == str(None):
            # assign the recession coefficient parameter(s)
            self.recessionCoeff = vos.readPCRmapClone(\
               iniItems.groundwaterOptions['recessionCoeff'],
               self.cloneMap,self.tmpDir,self.inputDir)
        else:       
            groundwaterPropertiesNC = vos.getFullPath(\
                                      iniItems.groundwaterOptions[\
                                         'groundwaterPropertiesNC'],
                                          self.inputDir)
            self.recessionCoeff = vos.netcdf2PCRobjCloneWithoutTime(\
                                  groundwaterPropertiesNC,'recessionCoeff',\
                                  cloneMapFileName = self.cloneMap)

        # groundwater recession coefficient (day-1_
        self.recessionCoeff = pcr.cover(self.recessionCoeff,0.00)       
        self.recessionCoeff = pcr.min(1.0000,self.recessionCoeff)       
        #
        if 'minRecessionCoeff' in iniItems.groundwaterOptions.keys():
            minRecessionCoeff = float(iniItems.groundwaterOptions['minRecessionCoeff'])
        else:
            minRecessionCoeff = 1.0e-4                                       # This is the minimum value used in Van Beek et al. (2011). 
        self.recessionCoeff = pcr.max(minRecessionCoeff,self.recessionCoeff)      
        
        if iniItems.groundwaterOptions['groundwaterPropertiesNC'] == str(None):
            # assign aquifer specific yield
            self.specificYield  = vos.readPCRmapClone(\
               iniItems.groundwaterOptions['specificYield'],
               self.cloneMap,self.tmpDir,self.inputDir)
        else:       
            self.specificYield = vos.netcdf2PCRobjCloneWithoutTime(\
                                 groundwaterPropertiesNC,'specificYield',\
                                 cloneMapFileName = self.cloneMap)

        self.specificYield  = pcr.cover(self.specificYield,0.0)       
        self.specificYield  = pcr.max(0.010,self.specificYield)         # TODO: TO BE CHECKED: The resample process of specificYield     
        self.specificYield  = pcr.min(1.000,self.specificYield)       

        if iniItems.groundwaterOptions['groundwaterPropertiesNC'] == str(None):
            # assign aquifer saturated conductivity
            self.kSatAquifer = vos.readPCRmapClone(\
               iniItems.groundwaterOptions['kSatAquifer'],
               self.cloneMap,self.tmpDir,self.inputDir)
        else:       
            self.kSatAquifer = vos.netcdf2PCRobjCloneWithoutTime(\
                               groundwaterPropertiesNC,'kSatAquifer',\
                               cloneMapFileName = self.cloneMap)

        self.kSatAquifer = pcr.cover(self.kSatAquifer,0.0)       
        self.kSatAquifer = pcr.max(0.010,self.kSatAquifer)       

        # limitAbstraction options
        self.limitAbstraction = False
        if iniItems.landSurfaceOptions['limitAbstraction'] == "True": self.limitAbstraction = True
        
        # option for limitting fossil groundwater abstractions - This option is only defined for IWMI project 
        self.limitFossilGroundwaterAbstraction = False
        if self.limitAbstraction == False and\
           "extraOptionsforProjectWithIWMI" in iniItems.allSections and\
           iniItems.extraOptionsforProjectWithIWMI['limitFossilGroundWaterAbstraction'] == "True":
            
            logger.info('Fossil groundwater abstraction limit is used (IWMI project).')
            self.limitFossilGroundwaterAbstraction = True
            
            # estimate of thickness (unit: mm) of aceesible groundwater: shallow and deep 
            totalGroundwaterThickness = vos.readPCRmapClone(\
                                        iniItems.extraOptionsforProjectWithIWMI['estimateOfTotalGroundwaterThickness'],
                                        self.cloneMap,self.tmpDir,self.inputDir)
            totalGroundwaterThickness = pcr.cover(totalGroundwaterThickness,
                                        pcr.windowaverage(totalGroundwaterThickness, 1.0))
            totalGroundwaterThickness = pcr.cover(totalGroundwaterThickness,
                                        pcr.windowaverage(totalGroundwaterThickness, 1.5))
            totalGroundwaterThickness = pcr.cover(totalGroundwaterThickness,
                                        pcr.windowaverage(totalGroundwaterThickness, 2.5))
            totalGroundwaterThickness = pcr.cover(totalGroundwaterThickness,
                                        pcr.windowaverage(totalGroundwaterThickness, 5.0))
            totalGroundwaterThickness = pcr.cover(totalGroundwaterThickness,
                                        pcr.windowaverage(totalGroundwaterThickness, 7.5))
            totalGroundwaterThickness = pcr.cover(totalGroundwaterThickness,
                                        pcr.mapmaximum(totalGroundwaterThickness))

            # set minimum thickness to 50 m:
            totalGroundwaterThickness = pcr.max(50.0, totalGroundwaterThickness)
            
            # estimate of capacity (unit: m) of renewable groundwater (shallow)
            storGroundwaterCap =  pcr.cover(
                                  vos.readPCRmapClone(\
                                  iniItems.extraOptionsforProjectWithIWMI['estimateOfRenewableGroundwaterCapacity'],
                                  self.cloneMap,self.tmpDir,self.inputDir),\
                                  0.0)

            # fossil groundwater capacity (unit: m)
            self.fossilWaterCap = pcr.max(0.0,\
                                  totalGroundwaterThickness*self.specificYield - storGroundwaterCap)
            
        # option for limitting regional groundwater abstractions - This option is only defined 
        self.limitRegionalAnnualGroundwaterAbstraction = False
        if "extraOptionsforProjectWithIWMI" in iniItems.allSections and\
           iniItems.extraOptionsforProjectWithIWMI['limitRegionalAnnualGroundwaterAbstraction'] == "True":

            logger.info('Limit for regional groundwater abstraction is used (IWMI project).')
            self.limitRegionalAnnualGroundwaterAbstraction = True
            
            region_ids = vos.readPCRmapClone(\
                         iniItems.extraOptionsforProjectWithIWMI['regionIds'],
                         self.cloneMap,self.tmpDir,self.inputDir)
            self.region_ids = pcr.nominal(region_ids)
            self.region_ids = pcr.ifthen(self.landmask, self.region_ids)
            
            self.regionalAnnualGroundwaterAbstractionLimit = vos.readPCRmapClone(\
                                                                 iniItems.extraOptionsforProjectWithIWMI['pumpingCapacity'],
                                                                 self.cloneMap,self.tmpDir,self.inputDir)
            self.regionalAnnualGroundwaterAbstractionLimit = pcr.roundup(self.regionalAnnualGroundwaterAbstractionLimit*1000.)/1000.
            self.regionalAnnualGroundwaterAbstractionLimit = pcr.cover(self.regionalAnnualGroundwaterAbstractionLimit, 0.0)
            
            self.regionalAnnualGroundwaterAbstractionLimit *= 1000. * 1000. * 1000. # unit: m3/year
            self.regionalAnnualGroundwaterAbstractionLimit  = pcr.ifthen(self.landmask,\
                                                                         self.regionalAnnualGroundwaterAbstractionLimit)

        # zones at which water allocation (surface and groundwater allocation) is determined
        self.usingAllocSegments = False
        if iniItems.landSurfaceOptions['allocationSegmentsForGroundSurfaceWater']  != "None": self.usingAllocSegments = True
        
        # incorporating groundwater distribution network:
        if self.usingAllocSegments and self.limitAbstraction == False:

            self.allocSegments = vos.readPCRmapClone(\
             iniItems.landSurfaceOptions['allocationSegmentsForGroundSurfaceWater'],
             self.cloneMap,self.tmpDir,self.inputDir,isLddMap=False,cover=None,isNomMap=True)
            self.allocSegments = pcr.ifthen(self.landmask, self.allocSegments)

            cellArea = vos.readPCRmapClone(\
              iniItems.routingOptions['cellAreaMap'],
              self.cloneMap,self.tmpDir,self.inputDir)
            cellArea = pcr.ifthen(self.landmask, cellArea)              # TODO: integrate this one with the one coming from the routing module

            self.segmentArea = pcr.areatotal(pcr.cover(cellArea, 0.0), self.allocSegments)
            self.segmentArea = pcr.ifthen(self.landmask, self.segmentArea)
        

        self.report = True
        try:
            self.outDailyTotNC = iniItems.groundwaterOptions['outDailyTotNC'].split(",")
            self.outMonthTotNC = iniItems.groundwaterOptions['outMonthTotNC'].split(",")
            self.outMonthAvgNC = iniItems.groundwaterOptions['outMonthAvgNC'].split(",")
            self.outMonthEndNC = iniItems.groundwaterOptions['outMonthEndNC'].split(",")
            self.outAnnuaTotNC = iniItems.groundwaterOptions['outAnnuaTotNC'].split(",")
            self.outAnnuaAvgNC = iniItems.groundwaterOptions['outAnnuaAvgNC'].split(",")
            self.outAnnuaEndNC = iniItems.groundwaterOptions['outAnnuaEndNC'].split(",")
        except:
            self.report = False
        if self.report == True:
            self.outNCDir  = iniItems.outNCDir
            self.netcdfObj = PCR2netCDF(iniItems)
            #
            # daily output in netCDF files:
            if self.outDailyTotNC[0] != "None":
                for var in self.outDailyTotNC:
                    # creating the netCDF files:
                    self.netcdfObj.createNetCDF(str(self.outNCDir)+"/"+ \
                                                str(var)+"_dailyTot.nc",\
                                                    var,"undefined")
            # MONTHly output in netCDF files:
            # - cummulative
            if self.outMonthTotNC[0] != "None":
                for var in self.outMonthTotNC:
                    # initiating monthlyVarTot (accumulator variable):
                    vars(self)[var+'MonthTot'] = None
                    # creating the netCDF files:
                    self.netcdfObj.createNetCDF(str(self.outNCDir)+"/"+ \
                                                str(var)+"_monthTot.nc",\
                                                    var,"undefined")
            # - average
            if self.outMonthAvgNC[0] != "None":
                for var in self.outMonthAvgNC:
                    # initiating monthlyTotAvg (accumulator variable)
                    vars(self)[var+'MonthTot'] = None
                    # initiating monthlyVarAvg:
                    vars(self)[var+'MonthAvg'] = None
                     # creating the netCDF files:
                    self.netcdfObj.createNetCDF(str(self.outNCDir)+"/"+ \
                                                str(var)+"_monthAvg.nc",\
                                                    var,"undefined")
            # - last day of the month
            if self.outMonthEndNC[0] != "None":
                for var in self.outMonthEndNC:
                     # creating the netCDF files:
                    self.netcdfObj.createNetCDF(str(self.outNCDir)+"/"+ \
                                                str(var)+"_monthEnd.nc",\
                                                    var,"undefined")
            # YEARly output in netCDF files:
            # - cummulative
            if self.outAnnuaTotNC[0] != "None":
                for var in self.outAnnuaTotNC:
                    # initiating yearly accumulator variable:
                    vars(self)[var+'AnnuaTot'] = None
                    # creating the netCDF files:
                    self.netcdfObj.createNetCDF(str(self.outNCDir)+"/"+ \
                                                str(var)+"_annuaTot.nc",\
                                                    var,"undefined")
            # - average
            if self.outAnnuaAvgNC[0] != "None":
                for var in self.outAnnuaAvgNC:
                    # initiating annualyVarAvg:
                    vars(self)[var+'AnnuaAvg'] = None
                    # initiating annualyTotAvg (accumulator variable)
                    vars(self)[var+'AnnuaTot'] = None
                     # creating the netCDF files:
                    self.netcdfObj.createNetCDF(str(self.outNCDir)+"/"+ \
                                                str(var)+"_annuaAvg.nc",\
                                                    var,"undefined")
            # - last day of the year
            if self.outAnnuaEndNC[0] != "None":
                for var in self.outAnnuaEndNC:
                     # creating the netCDF files:
                    self.netcdfObj.createNetCDF(str(self.outNCDir)+"/"+ \
                                                str(var)+"_annuaEnd.nc",\
                                                    var,"undefined")

        #get initial conditions
        self.getICs(iniItems,spinUp)
Esempio n. 42
0
    def createInstancesInitial(self):
        import generalfunctions

        if readDistributionOfParametersFromDisk:
            path = '/home/derek/tmp/'
            maximumInterceptionCapacityPerLAI = pcr.scalar(
                path +
                pcrfw.generateNameS('RPic', self.currentSampleNumber()) +
                '.map')
            ksat = pcr.scalar(
                path +
                pcrfw.generateNameS('RPks', self.currentSampleNumber()) +
                '.map')
            regolithThicknessHomogeneous = pcr.scalar(
                path +
                pcrfw.generateNameS('RPrt', self.currentSampleNumber()) +
                '.map')
            saturatedConductivityMetrePerDay = pcr.scalar(
                path +
                pcrfw.generateNameS('RPsc', self.currentSampleNumber()) +
                '.map')
            multiplierMaxStomatalConductance = pcr.scalar(
                path +
                pcrfw.generateNameS('RPmm', self.currentSampleNumber()) +
                '.map')
        else:
            maximumInterceptionCapacityPerLAI = generalfunctions.areauniformBounds(
                0.0001, 0.0005, pcr.nominal(1),
                pcr.scalar(cfg.maximumInterceptionCapacityValue),
                createRealizations)
            ksat = generalfunctions.areauniformBounds(
                0.025, 0.05, pcr.nominal(1), pcr.scalar(cfg.ksatValue),
                createRealizations)
            regolithThicknessHomogeneous = generalfunctions.areauniformBounds(
                1.0, 3.5, cfg.areas,
                pcr.scalar(cfg.regolithThicknessHomogeneousValue),
                createRealizations)
            saturatedConductivityMetrePerDay = generalfunctions.mapuniformBounds(
                25.0, 40.0,
                pcr.scalar(cfg.saturatedConductivityMetrePerDayValue),
                createRealizations)
            multiplierMaxStomatalConductance = generalfunctions.mapuniformBounds(
                0.8, 1.1,
                pcr.scalar(cfg.multiplierMaxStomatalConductanceValue),
                createRealizations)

        if swapCatchments:
            regolithThicknessHomogeneous = generalfunctions.swapValuesOfTwoRegions(
                cfg.areas, regolithThicknessHomogeneous, True)

        self.d_randomparameters = randomparameters.RandomParameters(
            timeStepsToReportRqs, setOfVariablesToReport,
            maximumInterceptionCapacityPerLAI, ksat,
            regolithThicknessHomogeneous, saturatedConductivityMetrePerDay,
            multiplierMaxStomatalConductance)

        # class for exchange variables in initial and dynamic
        # introduced to make filtering possible
        self.d_exchangevariables = exchangevariables.ExchangeVariables(
            timeStepsToReportSome,
            setOfVariablesToReport,
        )

        ################
        # interception #
        ################

        self.ldd = cfg.lddMap

        initialInterceptionStore = pcr.scalar(0.000001)
        leafAreaIndex = pcr.scalar(cfg.leafAreaIndexValue)

        if swapCatchments:
            leafAreaIndex = generalfunctions.swapValuesOfTwoRegions(
                cfg.areas, leafAreaIndex, True)
        gapFraction = pcr.exp(
            -0.5 * leafAreaIndex)  # equation 40 in Brolsma et al 2010a
        maximumInterceptionStore = maximumInterceptionCapacityPerLAI * leafAreaIndex

        self.d_interceptionuptomaxstore = interceptionuptomaxstore.InterceptionUpToMaxStore(
            self.ldd, initialInterceptionStore, maximumInterceptionStore,
            gapFraction, self.timeStepDurationHours, timeStepsToReportSome,
            setOfVariablesToReport)

        #################
        # surface store #
        #################

        initialSurfaceStore = pcr.scalar(0.0)
        maxSurfaceStore = pcr.scalar(cfg.maxSurfaceStoreValue)
        self.d_surfaceStore = surfacestore.SurfaceStore(
            initialSurfaceStore, maxSurfaceStore, self.timeStepDurationHours,
            timeStepsToReportSome, setOfVariablesToReport)

        ################
        # infiltration #
        ################

        # N initialMoistureContentFraction taken from 1st July

        # DK
        # we do not use rts and Gs as input to calculate initial moisture fraction to avoid
        # problems when the initial regolith thickness is calibrated (it might be thinner than
        # initialMoistureThick -> problems!)
        # instead, we use initial moisture content fraction as input, read from disk, it is just calculated
        # by pcrcalc 'mergeInitialMoistureContentFraction=Gs000008.761/rts00008.761'
        # note that I also changed the name for the initial soil moisture as a fraction
        initialSoilMoistureFractionFromDisk = pcr.scalar(
            cfg.initialSoilMoistureFractionFromDiskValue)
        if swapCatchments:
            initialSoilMoistureFractionFromDisk = generalfunctions.swapValuesOfTwoRegions(
                cfg.areas, initialSoilMoistureFractionFromDisk, True)

        # initial soil moisture as a fraction should not be above soil porosity as a fraction, just a check
        soilPorosityFraction = pcr.scalar(cfg.soilPorosityFractionValue)
        if swapCatchments:
            soilPorosityFraction = generalfunctions.swapValuesOfTwoRegions(
                cfg.areas, soilPorosityFraction, True)
        initialSoilMoistureFraction = pcr.min(
            soilPorosityFraction, initialSoilMoistureFractionFromDisk)
        hf = pcr.scalar(-0.0000001)
        self.d_infiltrationgreenandampt = infiltrationgreenandampt.InfiltrationGreenAndAmpt(
            soilPorosityFraction, initialSoilMoistureFraction, ksat, hf,
            self.timeStepDurationHours, timeStepsToReportSome,
            setOfVariablesToReport)

        ####################
        # subsurface water #
        ####################

        demOfBedrockTopography = self.dem

        stream = pcr.boolean(cfg.streamValue)
        theSlope = pcr.slope(self.dem)
        regolithThickness = pcr.ifthenelse(stream, 0.01,
                                           regolithThicknessHomogeneous)

        self.multiplierWiltingPoint = pcr.scalar(1.0)
        limitingPointFraction = pcr.scalar(cfg.limitingPointFractionValue)

        if swapCatchments:
            limitingPointFraction = generalfunctions.swapValuesOfTwoRegions(
                cfg.areas, limitingPointFraction, True)
        mergeWiltingPointFractionFS = pcr.scalar(
            cfg.mergeWiltingPointFractionFSValue)
        if swapCatchments:
            mergeWiltingPointFractionFS = generalfunctions.swapValuesOfTwoRegions(
                cfg.areas, mergeWiltingPointFractionFS, True)
        wiltingPointFractionNotChecked = mergeWiltingPointFractionFS * self.multiplierWiltingPoint
        wiltingPointFraction = pcr.min(wiltingPointFractionNotChecked,
                                       limitingPointFraction)

        fieldCapacityFraction = pcr.scalar(cfg.fieldCapacityFractionValue)
        if swapCatchments:
            fieldCapacityFraction = generalfunctions.swapValuesOfTwoRegions(
                cfg.areas, fieldCapacityFraction, True)

        self.d_subsurfaceWaterOneLayer = subsurfacewateronelayer.SubsurfaceWaterOneLayer(
            self.ldd, demOfBedrockTopography, regolithThickness,
            initialSoilMoistureFraction, soilPorosityFraction,
            wiltingPointFraction, fieldCapacityFraction, limitingPointFraction,
            saturatedConductivityMetrePerDay, self.timeStepDurationHours,
            timeStepsToReportSome, setOfVariablesToReport)

        ##########
        # runoff #
        ##########

        self.d_runoffAccuthreshold = runoffaccuthreshold.RunoffAccuthreshold(
            self.ldd, self.timeStepDurationHours, timeStepsToReportRqs,
            setOfVariablesToReport)

        ######################
        # evapotranspiration #
        ######################

        albedo = pcr.scalar(cfg.albedoValue)
        if swapCatchments:
            albedo = generalfunctions.swapValuesOfTwoRegions(
                cfg.areas, albedo, True)

        maxStomatalConductance = pcr.scalar(
            cfg.maxStomatalConductanceValue) * multiplierMaxStomatalConductance
        if swapCatchments:
            maxStomatalConductance = generalfunctions.swapValuesOfTwoRegions(
                cfg.areas, maxStomatalConductance, True)

        vegetationHeight = pcr.scalar(cfg.vegetationHeightValue)
        if swapCatchments:
            vegetationHeight = generalfunctions.swapValuesOfTwoRegions(
                cfg.areas, vegetationHeight, True)
        self.d_evapotranspirationPenman = evapotranspirationpenman.EvapotranspirationPenman(
            self.timeStepDurationHours, albedo, maxStomatalConductance,
            vegetationHeight, leafAreaIndex, timeStepsToReportSome,
            setOfVariablesToReport)
Esempio n. 43
0
    def readSoilMapOfFAO(self, iniItems, optionDict=None):

        # a dictionary/section of options that will be used
        if optionDict == None:
            optionDict = iniItems._sections[
                "landSurfaceOptions"
            ]  # iniItems.landSurfaceOptions

        # soil variable names given either in the ini or netCDF file:
        soilParameters = [
            "airEntryValue1",
            "airEntryValue2",
            "poreSizeBeta1",
            "poreSizeBeta2",
            "resVolWC1",
            "resVolWC2",
            "satVolWC1",
            "satVolWC2",
            "KSat1",
            "KSat2",
            "percolationImp",
        ]
        if optionDict["soilPropertiesNC"] == str(None):
            for var in soilParameters:
                input = optionDict[str(var)]
                vars(self)[var] = vos.readPCRmapClone(
                    input, self.cloneMap, self.tmpDir, self.inputDir
                )
                vars(self)[var] = pcr.scalar(vars(self)[var])

                if input == "percolationImp":
                    vars(self)[var] = pcr.cover(vars(self)[var], 0.0)

                # extrapolation
                # - TODO: Make a general extrapolation option as a function in the virtualOS.py
                vars(self)[var] = pcr.cover(
                    vars(self)[var], pcr.windowaverage(vars(self)[var], 0.75)
                )
                vars(self)[var] = pcr.cover(
                    vars(self)[var], pcr.windowaverage(vars(self)[var], 1.00)
                )
                vars(self)[var] = pcr.cover(
                    vars(self)[var], pcr.windowaverage(vars(self)[var], 1.00)
                )
                vars(self)[var] = pcr.cover(
                    vars(self)[var], pcr.windowaverage(vars(self)[var], 1.00)
                )
                vars(self)[var] = pcr.cover(
                    vars(self)[var], pcr.windowaverage(vars(self)[var], 1.00)
                )
                vars(self)[var] = pcr.cover(
                    vars(self)[var], pcr.windowaverage(vars(self)[var], 1.00)
                )
                vars(self)[var] = pcr.cover(vars(self)[var], 0.0)

        else:
            soilPropertiesNC = vos.getFullPath(
                optionDict["soilPropertiesNC"], self.inputDir
            )
            for var in soilParameters:
                vars(self)[var] = vos.netcdf2PCRobjCloneWithoutTime(
                    soilPropertiesNC, var, cloneMapFileName=self.cloneMap
                )

                if var == "percolationImp":
                    vars(self)[var] = pcr.cover(vars(self)[var], 0.0)

                # extrapolation
                # - TODO: Make a general extrapolation option as a function in the virtualOS.py
                vars(self)[var] = pcr.cover(
                    vars(self)[var], pcr.windowaverage(vars(self)[var], 0.75)
                )
                vars(self)[var] = pcr.cover(
                    vars(self)[var], pcr.windowaverage(vars(self)[var], 1.00)
                )
                vars(self)[var] = pcr.cover(
                    vars(self)[var], pcr.windowaverage(vars(self)[var], 1.00)
                )
                vars(self)[var] = pcr.cover(
                    vars(self)[var], pcr.windowaverage(vars(self)[var], 1.00)
                )
                vars(self)[var] = pcr.cover(
                    vars(self)[var], pcr.windowaverage(vars(self)[var], 1.00)
                )
                vars(self)[var] = pcr.cover(
                    vars(self)[var], pcr.windowaverage(vars(self)[var], 1.00)
                )

                vars(self)[var] = pcr.cover(vars(self)[var], 0.01)

        # make sure that resVolWC1 <= satVolWC1
        self.resVolWC1 = pcr.min(self.resVolWC1, self.satVolWC1)
        self.resVolWC2 = pcr.min(self.resVolWC2, self.satVolWC2)

        if self.numberOfLayers == 2:
            self.satVolMoistContUpp = (
                self.satVolWC1
            )  # saturated volumetric moisture content (m3.m-3)
            self.satVolMoistContLow = self.satVolWC2
            self.resVolMoistContUpp = (
                self.resVolWC1
            )  # residual volumetric moisture content (m3.m-3)
            self.resVolMoistContLow = self.resVolWC2
            self.airEntryValueUpp = (
                self.airEntryValue1
            )  # air entry value (m) according to soil water retention curve of Clapp & Hornberger (1978)
            self.airEntryValueLow = self.airEntryValue2
            self.poreSizeBetaUpp = (
                self.poreSizeBeta1
            )  # pore size distribution parameter according to Clapp & Hornberger (1978)
            self.poreSizeBetaLow = self.poreSizeBeta2
            self.kSatUpp = self.KSat1  # saturated hydraulic conductivity (m.day-1)
            self.kSatLow = self.KSat2

        if self.numberOfLayers == 3:
            self.satVolMoistContUpp000005 = self.satVolWC1
            self.satVolMoistContUpp005030 = self.satVolWC1
            self.satVolMoistContLow030150 = self.satVolWC2
            self.resVolMoistContUpp000005 = self.resVolWC1
            self.resVolMoistContUpp005030 = self.resVolWC1
            self.resVolMoistContLow030150 = self.resVolWC2
            self.airEntryValueUpp000005 = self.airEntryValue1
            self.airEntryValueUpp005030 = self.airEntryValue1
            self.airEntryValueLow030150 = self.airEntryValue2
            self.poreSizeBetaUpp000005 = self.poreSizeBeta1
            self.poreSizeBetaUpp005030 = self.poreSizeBeta1
            self.poreSizeBetaLow030150 = self.poreSizeBeta2
            self.kSatUpp000005 = self.KSat1
            self.kSatUpp005030 = self.KSat1
            self.kSatLow030150 = self.KSat2

        self.percolationImp = pcr.cover(
            self.percolationImp, 0.0
        )  # fractional area where percolation to groundwater store is impeded (dimensionless)

        # soil thickness and storage variable names
        # as given either in the ini or netCDF file:
        soilStorages = [
            "firstStorDepth",
            "secondStorDepth",
            "soilWaterStorageCap1",
            "soilWaterStorageCap2",
        ]
        if optionDict["soilPropertiesNC"] == str(None):
            for var in soilStorages:
                input = optionDict[str(var)]
                temp = str(var) + "Inp"
                vars(self)[temp] = vos.readPCRmapClone(
                    input, self.cloneMap, self.tmpDir, self.inputDir
                )

                # extrapolation
                # - TODO: Make a general extrapolation option as a function in the virtualOS.py
                vars(self)[temp] = pcr.cover(
                    vars(self)[temp], pcr.windowaverage(vars(self)[temp], 0.75)
                )
                vars(self)[temp] = pcr.cover(
                    vars(self)[temp], pcr.windowaverage(vars(self)[temp], 1.05)
                )
                vars(self)[temp] = pcr.cover(
                    vars(self)[temp], pcr.windowaverage(vars(self)[temp], 1.05)
                )
                vars(self)[temp] = pcr.cover(
                    vars(self)[temp], pcr.windowaverage(vars(self)[temp], 1.05)
                )
                vars(self)[temp] = pcr.cover(
                    vars(self)[temp], pcr.windowaverage(vars(self)[temp], 1.05)
                )
                vars(self)[temp] = pcr.cover(
                    vars(self)[temp], pcr.windowaverage(vars(self)[temp], 1.05)
                )
                vars(self)[temp] = pcr.cover(vars(self)[temp], 0.0)

        else:
            soilPropertiesNC = vos.getFullPath(
                optionDict["soilPropertiesNC"], self.inputDir
            )
            for var in soilStorages:
                temp = str(var) + "Inp"
                vars(self)[temp] = vos.netcdf2PCRobjCloneWithoutTime(
                    soilPropertiesNC, var, cloneMapFileName=self.cloneMap
                )
                # extrapolation
                # - TODO: Make a general extrapolation option as a function in the virtualOS.py
                vars(self)[temp] = pcr.cover(
                    vars(self)[temp], pcr.windowaverage(vars(self)[temp], 0.75)
                )
                vars(self)[temp] = pcr.cover(
                    vars(self)[temp], pcr.windowaverage(vars(self)[temp], 1.05)
                )
                vars(self)[temp] = pcr.cover(
                    vars(self)[temp], pcr.windowaverage(vars(self)[temp], 1.05)
                )
                vars(self)[temp] = pcr.cover(
                    vars(self)[temp], pcr.windowaverage(vars(self)[temp], 1.05)
                )
                vars(self)[temp] = pcr.cover(
                    vars(self)[temp], pcr.windowaverage(vars(self)[temp], 1.05)
                )
                vars(self)[temp] = pcr.cover(
                    vars(self)[temp], pcr.windowaverage(vars(self)[temp], 1.05)
                )
                vars(self)[temp] = pcr.cover(vars(self)[temp], 0.0)

        # layer thickness
        if self.numberOfLayers == 2:
            self.thickUpp = (0.30 / 0.30) * self.firstStorDepthInp
            self.thickLow = (1.20 / 1.20) * self.secondStorDepthInp
        if self.numberOfLayers == 3:
            self.thickUpp000005 = (0.05 / 0.30) * self.firstStorDepthInp
            self.thickUpp005030 = (0.25 / 0.30) * self.firstStorDepthInp
            self.thickLow030150 = (1.20 / 1.20) * self.secondStorDepthInp

        # soil storage
        if self.numberOfLayers == 2:
            # ~ self.storCapUpp = (0.30/0.30)*self.soilWaterStorageCap1Inp
            # ~ self.storCapLow = (1.20/1.20)*self.soilWaterStorageCap2Inp                     # 22 Feb 2014: We can calculate this based on thickness and porosity.
            self.storCapUpp = self.thickUpp * (
                self.satVolMoistContUpp - self.resVolMoistContUpp
            )
            self.storCapLow = self.thickLow * (
                self.satVolMoistContLow - self.resVolMoistContLow
            )
            self.rootZoneWaterStorageCap = (
                self.storCapUpp + self.storCapLow
            )  # This is called as WMAX in the original pcrcalc script.
        if self.numberOfLayers == 3:
            self.storCapUpp000005 = self.thickUpp000005 * (
                self.satVolMoistContUpp000005 - self.resVolMoistContUpp000005
            )
            self.storCapUpp005030 = self.thickUpp005030 * (
                self.satVolMoistContUpp005030 - self.resVolMoistContUpp005030
            )
            self.storCapLow030150 = self.thickLow030150 * (
                self.satVolMoistContLow030150 - self.resVolMoistContLow030150
            )
            self.rootZoneWaterStorageCap = (
                self.storCapUpp000005 + self.storCapUpp005030 + self.storCapLow030150
            )
 def setMaximumStore(self, maximumStore):
     self.maximumStore = pcr.scalar(maximumStore)
     self.store = pcr.min(self.store, self.maximumStore)
Esempio n. 45
0
def naturalLake(
    waterlevel,
    LakeLocs,
    LinkedLakeLocs,
    LakeArea,
    LakeThreshold,
    LakeStorFunc,
    LakeOutflowFunc,
    sh,
    hq,
    lake_b,
    lake_e,
    inflow,
    precip,
    pet,
    LakeAreasMap,
    JDOY,
    timestepsecs=86400,
):
    
    """
    Run Natural Lake module to compute the new waterlevel and outflow.
    Solves lake water balance with linearisation and iteration procedure,
    for any rating and storage curve.
    For the case where storage curve is S = AH and Q=b(H-Ho)^2, uses the direct
    solution from the Modified Puls Approach (LISFLOOD).


    :ivar waterlevel: water level H in the lake
    :ivar LakeLocs: location of lake's outlet
    :ivar LinkedLakeLocs: ID of linked lakes
    :ivar LakeArea: total lake area
    :ivar LakeThreshold: water level threshold Ho under which outflow is zero
    :ivar LakeStorFunc: type of lake storage curve
                        1: S = AH
                        2: S = f(H) from lake data and interpolation
    :ivar LakeOutflowFunc: type of lake rating curve
                           1: Q = f(H) from lake data and interpolation
                           2: General Q = b(H - Ho)^e
                           3: Case of Puls Approach Q = b(H - Ho)^2
    :ivar sh: data for storage curve
    :ivar hq: data for rating curve
    :ivar lake_b: rating curve coefficient
    :ivar lake_e: rating curve exponent
    :ivar inflow: inflow to the lake (surface runoff + river discharge + seepage)
    :ivar precip: precipitation map
    :ivar pet: PET map
    :ivar LakeAreasMap: lake extent map (for filtering P and PET)
    :ivar JDOY: Julian Day of Year to read storage/rating curve from data
    :ivar timestepsecs: model timestep in seconds

    :returns: waterlevel, outflow, prec_av, pet_av, storage
    """

    mv = -999.0
    LakeZeros = LakeArea * 0.0
    
    waterlevel_start = waterlevel

    inflow = pcr.ifthen(pcr.boolean(LakeLocs), inflow)

    prec_av = pcr.ifthen(
        pcr.boolean(LakeLocs), pcr.areaaverage(precip, LakeAreasMap)
    )
    pet_av = pcr.ifthen(
        pcr.boolean(LakeLocs), pcr.areaaverage(pet, LakeAreasMap)
    )
    
    
    ### Modified Puls Approach (Burek et al., 2013, LISFLOOD) ###
    #ResOutflowFunc = 3 
    
    #Calculate lake factor and SI parameter
    LakeFactor = pcr.ifthenelse(
            LakeOutflowFunc == 3,
            LakeArea / (timestepsecs * (lake_b) ** 0.5),
            mv
            )
    
    storage_start = pcr.ifthenelse(
            LakeStorFunc == 1,
            LakeArea * waterlevel_start,
            lookupResFunc(LakeLocs, waterlevel_start, sh, "0-1"),
            )

    SIFactor = pcr.ifthenelse(
            LakeOutflowFunc == 3,
            ((storage_start + (prec_av-pet_av)*LakeArea/1000.0) / timestepsecs 
             + inflow),
            mv
            )
    #Adjust SIFactor for ResThreshold != 0
    SIFactorAdj = SIFactor - LakeArea * LakeThreshold / timestepsecs
    
    #Calculate the new lake outflow/waterlevel/storage
    outflow = pcr.ifthenelse(
            LakeOutflowFunc == 3,
            pcr.ifthenelse(
                    SIFactorAdj > 0.0,
                    (-LakeFactor + (LakeFactor**2 + 2*SIFactorAdj) ** 0.5) ** 2,
                    0.0),
            LakeZeros
            )
    storage = pcr.ifthenelse(
            LakeOutflowFunc == 3,
            (SIFactor - outflow) * timestepsecs,
            LakeZeros
            )
    waterlevel = pcr.ifthenelse(
            LakeOutflowFunc == 3,
            storage / LakeArea,
            LakeZeros
            )
    
    ### Linearisation and iteration for specific storage/rating curves ###
    np_lakeoutflowfunc = pcr.pcr2numpy(LakeOutflowFunc, 0.0)
    if ((bool(np.isin(1, np.unique(np_lakeoutflowfunc)))) or 
        (bool(np.isin(2, np.unique(np_lakeoutflowfunc))))):
        
        np_lakelocs = pcr.pcr2numpy(LakeLocs, 0.0)
        np_linkedlakelocs = pcr.pcr2numpy(LinkedLakeLocs, 0.0)
        waterlevel_loop = waterlevel_start
    
        _outflow = []
        nr_loop = np.max([int(timestepsecs / 21600), 1])
        for n in range(0, nr_loop):
            np_waterlevel = pcr.pcr2numpy(waterlevel_loop, np.nan)
            np_waterlevel_lower = np_waterlevel.copy()
    
            for val in np.unique(np_linkedlakelocs):
                if val > 0:
                    np_waterlevel_lower[np_linkedlakelocs == val] = np_waterlevel[
                        np.where(np_lakelocs == val)
                    ]
    
            diff_wl = np_waterlevel - np_waterlevel_lower
            diff_wl[np.isnan(diff_wl)] = mv
            np_waterlevel_lower[np.isnan(np_waterlevel_lower)] = mv
    
            pcr_diff_wl = pcr.numpy2pcr(pcr.Scalar, diff_wl, mv)
            pcr_wl_lower = pcr.numpy2pcr(pcr.Scalar, np_waterlevel_lower, mv)
    
            storage_start_loop = pcr.ifthenelse(
                LakeStorFunc == 1,
                LakeArea * waterlevel_loop,
                lookupResFunc(LakeLocs, waterlevel_loop, sh, "0-1"),
            )
    
            outflow_loop = pcr.ifthenelse(
                LakeOutflowFunc == 1,
                lookupResRegMatr(LakeLocs, waterlevel_loop, hq, JDOY),
                pcr.ifthenelse(
                    pcr_diff_wl >= 0,
                    pcr.max(lake_b * (waterlevel_loop - LakeThreshold) ** lake_e, 0),
                    pcr.min(-1 * lake_b * (pcr_wl_lower - LakeThreshold) ** lake_e, 0),
                ),
            )
    
            np_outflow = pcr.pcr2numpy(outflow_loop, np.nan)
            np_outflow_linked = np_lakelocs * 0.0
    
            with np.errstate(invalid="ignore"):
                if np_outflow[np_outflow < 0] is not None:
                    np_outflow_linked[
                        np.in1d(np_lakelocs, np_linkedlakelocs[np_outflow < 0]).reshape(
                            np_linkedlakelocs.shape
                        )
                    ] = np_outflow[np_outflow < 0]
    
            outflow_linked = pcr.numpy2pcr(pcr.Scalar, np_outflow_linked, 0.0)
    
            fl_nr_loop = float(nr_loop)
            storage_loop = (
                storage_start_loop
                + (inflow * timestepsecs / fl_nr_loop)
                + (prec_av / fl_nr_loop / 1000.0) * LakeArea
                - (pet_av / fl_nr_loop / 1000.0) * LakeArea
                - (pcr.cover(outflow_loop, 0.0) * timestepsecs / fl_nr_loop)
                + (pcr.cover(outflow_linked, 0.0) * timestepsecs / fl_nr_loop)
            )
    
            waterlevel_loop = pcr.ifthenelse(
                LakeStorFunc == 1,
                waterlevel_loop + (storage_loop - storage_start_loop) / LakeArea,
                lookupResFunc(LakeLocs, storage_loop, sh, "1-0"),
            )
    
            np_outflow_nz = np_outflow * 0.0
            with np.errstate(invalid="ignore"):
                np_outflow_nz[np_outflow > 0] = np_outflow[np_outflow > 0]
            _outflow.append(np_outflow_nz)
    
        outflow_av_temp = np.average(_outflow, 0)
        outflow_av_temp[np.isnan(outflow_av_temp)] = mv
        outflow_av = pcr.numpy2pcr(pcr.Scalar, outflow_av_temp, mv)
        
        #Add the discharge/waterlevel/storage from the loop to the one from puls approach
        outflow = pcr.ifthenelse(
                LakeOutflowFunc == 3,
                outflow,
                outflow_av
                )
        waterlevel = pcr.ifthenelse(
                LakeOutflowFunc == 3,
                waterlevel,
                waterlevel_loop
                )
        storage = pcr.ifthenelse(
                LakeOutflowFunc == 3,
                storage,
                storage_loop
                )

    return waterlevel, outflow, prec_av, pet_av, storage
	def __init__(self,startDate,endDate,nrIterDefault= 12.):
		pcrm.DynamicModel.__init__(self)
		##############
		# * __init__ #
		##############
		#-echo to screen
		print 'PCR-GLOBWB dynamic floodplain model - version 3.0 June 2012'
		print '\tbeta version with smoothed floodplain elevations'
		print '\tincluding lakes and reservoirs'
		#-constants: duration of time step (day) in seconds 
		self.timeSec= duration*timeSec
		#-passing global variables to local ones
		#-cloone and cell area
		self.clone= clone
		self.cellArea= cellArea
		#-model settings
		self.nrIterDefault= nrIterDefault
		self.duration= duration
		self.currentDate= startDate
		self.endDate= endDate
		self.areaFractions= areaFractions
		self.relZFileName= os.path.join(mapsDir,relZFileName)
		self.reductionKK= reductionKK
		self.criterionKK= criterionKK
		#-number of entries in list and derived slopes and volumes
		self.nrEntries= len(self.areaFractions)
		self.relZ= [0.]*self.nrEntries
		self.floodVolume= [0.]*(self.nrEntries)    
		#-flood plain and channel characteristics
		self.channelGradient= pcr.max(1.e-7,channelGradient)
		self.LDD= LDD
		self.channelWidth= channelWidth
		self.channelLength= channelLength
		self.channelDepth= channelDepth
		self.channelManN= channelManN
		self.floodplainManN= floodplainManN
		self.floodplainMask= floodplainMask
		self.waterFractionMask= fractionWater
		#-waterBodies
		self.waterBodies= waterBodies
		self.waterBodies.actualArea= self.waterBodies.retrieveMapValue(pcr.areatotal(self.waterFractionMask*\
			self.cellArea,self.waterBodies.distribution))
		#self.reservoirDemandTSS= readTSS(reservoirDemandTSS)
		#-map names: initial maps of discharge and storage
		self.QIniMap= pcrm.generateNameT(QFileName,0).replace('.000','.ini')
		self.actualStorageIniMap= pcrm.generateNameT(actualStorageFileName,0).replace('.000','.ini')
		self.averageQ= averageQ
		self.bankfulQ= bankfulQ
		#-patch elevations: those that are part of sills are updated on the basis of the floodplain gradient
		# using local distances deltaX per increment upto z[N] and the sum over sills
		#-fill all lists including smoothing interval and slopes
		for iCnt in range(1,self.nrEntries):
			self.relZ[iCnt]= clippedRead.get(self.relZFileName %\
				(self.areaFractions[iCnt]*100))
		#-minimum slope of floodplain, being defined as the longest sill, first used to retrieve
		# longest cumulative distance 
		deltaX= [self.cellArea**0.5]*self.nrEntries
		deltaX[0]= 0.
		sumX= deltaX[:]
		minSlope= 0.
		for iCnt in range(self.nrEntries):
			if iCnt < self.nrEntries-1:
				deltaX[iCnt]= (self.areaFractions[iCnt+1]**0.5-self.areaFractions[iCnt]**0.5)*deltaX[iCnt]
			else:
				deltaX[iCnt]= (1.-self.areaFractions[iCnt-1]**0.5)*deltaX[iCnt]
			if iCnt > 0:
				sumX[iCnt]= pcr.ifthenelse(self.relZ[iCnt] == self.relZ[iCnt-1],sumX[iCnt-1]+deltaX[iCnt],0.)
				minSlope= pcr.ifthenelse(self.relZ[iCnt] == self.relZ[iCnt-1],\
					pcr.max(sumX[iCnt],minSlope),minSlope)
		minSlope= pcr.min(self.channelGradient,0.5*pcr.max(deltaX[1],minSlope)**-1.)
		#-add small increment to elevations to each sill except in the case of lakes
		for iCnt in range(self.nrEntries):
			self.relZ[iCnt]= self.relZ[iCnt]+sumX[iCnt]*pcr.ifthenelse(self.relZ[self.nrEntries-1] > 0.,\
				minSlope,0.)
		#-set slope and smoothing interval between dy= y(i+1)-y(i) and dx= x(i+1)-x(i)
		# on the basis of volume
		#-slope and smoothing interval
		self.kSlope=  [0.]*(self.nrEntries)
		self.mInterval= [0.]*(self.nrEntries)
		for iCnt in range(1,self.nrEntries):
			self.floodVolume[iCnt]= self.floodVolume[iCnt-1]+\
				0.5*(self.areaFractions[iCnt]+self.areaFractions[iCnt-1])*\
				(self.relZ[iCnt]-self.relZ[iCnt-1])*self.cellArea
			self.kSlope[iCnt-1]= (self.areaFractions[iCnt]-self.areaFractions[iCnt-1])/\
				pcr.max(0.001,self.floodVolume[iCnt]-self.floodVolume[iCnt-1])
		for iCnt in range(1,self.nrEntries):
			if iCnt < (self.nrEntries-1):
				self.mInterval[iCnt]= 0.5*self.reductionKK*pcr.min(self.floodVolume[iCnt+1]-self.floodVolume[iCnt],\
					self.floodVolume[iCnt]-self.floodVolume[iCnt-1])
			else:
				self.mInterval[iCnt]= 0.5*self.reductionKK*(self.floodVolume[iCnt]-self.floodVolume[iCnt-1])
    def set_river_package(self, discharge):

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

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

        # time
        self.d_dateTimePCRasterPython.update()
        timeDatetimeFormat = self.d_dateTimePCRasterPython.getTimeDatetimeFormat(
        )

        # precipitation
        # for calibration
        rainfallFluxDeterm = pcr.timeinputscalar(
            cfg.rainfallFluxDetermTimeSeries,
            pcr.nominal(cfg.rainfallFluxDetermTimeSeriesAreas))
        # for the experiments
        rainfallFlux = rainfallFluxDeterm  #generalfunctions.mapNormalRelativeError(rainfallFluxDeterm,0.25)
        self.d_exchangevariables.cumulativePrecipitation = \
                self.d_exchangevariables.cumulativePrecipitation + rainfallFlux * self.timeStepDuration

        # interception store
        actualAdditionFluxToInterceptionStore = self.d_interceptionuptomaxstore.addWater(
            rainfallFlux)
        throughfallFlux = rainfallFlux - actualAdditionFluxToInterceptionStore

        # surface store
        totalToSurfaceFlux = throughfallFlux + self.d_exchangevariables.upwardSeepageFlux
        potentialToSurfaceStoreFlux = self.d_surfaceStore.potentialToFlux()

        # potential infiltration
        potentialHortonianInfiltrationFlux = self.d_infiltrationgreenandampt.potentialInfiltrationFluxFunction(
        )
        maximumSaturatedOverlandFlowInfiltrationFlux = self.d_subsurfaceWaterOneLayer.getMaximumAdditionFlux(
        )
        potentialInfiltrationFlux = pcr.min(
            potentialHortonianInfiltrationFlux,
            maximumSaturatedOverlandFlowInfiltrationFlux)

        # abstraction from surface water
        potentialAbstractionFromSurfaceWaterFlux = potentialToSurfaceStoreFlux + potentialInfiltrationFlux
        actualAbstractionFromSurfaceWaterFlux, runoffCubicMetresPerHour = self.d_runoffAccuthreshold.update(
            totalToSurfaceFlux, potentialAbstractionFromSurfaceWaterFlux)
        potentialOutSurfaceStoreFlux = self.d_surfaceStore.potentialOutFlux()

        # infiltration
        availableForInfiltrationFlux = potentialOutSurfaceStoreFlux + actualAbstractionFromSurfaceWaterFlux
        availableForInfiltrationNotExceedingMaximumSaturatedOverlandFlowFlux = pcr.min(
            availableForInfiltrationFlux,
            maximumSaturatedOverlandFlowInfiltrationFlux)
        actualInfiltrationFlux = self.d_infiltrationgreenandampt.update(
            availableForInfiltrationNotExceedingMaximumSaturatedOverlandFlowFlux
        )

        # surface store
        surfaceStoreChange = actualAbstractionFromSurfaceWaterFlux - actualInfiltrationFlux
        self.d_surfaceStore.update(surfaceStoreChange)
        actualAdditionFlux = self.d_subsurfaceWaterOneLayer.addWater(
            actualInfiltrationFlux)

        if cfg.with_shading:
            # solar radiation (POTRAD, shading effect and inclination)
            fractionReceived, fractionReceivedFlatSurface, shaded = \
                                                  self.d_shading.update(timeDatetimeFormat)

            # we assume all cells receive the same solar radiation as measured by the device
            # except for shading, if shading, there is nothing received
            fractionReceived = pcr.ifthenelse(shaded, pcr.scalar(0.0),
                                              pcr.scalar(1.0))
        else:
            fractionReceived = pcr.scalar(cfg.fractionReceivedValue)
            fractionReceivedFlatSurface = pcr.scalar(
                cfg.fractionReceivedFlatSurfaceValue)

        fWaterPotential = self.d_subsurfaceWaterOneLayer.getFWaterPotential()

        # potential evapotranspiration
        airTemperatureDeterm = pcr.timeinputscalar(
            cfg.airTemperatureDetermString, self.clone)
        airTemperature = airTemperatureDeterm  #airTemperatureDeterm+mapnormal()

        relativeHumidityDeterm = pcr.timeinputscalar(
            cfg.relativeHumidityDetermString, self.clone)
        relativeHumidity = relativeHumidityDeterm  #pcr.max(pcr.min(relativeHumidityDeterm+mapnormal()*0.1,pcr.scalar(1.0)),pcr.scalar(0))

        incomingShortwaveRadiationFlatSurface = pcr.timeinputscalar(
            cfg.incomingShortwaveRadiationFlatSurfaceString, self.clone)
        # incomingShortwaveRadiationFlatSurface = pcr.max(pcr.scalar(0),
        #                              generalfunctions.mapNormalRelativeError(incomingShortwaveRadiationFlatSurfaceDeterm,0.25))

        incomingShortwaveRadiationAtSurface = incomingShortwaveRadiationFlatSurface * fractionReceived

        windVelocityDeterm = pcr.timeinputscalar(cfg.windVelocityDetermString,
                                                 self.clone)
        windVelocity = windVelocityDeterm  #generalfunctions.mapNormalRelativeError(windVelocityDeterm,0.25)

        elevationAboveSeaLevelOfMeteoStation = cfg.elevationAboveSeaLevelOfMeteoStationValue

        potentialEvapotranspirationFlux, \
               potentialEvapotranspirationAmount, \
               potentialEvapotranspirationFromCanopyFlux, \
               potentialEvapotranspirationFromCanopyAmount = \
                                self.d_evapotranspirationPenman.potentialEvapotranspiration(
                                airTemperature,
                                relativeHumidity,
                                incomingShortwaveRadiationAtSurface,
                                incomingShortwaveRadiationFlatSurface,
                                fractionReceivedFlatSurface,
                                windVelocity,
                                elevationAboveSeaLevelOfMeteoStation,
                                fWaterPotential,
                                rainfallFlux < 0.000000000001)

        potentialEvapotranspirationFluxNoNegativeValues = pcr.max(
            0.0, potentialEvapotranspirationFlux)
        potentialEvapotranspirationFluxFromCanopyNoNegativeValues = pcr.max(
            0.0, potentialEvapotranspirationFromCanopyFlux)

        # evapotranspirate first from interception store
        actualAbstractionFluxFromInterceptionStore = self.d_interceptionuptomaxstore.abstractWater(
            potentialEvapotranspirationFluxFromCanopyNoNegativeValues)

        # fraction of soil evapotranspiration depends on evapo from canopy
        evapFromSoilMultiplierMV = (potentialEvapotranspirationFluxFromCanopyNoNegativeValues -
                                actualAbstractionFluxFromInterceptionStore) / \
                                potentialEvapotranspirationFluxFromCanopyNoNegativeValues
        self.d_exchangevariables.evapFromSoilMultiplier = \
                               pcr.ifthenelse(potentialEvapotranspirationFluxNoNegativeValues < 0.0000000000001,
                               pcr.scalar(1), evapFromSoilMultiplierMV)

        # evapotranspirate from subsurface store
        # potentialEvapotranspirationFluxFromSubsurface= \
        #                       pcr.max(0.0,potentialEvapotranspirationFluxNoNegativeValues-actualAbstractionFluxFromInterceptionStore)
        potentialEvapotranspirationFluxFromSubsurface = self.d_exchangevariables.evapFromSoilMultiplier * \
                                                      potentialEvapotranspirationFluxNoNegativeValues
        actualAbstractionFluxFromSubsurface = self.d_subsurfaceWaterOneLayer.abstractWater(
            potentialEvapotranspirationFluxFromSubsurface)

        # upward seepage from subsurfacestore
        self.d_exchangevariables.upwardSeepageFlux = self.d_subsurfaceWaterOneLayer.lateralFlow(
        )

        # reports
        self.reportComponentsDynamic()
        self.reportRandomParametersDynamic()
        self.printComponentsDynamic()
        if doReportComponentsDynamicAsNumpy:
            self.reportComponentsDynamicAsNumpy()
Esempio n. 49
0
def agriZone_Ep_Sa_beta_frostSamax_surfTemp(self, k):
    """
    - Potential evaporation is decreased by energy used for interception evaporation    
    - Formula for evaporation based on LP
    - Outgoing fluxes are determined based on (value in previous timestep + inflow) 
    and if this leads to negative storage, the outgoing fluxes are corrected to rato --> Eu is 
    no longer taken into account for this correction
    - Qa u is determined from overflow from Sa --> incorporation of beta function
    - Fa is based on storage in Sa
    - Fa is decreased in case of frozen soil
    - Code for ini-file: 13
    """

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

    self.FrDur[k] = pcr.min(
        self.FrDur[k]
        + pcr.ifthenelse(
            self.TempSurf > 0, self.ratFT[k] * self.TempSurf, self.TempSurf
        )
        * self.dayDeg[k],
        0,
    )
    self.Ft = pcr.min(
        pcr.max(
            self.FrDur[k] / (self.FrDur1[k] - self.FrDur0[k])
            - self.FrDur0[k] / (self.FrDur1[k] - self.FrDur0[k]),
            self.samin[k],
        ),
        1,
    )

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

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

    self.Ea1 = pcr.max((self.PotEvaporation - self.Ei), 0) * pcr.min(
        self.Sa[k] / (self.samax2 * self.LP[k]), 1
    )
    self.Qa1 = (self.Pe - self.Qaadd) * (1 - (1 - self.SaN) ** self.beta[k])

    self.Fa1 = pcr.ifthenelse(
        self.SaN > 0,
        self.Fmin[k]
        + (self.Fmax[k] - self.Fmin[k]) * e ** (-self.decF[k] * (1 - self.SaN)),
        0,
    )

    self.Sa[k] = self.Sa_t[k] + (self.Pe - self.Qaadd) - self.Qa1 - self.Fa1 - self.Ea1

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

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

    self.Ea_[k] = self.Ea
    self.Qa_[k] = self.Qa + self.Qaadd
    self.Fa_[k] = self.Fa
    self.Ft_[k] = self.Ft
Esempio n. 50
0
    def getWaterBodyOutflow(
        self,
        maxTimestepsToAvgDischargeLong,
        avgChannelDischarge,
        length_of_time_step=vos.secondsPerDay(),
        downstreamDemand=None,
    ):

        # outflow in volume from water bodies with lake type (m3):
        lakeOutflow = self.getLakeOutflow(avgChannelDischarge, length_of_time_step)

        # outflow in volume from water bodies with reservoir type (m3):
        if isinstance(downstreamDemand, type(None)):
            downstreamDemand = pcr.scalar(0.0)
        reservoirOutflow = self.getReservoirOutflow(
            avgChannelDischarge, length_of_time_step, downstreamDemand
        )

        # outgoing/release volume from lakes and/or reservoirs
        self.waterBodyOutflow = pcr.cover(reservoirOutflow, lakeOutflow)

        # make sure that all water bodies have outflow:
        self.waterBodyOutflow = pcr.max(0.0, pcr.cover(self.waterBodyOutflow, 0.0))

        # limit outflow to available storage
        factor = 0.25  # to avoid flip flop
        self.waterBodyOutflow = pcr.min(
            self.waterBodyStorage * factor, self.waterBodyOutflow
        )  # unit: m3
        # use round values
        self.waterBodyOutflow = (
            pcr.rounddown(self.waterBodyOutflow / 1.0) * 1.0
        )  # unit: m3

        # outflow rate in m3 per sec
        waterBodyOutflowInM3PerSec = (
            self.waterBodyOutflow / length_of_time_step
        )  # unit: m3/s

        # updating (long term) average outflow (m3/s) ;
        # - needed to constrain/maintain reservoir outflow:
        #
        temp = pcr.max(
            1.0,
            pcr.min(
                maxTimestepsToAvgDischargeLong,
                self.timestepsToAvgDischarge
                - 1.0
                + length_of_time_step / vos.secondsPerDay(),
            ),
        )
        deltaOutflow = waterBodyOutflowInM3PerSec - self.avgOutflow
        R = deltaOutflow * (length_of_time_step / vos.secondsPerDay()) / temp
        self.avgOutflow = self.avgOutflow + R
        self.avgOutflow = pcr.max(0.0, self.avgOutflow)
        #
        # for the reference, see the "weighted incremental algorithm" in http://en.wikipedia.org/wiki/Algorithms_for_calculating_variance

        # update waterBodyStorage (after outflow):
        self.waterBodyStorage = self.waterBodyStorage - self.waterBodyOutflow
        self.waterBodyStorage = pcr.max(0.0, self.waterBodyStorage)
Esempio n. 51
0
 def update(self, availableForInfiltrationFlux):
     self.actualInfiltrationFlux = pcr.min(availableForInfiltrationFlux,
                                           self.potentialInfiltrationFlux)
     self.store = self.store + self.fluxToAmount(
         self.actualInfiltrationFlux)
     return self.actualInfiltrationFlux
Esempio n. 52
0
def waterAbstractionAndAllocation(water_demand_volume,available_water_volume,allocation_zones,\
                                  zone_area = None,
                                  high_volume_treshold = 1000000.,
                                  debug_water_balance = True,\
                                  extra_info_for_water_balance_reporting = "",
                                  ignore_small_values = True):

    logger.debug("Allocation of abstraction.")
    
    # demand volume in each cell (unit: m3)
    if ignore_small_values: # ignore small values to avoid runding error
        cellVolDemand = pcr.rounddown(pcr.max(0.0, water_demand_volume))
    else:
        cellVolDemand = pcr.max(0.0, water_demand_volume)
    
    # total demand volume in each zone/segment (unit: m3)
    zoneVolDemand = pcr.areatotal(cellVolDemand, allocation_zones)
    
    # total available water volume in each cell
    if ignore_small_values: # ignore small values to avoid runding error
        cellAvlWater = pcr.rounddown(pcr.max(0.00, available_water_volume))
    else:
        cellAvlWater = pcr.max(0.00, available_water_volume)
    
    # total available water volume in each zone/segment (unit: m3)
    # - to minimize numerical errors, separating cellAvlWater 
    if not isinstance(high_volume_treshold,types.NoneType):
        # mask: 0 for small volumes ; 1 for large volumes (e.g. in lakes and reservoirs)
        mask = pcr.cover(\
               pcr.ifthen(cellAvlWater > high_volume_treshold, pcr.boolean(1)), pcr.boolean(0))
        zoneAvlWater  = pcr.areatotal(
                        pcr.ifthenelse(mask, 0.0, cellAvlWater), allocation_zones)
        zoneAvlWater += pcr.areatotal(                
                        pcr.ifthenelse(mask, cellAvlWater, 0.0), allocation_zones)
    else:
        zoneAvlWater  = pcr.areatotal(cellAvlWater, allocation_zones)
    
    # total actual water abstraction volume in each zone/segment (unit: m3)
    # - limited to available water
    zoneAbstraction = pcr.min(zoneAvlWater, zoneVolDemand)
    
    # actual water abstraction volume in each cell (unit: m3)
    cellAbstraction = getValDivZero(\
                      cellAvlWater, zoneAvlWater, smallNumber)*zoneAbstraction
    cellAbstraction = pcr.min(cellAbstraction, cellAvlWater)                                                                   
    if ignore_small_values: # ignore small values to avoid runding error
        cellAbstraction = pcr.rounddown(pcr.max(0.00, cellAbstraction))
    # to minimize numerical errors, separating cellAbstraction 
    if not isinstance(high_volume_treshold,types.NoneType):
        # mask: 0 for small volumes ; 1 for large volumes (e.g. in lakes and reservoirs)
        mask = pcr.cover(\
               pcr.ifthen(cellAbstraction > high_volume_treshold, pcr.boolean(1)), pcr.boolean(0))
        zoneAbstraction  = pcr.areatotal(
                           pcr.ifthenelse(mask, 0.0, cellAbstraction), allocation_zones)
        zoneAbstraction += pcr.areatotal(                
                           pcr.ifthenelse(mask, cellAbstraction, 0.0), allocation_zones)
    else:
        zoneAbstraction  = pcr.areatotal(cellAbstraction, allocation_zones)    
    
    # allocation water to meet water demand (unit: m3)
    cellAllocation  = getValDivZero(\
                      cellVolDemand, zoneVolDemand, smallNumber)*zoneAbstraction 
    
    #~ # extraAbstraction to minimize numerical errors:
    #~ zoneDeficitAbstraction = pcr.max(0.0,\
                                     #~ pcr.areatotal(cellAllocation , allocation_zones) -\
                                     #~ pcr.areatotal(cellAbstraction, allocation_zones))
    #~ remainingCellAvlWater = pcr.max(0.0, cellAvlWater - cellAbstraction)
    #~ cellAbstraction      += zoneDeficitAbstraction * getValDivZero(\
                            #~ remainingCellAvlWater, 
                            #~ pcr.areatotal(remainingCellAvlWater, allocation_zones), 
                            #~ smallNumber)                        
    #~ # 
    #~ # extraAllocation to minimize numerical errors:
    #~ zoneDeficitAllocation = pcr.max(0.0,\
                                    #~ pcr.areatotal(cellAbstraction, allocation_zones) -\
                                    #~ pcr.areatotal(cellAllocation , allocation_zones))
    #~ remainingCellDemand = pcr.max(0.0, cellVolDemand - cellAllocation)
    #~ cellAllocation     += zoneDeficitAllocation * getValDivZero(\
                          #~ remainingCellDemand, 
                          #~ pcr.areatotal(remainingCellDemand, allocation_zones), 
                          #~ smallNumber)                        
    
    if debug_water_balance and not isinstance(zone_area,types.NoneType):

        zoneAbstraction = pcr.cover(pcr.areatotal(cellAbstraction, allocation_zones)/zone_area, 0.0)
        zoneAllocation  = pcr.cover(pcr.areatotal(cellAllocation , allocation_zones)/zone_area, 0.0)
    
        waterBalanceCheck([zoneAbstraction],\
                          [zoneAllocation],\
                          [pcr.scalar(0.0)],\
                          [pcr.scalar(0.0)],\
                          'abstraction - allocation per zone/segment (PS: Error here may be caused by rounding error.)' ,\
                           True,\
                           extra_info_for_water_balance_reporting,threshold=1e-4)
    
    return cellAbstraction, cellAllocation