Source code for abcmodel.land.standard

from dataclasses import dataclass, replace
from typing import Generic

from jax import Array

from ..abstracts import (
    AbstractCoupledState,
    AbstractLandModel,
    AbstractLandState,
)
from .abstracts import (
    AbstractBiosphereModel,
    AbstractSoilModel,
    AbstractSurfaceModel,
    BiosphereT,
    SoilT,
    SurfaceT,
)


[docs] @dataclass class StandardLandState(AbstractLandState, Generic[BiosphereT, SoilT, SurfaceT]): """Standard land surface model state aggregating biosphere, soil, and surface.""" biosphere: BiosphereT soil: SoilT surface: SurfaceT @property def alpha(self) -> Array: """Surface albedo [-], range 0 to 1.""" return self.surface.alpha @property def surf_temp(self) -> Array: """Surface temperature [K].""" return self.surface.surf_temp @property def rs(self) -> Array: """Surface resistance [s m-1].""" return self.biosphere.rs @property def wg(self) -> Array: """Ground water storage [m].""" return self.soil.wg @property def wl(self) -> Array: """Land water storage [m].""" return self.biosphere.wl @property def esat(self) -> Array: """Saturation vapor pressure [Pa].""" return self.surface.esat @property def qsat(self) -> Array: """Saturation specific humidity [kg kg-1].""" return self.surface.qsat @property def dqsatdT(self) -> Array: """Derivative of saturation specific humidity with respect to temperature [kg kg-1 K-1].""" return self.surface.dqsatdT @property def e(self) -> Array: """Vapor pressure [Pa].""" return self.surface.e @property def qsatsurf(self) -> Array: """Saturation specific humidity at the surface [kg kg-1].""" return self.surface.qsatsurf @property def wtheta(self) -> Array: """Kinematic heat flux [K m/s].""" return self.surface.wtheta @property def wq(self) -> Array: """Kinematic moisture flux [kg kg-1 m/s].""" return self.surface.wq @property def wCO2(self) -> Array: """Kinematic CO2 flux [kg m/s].""" return self.biosphere.wCO2
[docs] class StandardLandModel(AbstractLandModel[StandardLandState]): """Standard land model coordinating biosphere, soil, and surface models.""" def __init__( self, biosphere: AbstractBiosphereModel, soil: AbstractSoilModel, surface: AbstractSurfaceModel, ): self.biosphere = biosphere self.soil = soil self.surface = surface
[docs] def init_state( self, biosphere_state: BiosphereT, soil_state: SoilT, surface_state: SurfaceT, ) -> StandardLandState[BiosphereT, SoilT, SurfaceT]: """Initialize standard land state.""" return StandardLandState( biosphere=biosphere_state, soil=soil_state, surface=surface_state, )
[docs] def run(self, state: AbstractCoupledState) -> StandardLandState: """Run standard land components sequentially. Execution order: 1. biosphere diagnostics 2. soil diagnostics 3. surface fluxes and surf_temp 4. biosphere tendencies 5. soil tendencies """ # biosphere bio_state = self.biosphere.run(state) land_state = replace(state.land, biosphere=bio_state) state = state.replace(land=land_state) # soil soil_state = self.soil.run(state) land_state = replace(land_state, soil=soil_state) state = state.replace(land=land_state) # surface surf_state = self.surface.run(state) land_state = replace(land_state, surface=surf_state) state = state.replace(land=land_state) # tendencies (require surface fluxes computed above) bio_state = self.biosphere.run_tends(bio_state, surf_state) soil_state = self.soil.run_tends(soil_state, surf_state) return StandardLandState( biosphere=bio_state, soil=soil_state, surface=surf_state, )
[docs] def integrate(self, state: StandardLandState, dt: float) -> StandardLandState: """Integrate biosphere, soil, and surface states forward in time.""" biosphere = self.biosphere.integrate(state.biosphere, dt) soil = self.soil.integrate(state.soil, dt) surface = self.surface.integrate(state.surface, dt) return replace( state, biosphere=biosphere, soil=soil, surface=surface, )