Source code for abcmodel.land.jarvis_stewart

from dataclasses import dataclass

import jax.numpy as jnp
from jax import Array

from ..abstracts import AbstractCoupledState
from .standard import (
    AbstractStandardLandModel,
    StandardLandState,
)


[docs] @dataclass class JarvisStewartState(StandardLandState): """Jarvis-Stewart model state."""
[docs] class JarvisStewartModel(AbstractStandardLandModel): """Jarvis-Stewart land surface model with empirical surface resistance. Args: **kwargs: additional keyword arguments to pass to the base class. """ def __init__(self, **kwargs): super().__init__(**kwargs)
[docs] def init_state( self, alpha: float = 0.25, wg: float = 0.21, temp_soil: float = 285.0, temp2: float = 286.0, surf_temp: float = 290.0, wl: float = 0.0000, wq: float = 1e-4, wtheta: float = 0.1, rs: float = 1.0e6, rssoil: float = 1.0e6, ) -> JarvisStewartState: """Initialize the model state. Args: alpha: albedo [-]. Default is 0.25. wg: Volumetric soil moisture [m3 m-3]. Default is 0.21. temp_soil: Soil temperature [K]. Default is 285.0. temp2: Deep soil temperature [K]. Default is 286.0. surf_temp: Surface temperature [K]. Default is 290.0. wl: Canopy water content [m]. Default is 0.0000. wq: Kinematic moisture flux [kg/kg m/s]. Default is 1e-4. wtheta: Kinematic heat flux [K m/s]. Default is 0.1. rs: Surface resistance [s m-1]. Default is 1.0e6. rssoil: Soil resistance [s m-1]. Default is 1.0e6. Returns: The initial land state. """ return JarvisStewartState( alpha=jnp.array(alpha), wg=jnp.array(wg), temp_soil=jnp.array(temp_soil), temp2=jnp.array(temp2), surf_temp=jnp.array(surf_temp), wl=jnp.array(wl), wq=jnp.array(wq), wtheta=jnp.array(wtheta), rs=jnp.array(rs), rssoil=jnp.array(rssoil), )
[docs] def update_surface_resistance( self, state: AbstractCoupledState, ) -> AbstractCoupledState: """Update the surface resistance ``rs`` in the state using the Jarvis-Stewart model. Args: state: CoupledState. Returns: CoupledState (with updated land component). """ f1 = self.compute_f1(state.in_srad) f2 = self.compute_f2(state.land.wg) f3 = self.compute_f3(state.land.esat, state.land.e) f4 = self.compute_f4(state.atmos.theta) rs = self.rsmin / self.lai * f1 * f2 * f3 * f4 landstate = state.land.replace(rs=rs) state = state.replace(land=landstate) return state
[docs] def compute_f1(self, in_srad: Array) -> Array: """Compute rad factor f1.""" ratio = (0.004 * in_srad + 0.05) / (0.81 * (0.004 * in_srad + 1.0)) f1 = 1.0 / jnp.minimum(1.0, ratio) return f1
[docs] def compute_f2(self, wg: Array) -> Array: """Compute soil moisture factor f2.""" f2 = jnp.where( self.w2 > self.wwilt, (self.wfc - self.wwilt) / (wg - self.wwilt), 1.0e8, ) assert isinstance(f2, jnp.ndarray) f2 = jnp.maximum(f2, 1.0) return f2
[docs] def compute_f3(self, esat: Array, e: Array) -> Array: """Compute VPD factor f3.""" vpd = esat - e f3 = 1.0 / jnp.exp(-self.gD * vpd / 100.0) return f3
[docs] def compute_f4(self, theta: Array) -> Array: """Compute temperature factor f4.""" f4 = 1.0 / (1.0 - 0.0016 * (298.0 - theta) ** 2.0) return f4
[docs] def update_co2_flux( self, state: AbstractCoupledState, ) -> AbstractCoupledState: """No CO2 flux is computed using this model. See :class:`~abcmodel.land.ags.AgsModel`.""" return state