Source code for torchMWRT.atm

from __future__ import annotations

"""Thermodynamic helper functions for atmospheric moisture variables."""

import torch

from . import consts


[docs] def saturation_vapor_pressure(T: torch.Tensor, formula: str = "magnus", ice: bool = False) -> torch.Tensor: """Compute saturation vapor pressure. Parameters ---------- T : torch.Tensor Temperature in K. formula : str, optional Saturation formula to use. Supported values are ``"magnus"`` and ``"goff_gratch"``. ice : bool, optional If ``True``, apply ice coefficients/branch where supported by the selected formula. Returns ------- torch.Tensor Saturation vapor pressure in Pa. Raises ------ ValueError If ``formula`` is not recognized. Notes ----- The Goff-Gratch helper computes in hPa and is converted to Pa in this dispatcher. """ formula_l = formula.lower() if formula_l == "magnus": return saturation_vapor_pressure_magnus(T, ice=ice) if formula_l == "goff_gratch": # goff_gratch_saturation_vapor_pressure returns hPa return goff_gratch_saturation_vapor_pressure(T, ice=ice) * 100.0 raise ValueError(f"Unknown saturation vapor pressure formula '{formula}'.")
[docs] def vapor_pressure_from_relative_humidity(T: torch.Tensor, rh: torch.Tensor, formula: str = "goff_gratch", ice: bool = False) -> torch.Tensor: """Compute vapor pressure from relative humidity. Parameters ---------- T : torch.Tensor Temperature in K. rh : torch.Tensor Relative humidity as a fraction (0-1). formula : str, optional Saturation-vapor-pressure formula passed to :func:`saturation_vapor_pressure`. ice : bool, optional Ice handling flag passed to :func:`saturation_vapor_pressure`. Returns ------- torch.Tensor Vapor pressure in Pa. """ return rh * saturation_vapor_pressure(T, formula=formula, ice=ice)
[docs] def goff_gratch_saturation_vapor_pressure(T: torch.Tensor, ice: bool = False) -> torch.Tensor: """Compute saturation vapor pressure using the Goff-Gratch formula. Parameters ---------- T : torch.Tensor Temperature in K. ice : bool, optional If ``True``, apply the ice branch below 263.16 K, matching legacy behavior. Returns ------- torch.Tensor Saturation vapor pressure in hPa. Notes ----- This implementation mirrors the legacy pyrtlib ``RTEquation.vapor`` formulation. """ y = 373.16 / T es = ( -7.90298 * (y - 1.0) + 5.02808 * torch.log10(y) - 1.3816e-07 * (torch.pow(10.0, 11.344 * (1.0 - (1.0 / y))) - 1.0) + 0.0081328 * (torch.pow(10.0, -3.49149 * (y - 1.0)) - 1.0) + torch.log10(torch.tensor(1013.246, dtype=T.dtype, device=T.device)) ) if ice: indx = torch.nonzero(T < 263.16, as_tuple=True) y = 273.16 / T[indx] es[indx] = ( -9.09718 * (y - 1.0) - 3.56654 * torch.log10(y) + 0.876793 * (1.0 - (1.0 / y)) + torch.log10(torch.tensor(6.1071, dtype=T.dtype, device=T.device)) ) return torch.pow(10.0, es)
[docs] def saturation_vapor_pressure_magnus(T: torch.Tensor, ice: bool = False) -> torch.Tensor: """Compute saturation vapor pressure using a Magnus-type formula. Parameters ---------- T : torch.Tensor Temperature in K. ice : bool, optional If ``True``, use ice coefficients ``a=22.46`` and ``b=272.62``. Otherwise use water coefficients ``a=17.62`` and ``b=243.12``. Returns ------- torch.Tensor Saturation vapor pressure in Pa. """ T_c = T - consts.T_0 if ice: a = torch.tensor(22.46, device=T.device, dtype=T.dtype) b = torch.tensor(272.62, device=T.device, dtype=T.dtype) else: a = torch.tensor(17.62, device=T.device, dtype=T.dtype) b = torch.tensor(243.12, device=T.device, dtype=T.dtype) es0 = torch.tensor(611.2, device=T.device, dtype=T.dtype) return es0 * torch.exp(a * T_c / (T_c + b))
[docs] def vapor_pressure_from_specific_humidity(q: torch.Tensor, p: torch.Tensor) -> torch.Tensor: """Compute vapor pressure from specific humidity. Parameters ---------- q : torch.Tensor Specific humidity in kg/kg. p : torch.Tensor Total air pressure in Pa. Returns ------- torch.Tensor Vapor pressure in Pa. Notes ----- Uses :math:`e = q p / (\\epsilon + (1-\\epsilon)q)` with :math:`\\epsilon = R_d / R_v`. """ eps = torch.tensor(consts.eps, device=q.device, dtype=q.dtype) return q * p / (eps + (1 - eps) * q)