Module PySDM.environments.impl.moist

common logic for environments featuring moist-air thermodynamics

Expand source code
"""
common logic for environments featuring moist-air thermodynamics
"""

from abc import abstractmethod

import numpy as np


class Moist:
    def __init__(self, dt, mesh, variables, mixed_phase=False):
        variables += ["water_vapour_mixing_ratio", "thd", "T", "p", "RH"]
        if mixed_phase:
            variables += ["a_w_ice"]
        self.particulator = None
        self.dt = dt
        self.mesh = mesh
        self.variables = variables
        self._values = None
        self._tmp = None
        self._nan_field = None

    def register(self, builder):
        self.particulator = builder.particulator
        self.particulator.observers.append(self)

        if self.particulator.formulae.ventilation.__name__ != "Neglect":
            for var in ("air density", "air dynamic viscosity"):
                if var not in self.variables:
                    self.variables += [var]

        self._values = {"predicted": None, "current": self._allocate(self.variables)}
        self._tmp = self._allocate(self.variables)

        self._nan_field = self._allocate(("_",))["_"]
        self._nan_field.fill(np.nan)

    def _allocate(self, variables):
        result = {}
        for var in variables:
            result[var] = self.particulator.Storage.empty((self.mesh.n_cell,), float)
        return result

    def __getitem__(self, index):
        """returns a Storage representing the variable (field) at a given index or
        otherwise a NaN-filled Storage if the index is not found (in order to simplify
        generic code which uses optional variables, e.g. air viscosity, etc.)"""
        if index in self._values["current"]:
            return self._values["current"][index]
        return self._nan_field

    def get_predicted(self, index):
        if self._values["predicted"] is None:
            raise AssertionError(
                "It seems the AmbientThermodynamics dynamic was not added"
                " when building particulator"
            )
        return self._values["predicted"][index]

    def sync(self):
        target = self._tmp
        target["water_vapour_mixing_ratio"].ravel(self.get_water_vapour_mixing_ratio())
        target["thd"].ravel(self.get_thd())

        self.particulator.backend.temperature_pressure_RH(
            rhod=target["rhod"],
            thd=target["thd"],
            water_vapour_mixing_ratio=target["water_vapour_mixing_ratio"],
            T=target["T"],
            p=target["p"],
            RH=target["RH"],
        )
        if "a_w_ice" in self.variables:
            self.particulator.backend.a_w_ice(
                T=target["T"],
                p=target["p"],
                RH=target["RH"],
                water_vapour_mixing_ratio=target["water_vapour_mixing_ratio"],
                a_w_ice=target["a_w_ice"],
            )
        if "air density" in self.variables:
            self.particulator.backend.air_density(
                water_vapour_mixing_ratio=target["water_vapour_mixing_ratio"],
                rhod=target["rhod"],
                output=target["air density"],
            )
        if "air dynamic viscosity" in self.variables:
            self.particulator.backend.air_dynamic_viscosity(
                temperature=target["T"],
                output=target["air dynamic viscosity"],
            )
        self._values["predicted"] = target

    @abstractmethod
    def get_water_vapour_mixing_ratio(self) -> np.ndarray:
        raise NotImplementedError()

    @abstractmethod
    def get_thd(self) -> np.ndarray:
        raise NotImplementedError()

    def notify(self):
        if self._values["predicted"] is None:
            return

        self._tmp = self._values["current"]
        self._values["current"] = self._values["predicted"]
        self._values["predicted"] = None

Classes

