Source code for g3d.gas.gas

"""Gas class definition"""
from typing import Tuple, Any, Union

import os

if os.environ.get('__USE_CUDA', '0') == '1':
    import cupy as np
    from cupy import ndarray
else:
    import numpy as np
    from numpy import ndarray

from g3d.defs import G3DEntity
from g3d.defs import FunctionByPass


[docs] class Gas(G3DEntity): """ Gas: thermodynamic variables and gas relations (equation of state) extends G3DEntity """ def __init__(self, *args: Any, **kwargs: Any) -> None: """initialize Gas placeholder""" self._gamma = 1.4 self._R = 287.0 self._viscosity = 1.7e-5 self._Pr = 0.72 super().__init__(*args, **kwargs) def _set_default(self) -> None: super()._set_default() self._tag = 'g3d_gas' self.__update_secondary_parameters() def __update_secondary_parameters(self) -> None: self.__gm1 = self._gamma - 1.0 self.__gp1 = self._gamma + 1.0 self.__one_over_gm1 = 1. / self.__gm1 self.__gm1_over_g = self.__gm1 / self._gamma self.__g_over_gm1 = self._gamma / self.__gm1 self.__Cp = self._gamma * self._R / self.__gm1 self.__Cv = self._R / self.__gm1 def _set_from_args(self, *args: Any, **kwargs: Any) -> np.ndarray: bps = self._get_function_evaluate_status(**kwargs) if bps is FunctionByPass.SELF: args_stat = np.ones(len(args)) else: args_stat = super()._set_from_args(*args) if bps in [FunctionByPass.EVALUATE, FunctionByPass.SELF]: if np.sum(args_stat) > 0: gas_data = [] for i in range(len(args)): if args_stat[i] == 1: arg = args[i] if type(arg) is Gas: args_stat[i] = 0 self.copy(arg) elif type(arg) in [float, np.float64, np.float32, int, np.int64, np.int32]: # append all float type values to a list and make a sub call to _set_from_args args_stat[i] = 0 gas_data.append(np.float64(arg)) elif type(arg) is list: args_stat[i] = 0 if self._list_is_all_floats(arg) and len(arg) >= 2: # get gas data from list self._gamma = arg[0] self._R = arg[1] if len(arg) >= 3: self._viscosity = arg[2] if len(arg) >= 4: self._Pr = arg[3] if len(gas_data) >= 2: self._set_from_args(gas_data, bps=FunctionByPass.SELF) return args_stat
[docs] def set_from_key_value(self, key: str, value: Any) -> bool: """ sets entity parameters from specified key => value data input: key, value valid keys for Gas class: 'gamma', 'R', 'viscosity', 'Pr' example: set_from_key_value(key, value) """ if super().set_from_key_value(key, value): return True elif key == 'gcnt' or key == 'gamma': self._gamma = value self.__update_secondary_parameters() return True elif key == 'R': self._R = value self.__update_secondary_parameters() return True elif key == 'visc' or key == 'viscosity': self._viscosity = value return True elif key == 'Pr': self._Pr = value return True return False
@property def gamma(self) -> float: """ratio of specific heat Cp/Cv""" return self._gamma @gamma.setter def gamma(self, val: float) -> None: self._gamma = val self.__update_secondary_parameters() @property def R(self) -> float: """gas constant (gas specific)""" return self._R @R.setter def R(self, val: float) -> None: self._R = val self.__update_secondary_parameters() @property def viscosity(self) -> float: """viscosity""" return self._viscosity @viscosity.setter def viscosity(self, val: float) -> None: self._viscosity = val @property def Pr(self) -> float: """Prandtl number""" return self._Pr @Pr.setter def Pr(self, val: float) -> None: self._Pr = val # secondary gas properties @property def gm1(self) -> float: """ratio of specific heats minus one""" return self.__gm1 @property def gp1(self) -> float: """ratio of specific heats plus one""" return self.__gp1 @property def one_over_gm1(self) -> float: """one over ratio of specific heats minus one""" return self.__one_over_gm1 @property def gm1_over_g(self) -> float: """ratio of specific heats minus one over ratio of specific heats""" return self.__gm1_over_g @property def g_over_gm1(self) -> float: """ratio of specific heats over ratio of specific heats minus one""" return self.__g_over_gm1 @property def Cp(self) -> float: """specific heat at constant pressure""" return self.__Cp @property def Cv(self) -> float: """specific heat at constant volume""" return self.__Cv
[docs] def copy(self, gas: 'Gas') -> None: """ copies gas properties from provided instance of class Gas input: gas example: copy(Gas g) """ super().copy(gas) self._gamma = gas.gamma self._R = gas.R self._viscosity = gas.viscosity self._Pr = gas.Pr self.__update_secondary_parameters()
# -- data extract
[docs] def get_gas_data(self) -> Tuple[float, float, float, float]: """ returns gas data input: no input example: gamma, R, Cp, Cv = get_gas_data() """ return self._gamma, self._R, self.__Cp, self.__Cv
# -- ideal gas law for perfect gases
[docs] def get_pressure(self, T: Union[float, ndarray], ro: Union[float, ndarray]) -> Union[float, ndarray]: """ calculates pressure P [Pa] from provided temperature T [K] and density RO [kg/m^3] input: temperature T [K], density RO [kg/m^3] example: P = get_pressure(T, RO) """ return ro * self._R * T
[docs] def get_temperature(self, P: Union[float, ndarray], ro: Union[float, ndarray]) -> Union[float, ndarray]: """ calculates temperature T [K] from provided pressure [Pa] and density [kg/m^3] input: pressure P [Pa], density RO [kg/m^3] example: T = get_temperature(P, RO) """ return P / (self._R * ro)
[docs] def get_density(self, P: Union[float, ndarray], T: Union[float, ndarray]) -> Union[float, ndarray]: """ calculates density RO [kg/m^3] from provided pressure P [Pa] and temperature T [K] input: pressure P [Pa], temperature T [K] example: RO = get_density(P, T) """ return P / (self._R * T)
# -- speed of sound relation for perfect gases
[docs] def get_speed_of_sound(self, T: Union[float, ndarray]) -> Union[float, ndarray]: """ calculates speed of sound C [m/s] from specified temperature T [K] input: temperature T[K] example: C = get_speed_of_sound(T) """ return np.sqrt(T * self._R * self._gamma)
[docs] def get_temperature_from_speed_of_sound(self, a: Union[float, ndarray]) -> Union[float, ndarray]: """ calculates temperature T [K] from specified speed of sound C [m/s] input: speed of sound C [m/s] example: T = get_temperature_from_speed_of_sound(C) """ return a ** 2 / (self._R * self._gamma)
# -- energy <-> pressure relation
[docs] def get_energy_from_primitive(self, ro: Union[float, ndarray], p: Union[float, ndarray], u: Union[float, ndarray], v: Union[float, ndarray] = 0., w: Union[float, ndarray] = 0.) -> Union[float, ndarray]: """ calculates energy (ro * e_o) from provided primitive variables input: density, pressure, velocity example: roe_o = et_energy_from_primitive(ro, p, u, v, w) """ return p * self.__one_over_gm1 + 0.5 * ro * (u * u + v * v + w * w)
[docs] def get_pressure_from_conservative(self, ro: Union[float, ndarray], et: Union[float, ndarray], ru: Union[float, ndarray], rv: Union[float, ndarray] = 0., rw: Union[float, ndarray] = 0.) -> Union[float, ndarray]: """ calculates pressure from provided conservative variables input: ro, re_o, ru, rv, rw example: p = get_pressure_from_conservative(ro, re_o, ru, rv, rw) """ u = ru / ro v = rv / ro w = rw / ro return self.__gm1 * (et - 0.5 * ro * (u * u + v * v + w * w))
# -- isentropic relations
[docs] def isentropic_exp_p(self, x: Union[float, ndarray]) -> Union[float, ndarray]: """ calculates exponent in isentropic relation for pressure input: T2/T1 example: exp = isentropic_exp_p(T2/T1 """ return np.power(x, self.__g_over_gm1)
[docs] def isentropic_exp_ro(self, x: Union[float, ndarray]) -> Union[float, ndarray]: """ calculates exponent in isentropic relation for density input: T2/T1 example: exp = isentropic_exp_ro(T2/T1 """ return np.power(x, self.__one_over_gm1)
[docs] def inv_isentropic_exp_p(self, x: Union[float, ndarray]) -> Union[float, ndarray]: """ calculates one over exponent in isentropic relation for pressure input: T2/T1 example: exp = inv_isentropic_exp_p(T2/T1 """ return np.power(x, self.__gm1_over_g)
[docs] def inv_isentropic_exp_ro(self, x: Union[float, ndarray]) -> Union[float, ndarray]: """ calculates one over exponent in isentropic relation for density input: T2/T1 example: exp = inv_isentropic_exp_ro(T2/T1 """ return np.power(x, self.__gm1)