PySDM.environments.impl.moist
common logic for environments featuring moist-air thermodynamics
1""" 2common logic for environments featuring moist-air thermodynamics 3""" 4 5from abc import abstractmethod 6 7import numpy as np 8 9 10class Moist: 11 def __init__(self, dt, mesh, variables, mixed_phase=False): 12 variables += ["water_vapour_mixing_ratio", "thd", "T", "p", "RH"] 13 if mixed_phase: 14 variables += ["a_w_ice", "RH_ice"] 15 all_vars_unique = len(variables) == len(set(variables)) 16 assert all_vars_unique 17 18 self.particulator = None 19 self.dt = dt 20 self.mesh = mesh 21 self.variables = variables 22 self._values = None 23 self._tmp = None 24 self._nan_field = None 25 26 def register(self, builder): 27 self.particulator = builder.particulator 28 self.particulator.observers.append(self) 29 30 if self.particulator.formulae.ventilation.__name__ != "Neglect": 31 for var in ("air density", "air dynamic viscosity"): 32 if var not in self.variables: 33 self.variables += [var] 34 35 self._values = {"predicted": None, "current": self._allocate(self.variables)} 36 self._tmp = self._allocate(self.variables) 37 38 self._nan_field = self._allocate(("_",))["_"] 39 self._nan_field.fill(np.nan) 40 41 def _allocate(self, variables): 42 result = {} 43 for var in variables: 44 result[var] = self.particulator.Storage.empty((self.mesh.n_cell,), float) 45 return result 46 47 def __getitem__(self, key: str): 48 """returns a Storage representing the variable (field) at a given key or 49 otherwise a NaN-filled Storage if the key is not found (in order to simplify 50 generic code which uses optional variables, e.g. air viscosity, etc.)""" 51 if key in self._values["current"]: 52 return self._values["current"][key] 53 return self._nan_field 54 55 def get_predicted(self, key: str): 56 if self._values["predicted"] is None: 57 raise AssertionError( 58 "It seems the AmbientThermodynamics dynamic was not added" 59 " when building particulator" 60 ) 61 return self._values["predicted"][key] 62 63 def _recalculate_temperature_pressure_relative_humidity(self, target): 64 self.particulator.backend.temperature_pressure_rh( 65 rhod=target["rhod"], 66 thd=target["thd"], 67 water_vapour_mixing_ratio=target["water_vapour_mixing_ratio"], 68 T=target["T"], 69 p=target["p"], 70 RH=target["RH"], 71 ) 72 73 def sync(self): 74 target = self._tmp 75 target["water_vapour_mixing_ratio"].ravel(self.get_water_vapour_mixing_ratio()) 76 target["thd"].ravel(self.get_thd()) 77 78 self._recalculate_temperature_pressure_relative_humidity(target) 79 80 if "a_w_ice" in self.variables: 81 self.particulator.backend.a_w_ice( 82 T=target["T"], 83 p=target["p"], 84 RH=target["RH"], 85 water_vapour_mixing_ratio=target["water_vapour_mixing_ratio"], 86 a_w_ice=target["a_w_ice"], 87 RH_ice=target["RH_ice"], 88 ) 89 if "air density" in self.variables: 90 self.particulator.backend.air_density( 91 water_vapour_mixing_ratio=target["water_vapour_mixing_ratio"], 92 rhod=target["rhod"], 93 output=target["air density"], 94 ) 95 if "air dynamic viscosity" in self.variables: 96 self.particulator.backend.air_dynamic_viscosity( 97 temperature=target["T"], 98 output=target["air dynamic viscosity"], 99 ) 100 self._values["predicted"] = target 101 102 @abstractmethod 103 def get_water_vapour_mixing_ratio(self) -> np.ndarray: 104 raise NotImplementedError() 105 106 @abstractmethod 107 def get_thd(self) -> np.ndarray: 108 raise NotImplementedError() 109 110 def notify(self): 111 if self._values["predicted"] is None: 112 return 113 114 self._tmp = self._values["current"] 115 self._values["current"] = self._values["predicted"] 116 self._values["predicted"] = None
class
Moist:
11class Moist: 12 def __init__(self, dt, mesh, variables, mixed_phase=False): 13 variables += ["water_vapour_mixing_ratio", "thd", "T", "p", "RH"] 14 if mixed_phase: 15 variables += ["a_w_ice", "RH_ice"] 16 all_vars_unique = len(variables) == len(set(variables)) 17 assert all_vars_unique 18 19 self.particulator = None 20 self.dt = dt 21 self.mesh = mesh 22 self.variables = variables 23 self._values = None 24 self._tmp = None 25 self._nan_field = None 26 27 def register(self, builder): 28 self.particulator = builder.particulator 29 self.particulator.observers.append(self) 30 31 if self.particulator.formulae.ventilation.__name__ != "Neglect": 32 for var in ("air density", "air dynamic viscosity"): 33 if var not in self.variables: 34 self.variables += [var] 35 36 self._values = {"predicted": None, "current": self._allocate(self.variables)} 37 self._tmp = self._allocate(self.variables) 38 39 self._nan_field = self._allocate(("_",))["_"] 40 self._nan_field.fill(np.nan) 41 42 def _allocate(self, variables): 43 result = {} 44 for var in variables: 45 result[var] = self.particulator.Storage.empty((self.mesh.n_cell,), float) 46 return result 47 48 def __getitem__(self, key: str): 49 """returns a Storage representing the variable (field) at a given key or 50 otherwise a NaN-filled Storage if the key is not found (in order to simplify 51 generic code which uses optional variables, e.g. air viscosity, etc.)""" 52 if key in self._values["current"]: 53 return self._values["current"][key] 54 return self._nan_field 55 56 def get_predicted(self, key: str): 57 if self._values["predicted"] is None: 58 raise AssertionError( 59 "It seems the AmbientThermodynamics dynamic was not added" 60 " when building particulator" 61 ) 62 return self._values["predicted"][key] 63 64 def _recalculate_temperature_pressure_relative_humidity(self, target): 65 self.particulator.backend.temperature_pressure_rh( 66 rhod=target["rhod"], 67 thd=target["thd"], 68 water_vapour_mixing_ratio=target["water_vapour_mixing_ratio"], 69 T=target["T"], 70 p=target["p"], 71 RH=target["RH"], 72 ) 73 74 def sync(self): 75 target = self._tmp 76 target["water_vapour_mixing_ratio"].ravel(self.get_water_vapour_mixing_ratio()) 77 target["thd"].ravel(self.get_thd()) 78 79 self._recalculate_temperature_pressure_relative_humidity(target) 80 81 if "a_w_ice" in self.variables: 82 self.particulator.backend.a_w_ice( 83 T=target["T"], 84 p=target["p"], 85 RH=target["RH"], 86 water_vapour_mixing_ratio=target["water_vapour_mixing_ratio"], 87 a_w_ice=target["a_w_ice"], 88 RH_ice=target["RH_ice"], 89 ) 90 if "air density" in self.variables: 91 self.particulator.backend.air_density( 92 water_vapour_mixing_ratio=target["water_vapour_mixing_ratio"], 93 rhod=target["rhod"], 94 output=target["air density"], 95 ) 96 if "air dynamic viscosity" in self.variables: 97 self.particulator.backend.air_dynamic_viscosity( 98 temperature=target["T"], 99 output=target["air dynamic viscosity"], 100 ) 101 self._values["predicted"] = target 102 103 @abstractmethod 104 def get_water_vapour_mixing_ratio(self) -> np.ndarray: 105 raise NotImplementedError() 106 107 @abstractmethod 108 def get_thd(self) -> np.ndarray: 109 raise NotImplementedError() 110 111 def notify(self): 112 if self._values["predicted"] is None: 113 return 114 115 self._tmp = self._values["current"] 116 self._values["current"] = self._values["predicted"] 117 self._values["predicted"] = None
Moist(dt, mesh, variables, mixed_phase=False)
12 def __init__(self, dt, mesh, variables, mixed_phase=False): 13 variables += ["water_vapour_mixing_ratio", "thd", "T", "p", "RH"] 14 if mixed_phase: 15 variables += ["a_w_ice", "RH_ice"] 16 all_vars_unique = len(variables) == len(set(variables)) 17 assert all_vars_unique 18 19 self.particulator = None 20 self.dt = dt 21 self.mesh = mesh 22 self.variables = variables 23 self._values = None 24 self._tmp = None 25 self._nan_field = None
def
register(self, builder):
27 def register(self, builder): 28 self.particulator = builder.particulator 29 self.particulator.observers.append(self) 30 31 if self.particulator.formulae.ventilation.__name__ != "Neglect": 32 for var in ("air density", "air dynamic viscosity"): 33 if var not in self.variables: 34 self.variables += [var] 35 36 self._values = {"predicted": None, "current": self._allocate(self.variables)} 37 self._tmp = self._allocate(self.variables) 38 39 self._nan_field = self._allocate(("_",))["_"] 40 self._nan_field.fill(np.nan)
def
sync(self):
74 def sync(self): 75 target = self._tmp 76 target["water_vapour_mixing_ratio"].ravel(self.get_water_vapour_mixing_ratio()) 77 target["thd"].ravel(self.get_thd()) 78 79 self._recalculate_temperature_pressure_relative_humidity(target) 80 81 if "a_w_ice" in self.variables: 82 self.particulator.backend.a_w_ice( 83 T=target["T"], 84 p=target["p"], 85 RH=target["RH"], 86 water_vapour_mixing_ratio=target["water_vapour_mixing_ratio"], 87 a_w_ice=target["a_w_ice"], 88 RH_ice=target["RH_ice"], 89 ) 90 if "air density" in self.variables: 91 self.particulator.backend.air_density( 92 water_vapour_mixing_ratio=target["water_vapour_mixing_ratio"], 93 rhod=target["rhod"], 94 output=target["air density"], 95 ) 96 if "air dynamic viscosity" in self.variables: 97 self.particulator.backend.air_dynamic_viscosity( 98 temperature=target["T"], 99 output=target["air dynamic viscosity"], 100 ) 101 self._values["predicted"] = target