class Moist (dt, mesh, variables, mixed_phase=False)
Expand source code
class Moist:
    def __init__(self, dt, mesh, variables, mixed_phase=False):
        variables += ["water_vapour_mixing_ratio", "thd", "T", "p", "RH"]
        if mixed_phase:
            variables += ["a_w_ice"]
        self.particulator = None
        self.dt = dt
        self.mesh = mesh
        self.variables = variables
        self._values = None
        self._tmp = None
        self._nan_field = None

    def register(self, builder):
        self.particulator = builder.particulator
        self.particulator.observers.append(self)

        if self.particulator.formulae.ventilation.__name__ != "Neglect":
            for var in ("air density", "air dynamic viscosity"):
                if var not in self.variables:
                    self.variables += [var]

        self._values = {"predicted": None, "current": self._allocate(self.variables)}
        self._tmp = self._allocate(self.variables)

        self._nan_field = self._allocate(("_",))["_"]
        self._nan_field.fill(np.nan)

    def _allocate(self, variables):
        result = {}
        for var in variables:
            result[var] = self.particulator.Storage.empty((self.mesh.n_cell,), float)
        return result

    def __getitem__(self, index):
        """returns a Storage representing the variable (field) at a given index or
        otherwise a NaN-filled Storage if the index is not found (in order to simplify
        generic code which uses optional variables, e.g. air viscosity, etc.)"""
        if index in self._values["current"]:
            return self._values["current"][index]
        return self._nan_field

    def get_predicted(self, index):
        if self._values["predicted"] is None:
            raise AssertionError(
                "It seems the AmbientThermodynamics dynamic was not added"
                " when building particulator"
            )
        return self._values["predicted"][index]

    def sync(self):
        target = self._tmp
        target["water_vapour_mixing_ratio"].ravel(self.get_water_vapour_mixing_ratio())
        target["thd"].ravel(self.get_thd())

        self.particulator.backend.temperature_pressure_RH(
            rhod=target["rhod"],
            thd=target["thd"],
            water_vapour_mixing_ratio=target["water_vapour_mixing_ratio"],
            T=target["T"],
            p=target["p"],
            RH=target["RH"],
        )
        if "a_w_ice" in self.variables:
            self.particulator.backend.a_w_ice(
                T=target["T"],
                p=target["p"],
                RH=target["RH"],
                water_vapour_mixing_ratio=target["water_vapour_mixing_ratio"],
                a_w_ice=target["a_w_ice"],
            )
        if "air density" in self.variables:
            self.particulator.backend.air_density(
                water_vapour_mixing_ratio=target["water_vapour_mixing_ratio"],
                rhod=target["rhod"],
                output=target["air density"],
            )
        if "air dynamic viscosity" in self.variables:
            self.particulator.backend.air_dynamic_viscosity(
                temperature=target["T"],
                output=target["air dynamic viscosity"],
            )
        self._values["predicted"] = target

    @abstractmethod
    def get_water_vapour_mixing_ratio(self) -> np.ndarray:
        raise NotImplementedError()

    @abstractmethod
    def get_thd(self) -> np.ndarray:
        raise NotImplementedError()

    def notify(self):
        if self._values["predicted"] is None:
            return

        self._tmp = self._values["current"]
        self._values["current"] = self._values["predicted"]
        self._values["predicted"] = None

Subclasses

Methods

def get_predicted(self, index)
Expand source code
def get_predicted(self, index):
    if self._values["predicted"] is None:
        raise AssertionError(
            "It seems the AmbientThermodynamics dynamic was not added"
            " when building particulator"
        )
    return self._values["predicted"][index]
def get_thd(self) ‑> numpy.ndarray
Expand source code
@abstractmethod
def get_thd(self) -> np.ndarray:
    raise NotImplementedError()
def get_water_vapour_mixing_ratio(self) ‑> numpy.ndarray
Expand source code
@abstractmethod
def get_water_vapour_mixing_ratio(self) -> np.ndarray:
    raise NotImplementedError()
def notify(self)
Expand source code
def notify(self):
    if self._values["predicted"] is None:
        return

    self._tmp = self._values["current"]
    self._values["current"] = self._values["predicted"]
    self._values["predicted"] = None
def register(self, builder)
Expand source code
def register(self, builder):
    self.particulator = builder.particulator
    self.particulator.observers.append(self)

    if self.particulator.formulae.ventilation.__name__ != "Neglect":
        for var in ("air density", "air dynamic viscosity"):
            if var not in self.variables:
                self.variables += [var]

    self._values = {"predicted": None, "current": self._allocate(self.variables)}
    self._tmp = self._allocate(self.variables)

    self._nan_field = self._allocate(("_",))["_"]
    self._nan_field.fill(np.nan)
def sync(self)
Expand source code
def sync(self):
    target = self._tmp
    target["water_vapour_mixing_ratio"].ravel(self.get_water_vapour_mixing_ratio())
    target["thd"].ravel(self.get_thd())

    self.particulator.backend.temperature_pressure_RH(
        rhod=target["rhod"],
        thd=target["thd"],
        water_vapour_mixing_ratio=target["water_vapour_mixing_ratio"],
        T=target["T"],
        p=target["p"],
        RH=target["RH"],
    )
    if "a_w_ice" in self.variables:
        self.particulator.backend.a_w_ice(
            T=target["T"],
            p=target["p"],
            RH=target["RH"],
            water_vapour_mixing_ratio=target["water_vapour_mixing_ratio"],
            a_w_ice=target["a_w_ice"],
        )
    if "air density" in self.variables:
        self.particulator.backend.air_density(
            water_vapour_mixing_ratio=target["water_vapour_mixing_ratio"],
            rhod=target["rhod"],
            output=target["air density"],
        )
    if "air dynamic viscosity" in self.variables:
        self.particulator.backend.air_dynamic_viscosity(
            temperature=target["T"],
            output=target["air dynamic viscosity"],
        )
    self._values["predicted"] = target