Ejemplo n.º 1
0
    def checkWaterBalance(self, storesAtBeginning, storesAtEnd):
		# for the entire modules: snow + interception + soil + groundwater + waterDemand
		# except: river/routing 

        precipitation   = pcr.ifthen(self.landmask,\
                                     self.meteo.precipitation)          # unit: m

        runoff           = pcr.ifthen(self.landmask,self.routing.runoff)
        
        vos.waterBalanceCheck([precipitation],\
                              [runoff],\
                              [storesAtBeginning],\
                              [storesAtEnd],\
                              'all modules (including water demand), but except river/routing',\
                               True,\
                               self._modelTime.fulldate,threshold=1e-3)
Ejemplo n.º 2
0
    def update(
            self,
            newStorageAtLakeAndReservoirs,
            timestepsToAvgDischarge,
            maxTimestepsToAvgDischargeShort,
            maxTimestepsToAvgDischargeLong,
            currTimeStep,
            avgChannelDischarge,
            length_of_time_step=vos.secondsPerDay(),
            downstreamDemand=None,
    ):

        if self.debugWaterBalance:
            preStorage = self.waterBodyStorage  # unit: m

        self.timestepsToAvgDischarge = (
            timestepsToAvgDischarge
        )  # TODO: include this one in "currTimeStep"

        # obtain inflow (and update storage)
        self.moveFromChannelToWaterBody(
            newStorageAtLakeAndReservoirs,
            timestepsToAvgDischarge,
            maxTimestepsToAvgDischargeShort,
            length_of_time_step,
        )

        # calculate outflow (and update storage)
        self.getWaterBodyOutflow(
            maxTimestepsToAvgDischargeLong,
            avgChannelDischarge,
            length_of_time_step,
            downstreamDemand,
        )

        if self.debugWaterBalance:
            vos.waterBalanceCheck(
                [pcr.cover(self.inflow / self.waterBodyArea, 0.0)],
                [pcr.cover(self.waterBodyOutflow / self.waterBodyArea, 0.0)],
                [pcr.cover(preStorage / self.waterBodyArea, 0.0)],
                [pcr.cover(self.waterBodyStorage / self.waterBodyArea, 0.0)],
                "WaterBodyStorage (unit: m)",
                True,
                currTimeStep.fulldate,
                threshold=5e-3,
            )
Ejemplo n.º 3
0
    def checkLandSurfaceWaterBalance(self, storesAtBeginning, storesAtEnd):
		
		# for the entire stores from snow + interception + soil + groundwater, but excluding river/routing
		# 
        # - incoming fluxes (unit: m)
        precipitation   = pcr.ifthen(self.landmask, self.meteo.precipitation)
        irrGrossDemand  = pcr.ifthen(self.landmask, self.landSurface.irrGrossDemand)
        surfaceWaterInf = pcr.ifthen(self.landmask, self.groundwater.surfaceWaterInf)
		# 
        # - outgoing fluxes (unit: m)
        actualET                = pcr.ifthen(self.landmask, self.landSurface.actualET)
        runoff                  = pcr.ifthen(self.landmask, self.routing.runoff)
        nonFossilGroundwaterAbs = pcr.ifthen(self.landmask, self.groundwater.nonFossilGroundwaterAbs)   
		# 
        vos.waterBalanceCheck([precipitation,surfaceWaterInf,irrGrossDemand],\
                              [actualET,runoff,nonFossilGroundwaterAbs],\
                              [storesAtBeginning],\
                              [storesAtEnd],\
                              'all stores (snow + interception + soil + groundwater), but except river/routing',\
                               True,\
                               self._modelTime.fulldate,threshold=1e-3)
Ejemplo n.º 4
0
    def update(self,newStorageAtLakeAndReservoirs,\
                              timestepsToAvgDischarge,\
                           maxTimestepsToAvgDischargeShort,\
                           maxTimestepsToAvgDischargeLong,\
                           currTimeStep,\
                           avgChannelDischarge,\
                           length_of_time_step = vos.secondsPerDay(),\
                           downstreamDemand = None):

        if self.debugWaterBalance:            \
                       preStorage = self.waterBodyStorage    # unit: m

        self.timestepsToAvgDischarge = timestepsToAvgDischarge  # TODO: include this one in "currTimeStep"

        # obtain inflow (and update storage)
        self.moveFromChannelToWaterBody(\
         newStorageAtLakeAndReservoirs,\
             timestepsToAvgDischarge,\
             maxTimestepsToAvgDischargeShort,\
             length_of_time_step)

        # calculate outflow (and update storage)
        self.getWaterBodyOutflow(\
             maxTimestepsToAvgDischargeLong,\
             avgChannelDischarge,\
             length_of_time_step,\
             downstreamDemand)

        if self.debugWaterBalance:            \
                       vos.waterBalanceCheck([          pcr.cover(self.inflow/self.waterBodyArea,0.0)],\
                                             [pcr.cover(self.waterBodyOutflow/self.waterBodyArea,0.0)],\
                                             [           pcr.cover(preStorage/self.waterBodyArea,0.0)],\
                                             [pcr.cover(self.waterBodyStorage/self.waterBodyArea,0.0)],\
                                               'WaterBodyStorage (unit: m)',\
                                              True,\
                                              currTimeStep.fulldate,threshold=5e-3)

        self.waterBodyBalance = (pcr.cover(self.inflow/self.waterBodyArea, 0.0) - pcr.cover(self.waterBodyOutflow/self.waterBodyArea,0.0)) -\
                                (pcr.cover(self.waterBodyStorage/self.waterBodyArea,0.0) - pcr.cover(preStorage/self.waterBodyArea,0.0))
