# -*- coding: utf-8 -*-
"""
@author: jeremy leconte
"""
import numpy as np
import numba
import exo_k.util.cst as cst
[docs]
class Condensing_species(object):
def __init__(self, Latent_heat_vaporization = 0., cp_vap = 0., Mvap = 0.,
T_ref = 0., Psat_ref = 0., cp_cond = None):
"""
Parameters
----------
Latent_heat_vaporization: float
specific Latent heat vaporization (J/kg)
cp_vap: float
Specific heat capacity of the vapor (J/kg/K)
Mvap: float
Molar mass of vapor (kg/mol)
T_ref: float
Reference temperature
Psat_ref: float
Saturation vapor pressure at the reference temperature (Pa)
cp_cond: float (optional)
Specific heat capacity of the condensate (J/kg/K).
Assumed equal to cp_vap if not provided.
"""
self.Latent_heat_vaporization = Latent_heat_vaporization
self.cp_vap = cp_vap
self.T_ref = T_ref
self.Psat_ref = Psat_ref
self.Mvap = Mvap
self.Rvap = cst.RGP / self.Mvap
if cp_cond is None:
self.cp_cond = cp_vap
else:
self.cp_cond = cp_cond
self.delta_cp = self.cp_vap - self.cp_cond
self.delta_cp_R = self.delta_cp / self.Rvap
self.LovR = self.Latent_heat_vaporization / self.Rvap
self.c1 = self.LovR / self.T_ref - self.delta_cp_R
self.c2 = self.delta_cp_R * self.T_ref - self.LovR
[docs]
def Lvap(self, T):
"""Latent heat at temperature T
Parameters
----------
T: array, np.ndarray
Temperature in layers (K)
"""
return Lvap_T(T, self.Latent_heat_vaporization, self.T_ref, self.delta_cp)
[docs]
def Psat(self, T):
"""Saturation vapor pressure for the condensing species
Parameters
----------
T: array, np.ndarray
Temperature in layers (K)
"""
return Psat_T(T, self.T_ref, self.Psat_ref, self.c1, self.c2, self.delta_cp_R)
[docs]
def Tsat(self, P):
"""Boiling temperature for the condensing species
NOT EXACT IF DELTA CP != 0.
Parameters
----------
P: array, np.ndarray
Pressure in layers (Pa)
"""
return Tsat_P(P, self.Psat_ref, self.c1, self.c2)
[docs]
def qsat(self, psat, p, epsilon):
"""Saturation vapor mass mixing ratio for the condensing species
Parameters
----------
psat: array, np.ndarray
saturation vapor pressure
p: array, np.ndarray
pressure at the layer center
epsilon: float or array
Ratio of the molar mass of the vapor over the background molar mass
"""
return Qsat(psat, p, epsilon)
[docs]
def dPsat_dT(self, T):
"""Saturation vapor pressure derivative for the condensing species
Parameters
----------
T: array, np.ndarray
Temperature in layers (K)
"""
return dPsat_dT(T, self.Latent_heat_vaporization, self.T_ref,
self.Psat_ref, self.Rvap, self.delta_cp, self.delta_cp_R, self.c1, self.c2)
[docs]
def dlnPsat_dlnT(self, T):
"""Saturation vapor pressure for the condensing species and its derivative
Parameters
----------
T: array, np.ndarray
Temperature in layers (K)
"""
return dlnPsat_dlnT(T, self.Latent_heat_vaporization, self.T_ref,
self.delta_cp, self.Rvap)
[docs]
def moist_adiabat(self, T, P, cp, Mgas):
"""Computes the threshold thermal gradient (d ln T / d ln P) for a moist atmosphere.
Parameters
----------
T: array, np.ndarray
Temperature in layers (K)
P: array, np.ndarray
pressure at the layer center
cp: float
specific heat capacity at constant pressure of the background gas
Mgas: float or array
Molar mass of the background atmosphere
Returns
-------
array
Moist adiabat lapse rate
Lvap: array, np.ndarray
Latent heat at temperature T
psat: array, np.ndarray
Saturation vapor pressure for the condensing species (Pa)
qsat: array, np.ndarray
Saturation vapor mass mixing ratio for the condensing species
dqsat_dt: array, np.ndarray
Derivative of qsat with respect to temperature at fixed pressure
q_crit: array, np.ndarray
Critical mass mixing ratio for the inhibition of moist convection
(Eq. 17 of Leconte et al. 2017)
"""
return moist_adiabat(T, P, cp, Mgas, self.cp_vap, self.Mvap, self.Rvap,
self.Latent_heat_vaporization, self.T_ref, self.Psat_ref,
self.delta_cp, self.delta_cp_R, self.c1, self.c2)
[docs]
def compute_condensation_parameters(self, T, P, Mgas):
"""Computes necessary quantities to compute
large scale condensation.
Parameters
----------
T: array, np.ndarray
Temperature in layers (K)
P: array, np.ndarray
pressure at the layer center
Mgas: float or array
Molar mass of the background atmosphere
"""
return compute_condensation_parameters(T, P, Mgas, self.Mvap,
self.Rvap, self.Latent_heat_vaporization, self.T_ref,
self.Psat_ref, self.delta_cp, self.delta_cp_R, self.c1, self.c2)
def __repr__(self):
"""Method to output parameters
"""
output="""
Lvap : {lvap}
cp (vap) : {cp}
T0 (K): {t0}
Psat(T0) (Pa): {p0}""".format(lvap=self.Latent_heat_vaporization,
cp=self.cp_vap, t0=self.T_ref, p0=self.Psat_ref)
return output
[docs]
class Condensation_Thermodynamical_Parameters(object):
def __init__(self, Latent_heat_vaporization = 0., cp_vap = 0., Mvap = 0.,
T_ref = 0., Psat_ref = 0., cp_cond = None):
"""
Parameters
----------
Latent_heat_vaporization: float
specific Latent heat vaporization (J/kg)
cp_vap: float
Specific heat capacity of the vapor (J/kg/K)
Mvap: float
Molar mass of vapor (kg/mol)
T_ref: float
Reference temperature
Psat_ref: float
Saturation vapor pressure at the reference temperature (Pa)
cp_cond: float (optional)
Specific heat capacity of the condensate (J/kg/K).
Assumed equal to cp_vap if not provided.
"""
Rvap = cst.RGP / Mvap
if cp_cond is None:
cp_cond = cp_vap
else:
cp_cond = cp_cond
delta_cp = cp_vap - cp_cond
delta_cp_R = delta_cp / Rvap
LovR = Latent_heat_vaporization / Rvap
c1 = LovR / T_ref - delta_cp_R
c2 = delta_cp_R * T_ref - LovR
self.th_params = np.array([cp_vap, Mvap, Rvap,
Latent_heat_vaporization, T_ref, Psat_ref,
delta_cp, delta_cp_R, c1, c2])
[docs]
@numba.jit(nopython=True, fastmath=True, cache=True)
def Lvap_T(T, Latent_heat_vaporization, T_ref, delta_cp):
"""Latent heat at temperature T
Parameters
----------
T: array, np.ndarray
Temperature in layers (K)
"""
return Latent_heat_vaporization + delta_cp * (T-T_ref)
[docs]
@numba.jit(nopython=True, fastmath=True, cache=True)
def Psat_T(T, T_ref, Psat_ref, c1, c2, delta_cp_R):
"""Saturation vapor pressure for the condensing species
Parameters
----------
T: array, np.ndarray
Temperature in layers (K)
"""
return Psat_ref*np.exp( c1 + c2/T + delta_cp_R*np.log(T/T_ref))
[docs]
@numba.jit(nopython=True, fastmath=True, cache=True)
def Tsat_P(P, Psat_ref, c1, c2):
"""Boiling temperature for the condensing species
NOT EXACT IF DELTA CP != 0.
Parameters
----------
P: array, np.ndarray
Pressure in layers (Pa)
"""
return c2/(np.log(P/Psat_ref)-c1)
[docs]
@numba.jit(nopython=True, fastmath=True, cache=True)
def Qsat(psat, p, epsilon):
"""Saturation vapor mass mixing ratio for the condensing species
Parameters
----------
psat: array, np.ndarray
saturation vapor pressure
p: array, np.ndarray
pressure at the layer center
epsilon: float or array
Ratio of the molar mass of the vapor over the background molar mass
"""
psat_tmp = np.core.umath.minimum(psat,p)
fac = p + (epsilon -1.) * psat_tmp
qsat = epsilon * psat_tmp / fac
return qsat
[docs]
@numba.jit(nopython=True, fastmath=True, cache=True)
def dPsat_dT(T, Latent_heat_vaporization, T_ref, Psat_ref, Rvap, delta_cp, delta_cp_R, c1, c2):
"""Saturation vapor pressure derivative for the condensing species
Parameters
----------
T: array, np.ndarray
Temperature in layers (K)
"""
RT2 = Rvap * T * T
Lvap = Lvap_T(T, Latent_heat_vaporization, T_ref, delta_cp)
psat = Psat_T(T, T_ref, Psat_ref, c1, c2, delta_cp_R)
return psat * Lvap / RT2, psat, Lvap
[docs]
@numba.jit(nopython=True, fastmath=True, cache=True)
def dlnPsat_dlnT(T, Latent_heat_vaporization, T_ref, delta_cp, Rvap):
"""Saturation vapor pressure for the condensing species and its derivative
Parameters
----------
T: array, np.ndarray
Temperature in layers (K)
"""
RT = Rvap * T
Lvap = Lvap_T(T, Latent_heat_vaporization, T_ref, delta_cp)
return Lvap / RT, Lvap
[docs]
@numba.jit(nopython=True, fastmath=True, cache=True)
def moist_adiabat(T, P, cp, Mgas, cp_vap, Mvap, Rvap, Latent_heat_vaporization, T_ref, Psat_ref, delta_cp, delta_cp_R, c1, c2):
"""Computes the threshold thermal gradient (d ln T / d ln P) for a moist atmosphere.
Parameters
----------
T: array, np.ndarray
Temperature in layers (K)
P: array, np.ndarray
pressure at the layer center
cp: float
specific heat capacity at constant pressure of the background gas
Mgas: float or array
Molar mass of the background atmosphere
Returns
-------
array
Moist adiabat lapse rate
Lvap: array, np.ndarray
Latent heat at temperature T
psat: array, np.ndarray
Saturation vapor pressure for the condensing species (Pa)
qsat: array, np.ndarray
Saturation vapor mass mixing ratio for the condensing species
dqsat_dt: array, np.ndarray
Derivative of qsat with respect to temperature at fixed pressure
q_crit: array, np.ndarray
Critical mass mixing ratio for the inhibition of moist convection
(Eq. 17 of Leconte et al. 2017)
"""
epsilon = Mvap / Mgas
psat = Psat_T(T, T_ref, Psat_ref, c1, c2, delta_cp_R)
qsat = Qsat(psat, P, epsilon)
dlpsat_dlT, Lvap = dlnPsat_dlnT(T, Latent_heat_vaporization, T_ref, delta_cp, Rvap)
dqsat_dt = qsat**2 * P * dlpsat_dlT / (epsilon*psat*T)
qa=1.-qsat
qLvt = qsat * Lvap / T
fac = qsat * cp_vap + qa * cp + qLvt * dlpsat_dlT
q_crit = epsilon / ((epsilon - 1.) * dlpsat_dlT)
return ( (1.-qsat) * cst.RGP / Mgas + qLvt ) / fac, Lvap, psat, qsat, dqsat_dt, q_crit # is missing p/p_a terms
[docs]
@numba.jit(nopython=True, fastmath=True, cache=True)
def compute_condensation_parameters(T, P, Mgas, Mvap, Rvap, Latent_heat_vaporization, T_ref, Psat_ref, delta_cp, delta_cp_R, c1, c2):
"""Computes necessary quantities to compute
large scale condensation.
Parameters
----------
T: array, np.ndarray
Temperature in layers (K)
P: array, np.ndarray
pressure at the layer center
Mgas: float or array
Molar mass of the background atmosphere
"""
epsilon = Mvap / Mgas
psat = Psat_T(T, T_ref, Psat_ref, c1, c2, delta_cp_R)
qsat = Qsat(psat, P, epsilon)
dlpsat_dlT, Lvap = dlnPsat_dlnT(T, Latent_heat_vaporization, T_ref, delta_cp, Rvap)
dqsat_dt = qsat**2 * P * dlpsat_dlT / (epsilon*psat*T)
return Lvap, qsat, dqsat_dt