Module PySDM.environments.parcel
Zero-dimensional adiabatic parcel framework
Expand source code
"""
Zero-dimensional adiabatic parcel framework
"""
import numpy as np
from PySDM.environments.impl.moist import Moist
from PySDM.impl.mesh import Mesh
from PySDM.initialisation.equilibrate_wet_radii import (
default_rtol,
equilibrate_wet_radii,
)
class Parcel(Moist): # pylint: disable=too-many-instance-attributes
def __init__(
self,
*,
dt,
mass_of_dry_air: float,
p0: float,
initial_water_vapour_mixing_ratio: float,
T0: float,
w: [float, callable],
z0: float = 0,
mixed_phase=False,
):
super().__init__(
dt, Mesh.mesh_0d(), ["rhod", "z", "t"], mixed_phase=mixed_phase
)
self.p0 = p0
self.initial_water_vapour_mixing_ratio = initial_water_vapour_mixing_ratio
self.T0 = T0
self.z0 = z0
self.mass_of_dry_air = mass_of_dry_air
self.w = w if callable(w) else lambda _: w
self.formulae = None
self.delta_liquid_water_mixing_ratio = None
self.params = None
@property
def dv(self):
rhod_mean = (self.get_predicted("rhod")[0] + self["rhod"][0]) / 2
return self.formulae.trivia.volume_of_density_mass(
rhod_mean, self.mass_of_dry_air
)
def register(self, builder):
self.formulae = builder.particulator.formulae
pd0 = self.formulae.trivia.p_d(self.p0, self.initial_water_vapour_mixing_ratio)
rhod0 = self.formulae.state_variable_triplet.rhod_of_pd_T(pd0, self.T0)
self.mesh.dv = self.formulae.trivia.volume_of_density_mass(
rhod0, self.mass_of_dry_air
)
Moist.register(self, builder)
params = (
self.initial_water_vapour_mixing_ratio,
self.formulae.trivia.th_std(pd0, self.T0),
rhod0,
self.z0,
0,
)
self["water_vapour_mixing_ratio"][:] = params[0]
self["thd"][:] = params[1]
self["rhod"][:] = params[2]
self["z"][:] = params[3]
self["t"][:] = params[4]
self._tmp["water_vapour_mixing_ratio"][:] = params[0]
self.sync_parcel_vars()
Moist.sync(self)
self.notify()
def init_attributes(
self,
*,
n_in_dv: [float, np.ndarray],
kappa: float,
r_dry: [float, np.ndarray],
rtol=default_rtol,
include_dry_volume_in_attribute: bool = True,
):
if not isinstance(n_in_dv, np.ndarray):
r_dry = np.array([r_dry])
n_in_dv = np.array([n_in_dv])
attributes = {}
dry_volume = self.formulae.trivia.volume(radius=r_dry)
attributes["kappa times dry volume"] = dry_volume * kappa
attributes["multiplicity"] = n_in_dv
r_wet = equilibrate_wet_radii(
r_dry=r_dry,
environment=self,
kappa_times_dry_volume=attributes["kappa times dry volume"],
rtol=rtol,
)
attributes["volume"] = self.formulae.trivia.volume(radius=r_wet)
if include_dry_volume_in_attribute:
attributes["dry volume"] = dry_volume
return attributes
def advance_parcel_vars(self):
dt = self.particulator.dt
T = self["T"][0]
p = self["p"][0]
t = self["t"][0]
dz_dt = self.w(t + dt / 2) # "mid-point"
water_vapour_mixing_ratio = (
self["water_vapour_mixing_ratio"][0]
- self.delta_liquid_water_mixing_ratio / 2
)
drho_dz = self.formulae.hydrostatics.drho_dz(
g=self.formulae.constants.g_std,
p=p,
T=T,
water_vapour_mixing_ratio=water_vapour_mixing_ratio,
lv=self.formulae.latent_heat.lv(T),
d_liquid_water_mixing_ratio__dz=(
self.delta_liquid_water_mixing_ratio / dz_dt / dt
),
)
drhod_dz = drho_dz
self.particulator.backend.explicit_euler(self._tmp["t"], dt, 1)
self.particulator.backend.explicit_euler(self._tmp["z"], dt, dz_dt)
self.particulator.backend.explicit_euler(
self._tmp["rhod"], dt, dz_dt * drhod_dz
)
self.mesh.dv = self.formulae.trivia.volume_of_density_mass(
(self._tmp["rhod"][0] + self["rhod"][0]) / 2, self.mass_of_dry_air
)
def get_thd(self):
return self["thd"]
def get_water_vapour_mixing_ratio(self):
return self["water_vapour_mixing_ratio"]
def sync_parcel_vars(self):
self.delta_liquid_water_mixing_ratio = (
self._tmp["water_vapour_mixing_ratio"][0]
- self["water_vapour_mixing_ratio"][0]
)
for var in self.variables:
self._tmp[var][:] = self[var][:]
def sync(self):
self.sync_parcel_vars()
self.advance_parcel_vars()
super().sync()
Classes
class Parcel (*, dt, mass_of_dry_air: float, p0: float, initial_water_vapour_mixing_ratio: float, T0: float, w: [
, ], z0: float = 0, mixed_phase=False) -
Expand source code
class Parcel(Moist): # pylint: disable=too-many-instance-attributes def __init__( self, *, dt, mass_of_dry_air: float, p0: float, initial_water_vapour_mixing_ratio: float, T0: float, w: [float, callable], z0: float = 0, mixed_phase=False, ): super().__init__( dt, Mesh.mesh_0d(), ["rhod", "z", "t"], mixed_phase=mixed_phase ) self.p0 = p0 self.initial_water_vapour_mixing_ratio = initial_water_vapour_mixing_ratio self.T0 = T0 self.z0 = z0 self.mass_of_dry_air = mass_of_dry_air self.w = w if callable(w) else lambda _: w self.formulae = None self.delta_liquid_water_mixing_ratio = None self.params = None @property def dv(self): rhod_mean = (self.get_predicted("rhod")[0] + self["rhod"][0]) / 2 return self.formulae.trivia.volume_of_density_mass( rhod_mean, self.mass_of_dry_air ) def register(self, builder): self.formulae = builder.particulator.formulae pd0 = self.formulae.trivia.p_d(self.p0, self.initial_water_vapour_mixing_ratio) rhod0 = self.formulae.state_variable_triplet.rhod_of_pd_T(pd0, self.T0) self.mesh.dv = self.formulae.trivia.volume_of_density_mass( rhod0, self.mass_of_dry_air ) Moist.register(self, builder) params = ( self.initial_water_vapour_mixing_ratio, self.formulae.trivia.th_std(pd0, self.T0), rhod0, self.z0, 0, ) self["water_vapour_mixing_ratio"][:] = params[0] self["thd"][:] = params[1] self["rhod"][:] = params[2] self["z"][:] = params[3] self["t"][:] = params[4] self._tmp["water_vapour_mixing_ratio"][:] = params[0] self.sync_parcel_vars() Moist.sync(self) self.notify() def init_attributes( self, *, n_in_dv: [float, np.ndarray], kappa: float, r_dry: [float, np.ndarray], rtol=default_rtol, include_dry_volume_in_attribute: bool = True, ): if not isinstance(n_in_dv, np.ndarray): r_dry = np.array([r_dry]) n_in_dv = np.array([n_in_dv]) attributes = {} dry_volume = self.formulae.trivia.volume(radius=r_dry) attributes["kappa times dry volume"] = dry_volume * kappa attributes["multiplicity"] = n_in_dv r_wet = equilibrate_wet_radii( r_dry=r_dry, environment=self, kappa_times_dry_volume=attributes["kappa times dry volume"], rtol=rtol, ) attributes["volume"] = self.formulae.trivia.volume(radius=r_wet) if include_dry_volume_in_attribute: attributes["dry volume"] = dry_volume return attributes def advance_parcel_vars(self): dt = self.particulator.dt T = self["T"][0] p = self["p"][0] t = self["t"][0] dz_dt = self.w(t + dt / 2) # "mid-point" water_vapour_mixing_ratio = ( self["water_vapour_mixing_ratio"][0] - self.delta_liquid_water_mixing_ratio / 2 ) drho_dz = self.formulae.hydrostatics.drho_dz( g=self.formulae.constants.g_std, p=p, T=T, water_vapour_mixing_ratio=water_vapour_mixing_ratio, lv=self.formulae.latent_heat.lv(T), d_liquid_water_mixing_ratio__dz=( self.delta_liquid_water_mixing_ratio / dz_dt / dt ), ) drhod_dz = drho_dz self.particulator.backend.explicit_euler(self._tmp["t"], dt, 1) self.particulator.backend.explicit_euler(self._tmp["z"], dt, dz_dt) self.particulator.backend.explicit_euler( self._tmp["rhod"], dt, dz_dt * drhod_dz ) self.mesh.dv = self.formulae.trivia.volume_of_density_mass( (self._tmp["rhod"][0] + self["rhod"][0]) / 2, self.mass_of_dry_air ) def get_thd(self): return self["thd"] def get_water_vapour_mixing_ratio(self): return self["water_vapour_mixing_ratio"] def sync_parcel_vars(self): self.delta_liquid_water_mixing_ratio = ( self._tmp["water_vapour_mixing_ratio"][0] - self["water_vapour_mixing_ratio"][0] ) for var in self.variables: self._tmp[var][:] = self[var][:] def sync(self): self.sync_parcel_vars() self.advance_parcel_vars() super().sync()
Ancestors
Instance variables
var dv
-
Expand source code
@property def dv(self): rhod_mean = (self.get_predicted("rhod")[0] + self["rhod"][0]) / 2 return self.formulae.trivia.volume_of_density_mass( rhod_mean, self.mass_of_dry_air )
Methods
def advance_parcel_vars(self)
-
Expand source code
def advance_parcel_vars(self): dt = self.particulator.dt T = self["T"][0] p = self["p"][0] t = self["t"][0] dz_dt = self.w(t + dt / 2) # "mid-point" water_vapour_mixing_ratio = ( self["water_vapour_mixing_ratio"][0] - self.delta_liquid_water_mixing_ratio / 2 ) drho_dz = self.formulae.hydrostatics.drho_dz( g=self.formulae.constants.g_std, p=p, T=T, water_vapour_mixing_ratio=water_vapour_mixing_ratio, lv=self.formulae.latent_heat.lv(T), d_liquid_water_mixing_ratio__dz=( self.delta_liquid_water_mixing_ratio / dz_dt / dt ), ) drhod_dz = drho_dz self.particulator.backend.explicit_euler(self._tmp["t"], dt, 1) self.particulator.backend.explicit_euler(self._tmp["z"], dt, dz_dt) self.particulator.backend.explicit_euler( self._tmp["rhod"], dt, dz_dt * drhod_dz ) self.mesh.dv = self.formulae.trivia.volume_of_density_mass( (self._tmp["rhod"][0] + self["rhod"][0]) / 2, self.mass_of_dry_air )
def get_thd(self)
-
Expand source code
def get_thd(self): return self["thd"]
def get_water_vapour_mixing_ratio(self)
-
Expand source code
def get_water_vapour_mixing_ratio(self): return self["water_vapour_mixing_ratio"]
def init_attributes(self, *, n_in_dv: [
, ], kappa: float, r_dry: [ , ], rtol=1e-05, include_dry_volume_in_attribute: bool = True) -
Expand source code
def init_attributes( self, *, n_in_dv: [float, np.ndarray], kappa: float, r_dry: [float, np.ndarray], rtol=default_rtol, include_dry_volume_in_attribute: bool = True, ): if not isinstance(n_in_dv, np.ndarray): r_dry = np.array([r_dry]) n_in_dv = np.array([n_in_dv]) attributes = {} dry_volume = self.formulae.trivia.volume(radius=r_dry) attributes["kappa times dry volume"] = dry_volume * kappa attributes["multiplicity"] = n_in_dv r_wet = equilibrate_wet_radii( r_dry=r_dry, environment=self, kappa_times_dry_volume=attributes["kappa times dry volume"], rtol=rtol, ) attributes["volume"] = self.formulae.trivia.volume(radius=r_wet) if include_dry_volume_in_attribute: attributes["dry volume"] = dry_volume return attributes
def register(self, builder)
-
Expand source code
def register(self, builder): self.formulae = builder.particulator.formulae pd0 = self.formulae.trivia.p_d(self.p0, self.initial_water_vapour_mixing_ratio) rhod0 = self.formulae.state_variable_triplet.rhod_of_pd_T(pd0, self.T0) self.mesh.dv = self.formulae.trivia.volume_of_density_mass( rhod0, self.mass_of_dry_air ) Moist.register(self, builder) params = ( self.initial_water_vapour_mixing_ratio, self.formulae.trivia.th_std(pd0, self.T0), rhod0, self.z0, 0, ) self["water_vapour_mixing_ratio"][:] = params[0] self["thd"][:] = params[1] self["rhod"][:] = params[2] self["z"][:] = params[3] self["t"][:] = params[4] self._tmp["water_vapour_mixing_ratio"][:] = params[0] self.sync_parcel_vars() Moist.sync(self) self.notify()
def sync(self)
-
Expand source code
def sync(self): self.sync_parcel_vars() self.advance_parcel_vars() super().sync()
def sync_parcel_vars(self)
-
Expand source code
def sync_parcel_vars(self): self.delta_liquid_water_mixing_ratio = ( self._tmp["water_vapour_mixing_ratio"][0] - self["water_vapour_mixing_ratio"][0] ) for var in self.variables: self._tmp[var][:] = self[var][:]