Ejemplo n.º 5
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)
Ejemplo n.º 6
0
    def checkWaterBalance(self, storesAtBeginning, storesAtEnd):
		# for the entire modules: snow + interception + soil + groundwater + waterDemand
		# except: river/routing 

        irrGrossDemand  = pcr.ifthen(self.landmask,\
                                self.landSurface.irrGrossDemand)        # unit: m

        nonIrrGrossDemand = \
                           pcr.ifthen(self.landmask,\
                                self.landSurface.nonIrrGrossDemand)     # unit: m

        precipitation   = pcr.ifthen(self.landmask,\
                                     self.meteo.precipitation)          # unit: m

        surfaceWaterInf =  pcr.ifthen(self.landmask,\
                                      self.groundwater.surfaceWaterInf)
        
        surfaceWaterAbstraction = \
                           pcr.ifthen(self.landmask,\
                                      self.landSurface.actSurfaceWaterAbstract)                                     
        
        nonFossilGroundwaterAbs = pcr.ifthen(self.landmask,self.groundwater.nonFossilGroundwaterAbs)   

        unmetDemand      = pcr.ifthen(self.landmask,\
                                      self.groundwater.unmetDemand)                                   # PS: We assume that unmetDemand is extracted (only) to satisfy local demand.

        runoff           = pcr.ifthen(self.landmask,self.routing.runoff)
        
        actualET         = pcr.ifthen(self.landmask,\
                                      self.landSurface.actualET)

        vos.waterBalanceCheck([precipitation,surfaceWaterInf,irrGrossDemand],\
                              [actualET,runoff,nonFossilGroundwaterAbs],\
                              [storesAtBeginning],\
                              [storesAtEnd],\
                              'all modules (including water demand), but except river/routing',\
                               True,\
                               self._modelTime.fulldate,threshold=1e-3)

        
        if self.landSurface.usingAllocSegments:

            allocSurfaceWaterAbstract = \
                           pcr.ifthen(self.landmask,\
                                      self.landSurface.allocSurfaceWaterAbstract)

            allocNonFossilGroundwaterAbs = \
                           pcr.ifthen(self.landmask,\
                                      self.groundwater.allocNonFossilGroundwater)

            allocUnmetDemand = unmetDemand                           # PS: We assume that unmetDemand is extracted (only) to satisfy local demand.

            segTotalDemand = pcr.areatotal( pcr.cover((irrGrossDemand+nonIrrGrossDemand)           * self.routing.cellArea, 0.0), self.landSurface.allocSegments) / self.landSurface.segmentArea
            
            segAllocSurfaceWaterAbstract    = pcr.areatotal( pcr.cover(allocSurfaceWaterAbstract   * self.routing.cellArea, 0.0), self.landSurface.allocSegments) / self.landSurface.segmentArea

            segAllocNonFossilGroundwaterAbs = pcr.areatotal( pcr.cover(allocNonFossilGroundwaterAbs * self.routing.cellArea, 0.0), self.landSurface.allocSegments) / self.landSurface.segmentArea

            segAllocUnmetDemand             = pcr.areatotal( pcr.cover(allocUnmetDemand * self.routing.cellArea, 0.0), self.landSurface.allocSegments) / self.landSurface.segmentArea
            
            vos.waterBalanceCheck([segTotalDemand],\
                                  [segAllocSurfaceWaterAbstract,segAllocNonFossilGroundwaterAbs,segAllocUnmetDemand],\
                                  [pcr.scalar(0.0)],\
                                  [pcr.scalar(0.0)],\
                                  'Water balance error in water allocation (per zone). Note that error here is most likely due to rounding error (32 bit implementation of pcraster)',\
                                   True,\
                                   self._modelTime.fulldate,threshold=5e-3)
        else:    
            
            vos.waterBalanceCheck([irrGrossDemand,nonIrrGrossDemand],\
                                  [surfaceWaterAbstraction,nonFossilGroundwaterAbs,unmetDemand],\
                                  [pcr.scalar(0.0)],\
                                  [pcr.scalar(0.0)],\
                                  'Water balance error in water allocation.',\
                                   True,\
                                   self._modelTime.fulldate,threshold=1e-3)
Ejemplo n.º 7
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