Source code for canopy
# -*- coding: utf-8 -*-
# =============================================================================
# This file is part of WaterGAP.
# WaterGAP is an opensource software which computes water flows and storages as
# well as water withdrawals and consumptive uses on all continents.
# You should have received a copy of the LGPLv3 License along with WaterGAP.
# if not see <https://www.gnu.org/licenses/lgpl-3.0>
# =============================================================================
"""Canopy storage."""
# =============================================================================
# This modules computes the canopy water balance, including canopy storage and
# water flows entering and leaving the canopy storage.
# Based on section 4.2 of (Müller Schmied et al. (2021)).
# =============================================================================
import numpy as np
from numba import njit
[docs]
@njit(cache=True)
def canopy_water_balance(canopy_storage, daily_leaf_area_index, potential_evap,
precipitation, current_landarea_frac, landareafrac_ratio,
max_storage_coefficient, minstorage_volume, x, y):
"""
Calulate daily canopy balance including canopy storage and water flows
entering and leaving the canopy storage.
Parameters
----------
canopy_storage : float
Daily canopy storage, Units: [mm]
daily_leaf_area_index : float
Daily leaf area index Units: [-]
potential_evap : float
Daily potential evapotranspiration, Units: [mm/day]
precipitation : float
Daily precipitation, Units: [mm/day]
current_landarea_frac : float
Land area fraction of current time step, Units: [-]
landareafrac_ratio : float
Ratio of land area fraction of previous to current time step, Units: [-]
max_storage_coefficient:
coefficient for computing maximum canopy storage, Units: [-]
minstorage_volume: float
Volumes at which storage is set to zero, units: [km3]
Returns
-------
canopy_storage : float
Updated daily canopy storage, Units: [mm]
throughfall : float
Throughfall, Units: [mm/day]
canopy_evap : float
Canopy evaporation, Units: [mm/day]
pet_to_soil : float
Remaining energy for addtional soil evaporation, Units: [mm/day]
land_storage_change_sum : float
Sum of change in vertical balance storages, Units: [mm]
daily_storage_transfer : float
Storage to be transfered to runoff when land area fraction of current
time step is zero, Units: [mm]
"""
if current_landarea_frac > 0:
# =========================================================
# Adapt for change in land area fraction on canopy storage
# =========================================================
canopy_storage *= landareafrac_ratio
# minimal storage volume =1e15 (smaller volumes set to zero) to counter
# numerical inaccuracies
if np.abs(canopy_storage) <= minstorage_volume:
canopy_storage = 0
# Initial storage to calulate change in canopy_storage.
initial_storage = canopy_storage
if daily_leaf_area_index > 0:
# =================================================================
# Calculating maxumum storage and canopy storage deficit (mm)
# =================================================================
# See Eq. 4 in Müller Schmied et al 2021. for maximum storage
# equation
max_canopy_storage = max_storage_coefficient * daily_leaf_area_index
canopy_storage_difference = max_canopy_storage - canopy_storage
# =================================================================
# Calculating throughfall (mm/day) and canopy storage (mm)
# ================================================================
# See Eq. 3 in Müller Schmied et al 2021. for throughfall equation
if precipitation < canopy_storage_difference:
throughfall = 0
canopy_storage += precipitation
else:
throughfall = precipitation - canopy_storage_difference
canopy_storage = max_canopy_storage
# =================================================================
# Calculating Canopy Evaporation (mm/day)
# =================================================================
# Check non zero division for canopy_storage and max_canopy_storage
# required for canopy evaporation
if max_canopy_storage > 0:
canopy_evap = potential_evap * \
(canopy_storage / max_canopy_storage)**(2 / 3)
else:
canopy_evap = 0
if canopy_evap > canopy_storage:
canopy_evap = canopy_storage
# Note!!! not all PET is used for canopy evaporation.
# Part goes to the soil which is the variable pet_to_soil.
pet_to_soil = potential_evap - canopy_storage
canopy_storage = 0
else:
canopy_storage -= canopy_evap
pet_to_soil = potential_evap - canopy_evap
else:
throughfall = precipitation
pet_to_soil = potential_evap
canopy_evap = 0
# Computing change in canopy storage
canopy_storage_change = canopy_storage - initial_storage
# land_storage_change_sum variable is the sum of all vertical water
# balance storage change (canopy, snow, soil):
# used for AET correction. see soil.py module
land_storage_change_sum = canopy_storage_change
else:
# =========================================================================
# Check if current_landarea_frac == 0 , then add previous storage to
# daily_storage_tranfer. This storage will then be added to runoff.
# (e.g. island)
# =========================================================================
daily_storage_transfer = canopy_storage
canopy_storage = 0
canopy_evap = 0
if pet_to_soil < 0:
pet_to_soil = 0
return canopy_storage, throughfall, canopy_evap, pet_to_soil, \
land_storage_change_sum, daily_storage_transfer