Source code for cwatm.hydrological_modules.water_demand.irrigation

# -------------------------------------------------------------------------
# Name:        Waterdemand modules
# Purpose:
#
# Author:      PB, YS, MS, JdB
#
# Created:     15/07/2016
# Copyright:   (c) PB 2016
# -------------------------------------------------------------------------

from cwatm.management_modules import globals
from cwatm.management_modules.data_handling import returnBool, binding, cbinding, loadmap
import numpy as np


# from cwatm.management_modules.data_handling import *  # luca for testing
# import matplotlib.pyplot as plt


# def decompress(map, nanvalue=None):
#    """
#    Decompressing CWatM maps from 1D to 2D with missing values
#
#    :param map: compressed map
#    :return: decompressed 2D map
#    """
#
#    dmap = maskinfo['maskall'].copy()
#    dmap[~maskinfo['maskflat']] = map[:]
#    if nanvalue is not None:
#        dmap.data[np.isnan(dmap.data)] = nanvalue
#
#    return dmap.data

[docs]class waterdemand_irrigation: """ WATERDEMAND calculating water demand - irrigation Agricultural water demand based on water need by plants **Global variables** ===================================== ====================================================================== ===== Variable [self.var] Description Unit ===================================== ====================================================================== ===== load_initial Settings initLoad holds initial conditions for variables input cropKC crop coefficient for each of the 4 different land cover types (forest, -- topwater quantity of water above the soil (flooding) m efficiencyPaddy Input, irrPaddy_efficiency, paddy irrigation efficiency, the amount of frac efficiencyNonpaddy Input, irrNonPaddy_efficiency, non-paddy irrigation efficiency, the am frac returnfractionIrr Input, irrigation_returnfraction, the fraction of non-efficient water frac alphaDepletion Input, alphaDepletion, irrigation aims to alphaDepletion of field capa frac minimum_irrigation Cover-specific irrigation in metres is 0 if less than this, currently 1/m2 pot_irrConsumption Cover-specific potential irrigation consumption m/m fraction_IncreaseIrrigation_Nonpaddy Input, fraction_IncreaseIrrigation_Nonpaddy, scales pot_irrConsumption frac irrPaddyDemand Paddy irrigation demand m availWaterInfiltration quantity of water reaching the soil after interception, more snowmelt m ws1 Maximum storage capacity in layer 1 m ws2 Maximum storage capacity in layer 2 m wfc1 Soil moisture at field capacity in layer 1 -- wfc2 Soil moisture at field capacity in layer 2 -- wwp1 Soil moisture at wilting point in layer 1 -- wwp2 Soil moisture at wilting point in layer 2 -- arnoBeta -- maxtopwater maximum heigth of topwater m totAvlWater Field capacity minus wilting point in soil layers 1 and 2 m InvCellArea Inverse of cell area of each simulated mesh 1/m2 totalPotET Potential evaporation per land use class m w1 Simulated water storage in the layer 1 m w2 Simulated water storage in the layer 2 m fracVegCover Fraction of specific land covers (0=forest, 1=grasslands, etc.) % unmetDemand Unmet groundwater demand to determine potential fossil groundwaterwate m unmetDemandPaddy Unmet paddy demand m unmetDemandNonpaddy Unmet nonpaddy demand m irrDemand Cover-specific Irrigation demand m/m irrNonpaddyDemand -- totalIrrDemand Irrigation demand m ===================================== ====================================================================== ===== **Functions** """ def __init__(self, model): self.var = model.var self.model = model
[docs] def initial(self): """ Initial part of the water demand module irrigation """ # init unmetWaterDemand -> to calculate actual one the the unmet water demand from previous day is needed self.var.unmetDemandPaddy = self.var.load_initial('unmetDemandPaddy', default=globals.inZero.copy()) self.var.unmetDemandNonpaddy = self.var.load_initial('unmetDemandNonpaddy', default=globals.inZero.copy()) # in case fossil water abstraction is allowed this will be filled self.var.unmetDemand = globals.inZero.copy() # irrigation efficiency # at the moment a single map, but will be replaced by map stack for every year self.var.efficiencyPaddy = loadmap("irrPaddy_efficiency") self.var.efficiencyNonpaddy = loadmap("irrNonPaddy_efficiency") self.var.returnfractionIrr = loadmap("irrigation_returnfraction") # for Xiaogang's agent model if "alphaDepletion" in binding: self.var.alphaDepletion = loadmap('alphaDepletion') else: self.var.alphaDepletion = 0.7 # ignore demand if less than self.var.minimum_irrigation #1 m3 self.var.minimum_irrigation = self.var.InvCellArea
# print('=> If irrigation demand is smaller than ', np.nanmean(self.var.minimum_irrigation), ' m/day, the demand is set to zero')
[docs] def dynamic(self): """ Dynamic part of the water demand module * calculate the fraction of water from surface water vs. groundwater * get non-Irrigation water demand and its return flow fraction """ # Paddy irrigation -> No = 2 # Non paddy irrigation -> No = 3 # irrigation water demand for paddy No = 2 # a function of cropKC (evaporation and transpiration) and available water see Wada et al. 2014 p. 19 self.var.pot_irrConsumption[No] = np.where( self.var.cropKC[No] > 0.75, np.maximum(0., (self.var.alphaDepletion * self.var.maxtopwater - ( self.var.topwater + self.var.availWaterInfiltration[No]))), 0. ) # ignore demand if less than 1 m3 self.var.pot_irrConsumption[No] = np.where(self.var.pot_irrConsumption[No] > self.var.InvCellArea, self.var.pot_irrConsumption[No], 0) self.var.irrDemand[No] = self.var.pot_irrConsumption[No] / self.var.efficiencyPaddy # ----------------- # irrNonPaddy No = 3 # Infiltration capacity # ======================================== # first 2 soil layers to estimate distribution between runoff and infiltration soilWaterStorage = self.var.w1[No] + self.var.w2[No] soilWaterStorageCap = self.var.ws1[No] + self.var.ws2[No] relSat = soilWaterStorage / soilWaterStorageCap satAreaFrac = 1 - (1 - relSat) ** self.var.arnoBeta[No] satAreaFrac = np.maximum(np.minimum(satAreaFrac, 1.0), 0.0) store = soilWaterStorageCap / (self.var.arnoBeta[No] + 1) potBeta = (self.var.arnoBeta[No] + 1) / self.var.arnoBeta[No] potInf = store - store * (1 - (1 - satAreaFrac) ** potBeta) # ---------------------------------------------------------- availWaterPlant1 = np.maximum(0., self.var.w1[No] - self.var.wwp1[ No]) # * self.var.rootDepth[0][No] should not be multiplied again with soildepth availWaterPlant2 = np.maximum(0., self.var.w2[No] - self.var.wwp2[No]) # * self.var.rootDepth[1][No] # availWaterPlant3 = np.maximum(0., self.var.w3[No] - self.var.wwp3[No]) #* self.var.rootDepth[2][No] readAvlWater = availWaterPlant1 + availWaterPlant2 # + availWaterPlant3 # calculate ****** SOIL WATER STRESS ************************************ # The crop group number is a indicator of adaptation to dry climate, # e.g. olive groves are adapted to dry climate, therefore they can extract more water from drying out soil than e.g. rice. # The crop group number of olive groves is 4 and of rice fields is 1 # for irrigation it is expected that the crop has a low adaptation to dry climate # cropGroupNumber = 1.0 etpotMax = np.minimum(0.1 * (self.var.totalPotET[No] * 1000.), 1.0) # print('-----------------------------etpotMax---------: ', np.sum(etpotMax * self.var.cellArea)) # to avoid a strange behaviour of the p-formula's, ETRef is set to a maximum of 10 mm/day. # for group number 1 -> those are plants which needs irrigation # p = 1 / (0.76 + 1.5 * np.minimum(0.1 * (self.var.totalPotET[No] * 1000.), 1.0)) - 0.10 * ( 5 - cropGroupNumber) p = 1 / (0.76 + 1.5 * etpotMax) - 0.4 # soil water depletion fraction (easily available soil water) # Van Diepen et al., 1988: WOFOST 6.0, p.87. p = p + (etpotMax - 0.6) / 4 # correction for crop group 1 (Van Diepen et al, 1988) -> p between 0.14 - 0.77 p = np.maximum(np.minimum(p, 1.0), 0.) # p is between 0 and 1 => if p =1 wcrit = wwp, if p= 0 wcrit = wfc # p is closer to 0 if evapo is bigger and cropgroup is smaller wCrit1 = ((1 - p) * (self.var.wfc1[No] - self.var.wwp1[No])) + self.var.wwp1[No] wCrit2 = ((1 - p) * (self.var.wfc2[No] - self.var.wwp2[No])) + self.var.wwp2[No] # wCrit3 = ((1 - p) * (self.var.wfc3[No] - self.var.wwp3[No])) + self.var.wwp3[No] critWaterPlant1 = np.maximum(0., wCrit1 - self.var.wwp1[No]) # * self.var.rootDepth[0][No] critWaterPlant2 = np.maximum(0., wCrit2 - self.var.wwp2[No]) # * self.var.rootDepth[1][No] # critWaterPlant3 = np.maximum(0., wCrit3 - self.var.wwp3[No]) # * self.var.rootDepth[2][No] critAvlWater = critWaterPlant1 + critWaterPlant2 # + critWaterPlant3 # with alpha from Xiaogang He, to adjust irrigation to farmer's need self.var.pot_irrConsumption[No] = np.where(self.var.cropKC[No] > 0.20, np.where(readAvlWater < (self.var.alphaDepletion * critAvlWater), np.maximum(0.0, self.var.alphaDepletion * self.var.totAvlWater - readAvlWater), 0.), 0.) if "fraction_IncreaseIrrigation_Nonpaddy" in binding: self.var.fraction_IncreaseIrrigation_Nonpaddy = loadmap( 'fraction_IncreaseIrrigation_Nonpaddy') + globals.inZero.copy() self.var.pot_irrConsumption[No] *= self.var.fraction_IncreaseIrrigation_Nonpaddy # should not be bigger than infiltration capacity self.var.pot_irrConsumption[No] = np.minimum(self.var.pot_irrConsumption[No], potInf) # ignore demand if less than self.var.minimum_irrigation self.var.pot_irrConsumption[No] = np.where(self.var.pot_irrConsumption[No] > self.var.minimum_irrigation, self.var.pot_irrConsumption[No], 0) self.var.irrDemand[No] = self.var.pot_irrConsumption[No] / self.var.efficiencyNonpaddy # Sum up irrigation water demand with area fraction self.var.irrNonpaddyDemand = self.var.fracVegCover[3] * self.var.irrDemand[3] self.var.irrPaddyDemand = self.var.fracVegCover[2] * self.var.irrDemand[2] self.var.totalIrrDemand = self.var.irrPaddyDemand + self.var.irrNonpaddyDemand