Source code for g3d.calc.calculators.friction

"""One-dimensional flow with friction calculator"""
import os
from typing import Tuple, Union, Any

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 .calculator import G3DCalculator
from .normal_shock import G3DNormalShockCalculator

from g3d.defs import CFlowRegime
from g3d.defs import CFlowVariableType
from g3d.defs import CFlowAdditionMode


[docs] class G3DFrictionCalculator(G3DCalculator): """Class collecting functions related to one-dimensional flow with friction""" def __init__(self, *args: Any, **kwargs: Any) -> None: """Initialize calculator parameters""" super().__init__(*args, **kwargs) self.__normal_shock = G3DNormalShockCalculator(update_code_type=False) def _set_default(self) -> None: super()._set_default() self.__M = self._vars.add(name="M", long_name="Mach number") self.__M1 = self._vars.add(name="M1", long_name="Upstream Mach number") self.__M2 = self._vars.add(name="M2", long_name="Downstream Mach number") self.__f = self._vars.add(name="f", long_name="Friction factor") self.__D = self._vars.add(name="D", long_name="Pipe diameter", type=CFlowVariableType.DIAMETER) self.__P = self._vars.add(name="P", long_name="Pressure", type=CFlowVariableType.PRESSURE) self.__T = self._vars.add(name="T", long_name="Temperature", type=CFlowVariableType.TEMPERATURE) self.__RO = self._vars.add(name="RO", long_name="Density", type=CFlowVariableType.DENSITY) self.__P1 = self._vars.add(name="P1", long_name="Upstream pressure", type=CFlowVariableType.PRESSURE) self.__T1 = self._vars.add(name="T1", long_name="Upstream temperature", type=CFlowVariableType.TEMPERATURE) self.__RO1 = self._vars.add(name="RO1", long_name="Upstream density", type=CFlowVariableType.DENSITY) self.__P2 = self._vars.add(name="P2", long_name="Downstream pressure", type=CFlowVariableType.PRESSURE) self.__T2 = self._vars.add(name="T2", long_name="Downstream temperature", type=CFlowVariableType.TEMPERATURE) self.__RO2 = self._vars.add(name="RO2", long_name="Downstream density", type=CFlowVariableType.DENSITY) self.__Po = self._vars.add(name="Po", long_name="Total pressure", type=CFlowVariableType.PRESSURE) self.__To = self._vars.add(name="To", long_name="Total temperature", type=CFlowVariableType.TEMPERATURE) self.__Ps = self._vars.add(name="Ps", long_name="Pressure (choked flow)", type=CFlowVariableType.PRESSURE) self.__Ts = self._vars.add(name="Ts", long_name="Temperature (choked flow)", type=CFlowVariableType.TEMPERATURE) self.__ROs = self._vars.add(name="ROs", long_name="Density (choked flow)", type=CFlowVariableType.DENSITY) self.__Pos = self._vars.add(name="Pos", long_name="Total pressure (choked flow)", type=CFlowVariableType.PRESSURE) self.__Ls = self._vars.add(name="Ls", long_name="L* (choked flow)", type=CFlowVariableType.LENGTH) self.__PR = self._vars.add(name="PR", long_name="Pressure ratio") self.__TR = self._vars.add(name="TR", long_name="Temperature ratio") self.__RR = self._vars.add(name="RR", long_name="Density ratio") self.__L = self._vars.add(name="L", long_name="Pipe length", type=CFlowVariableType.LENGTH) self.__mp = self._vars.add(name="mp", long_name="Massflow", type=CFlowVariableType.MASSFLOW) def _associate(self) -> None: super()._associate() self.__normal_shock.gas = self._gas def __friction_factor(self, M: float = None) -> float: if M is None: M = self.__M.value MM = M * M return ((1. - MM) / (self._gas.gamma * MM) + (self._gas.gp1 / (2. * self._gas.gamma)) * np.log(self._gas.gp1 * MM / (2. + self._gas.gm1 * MM)))
[docs] def get_friction_factor(self, *args: Any, **kwargs: Any) -> Union[Union[tuple[Any, ...], list[Any]], Any]: """Calculates friction factor (4fL/D []) for specified Mach number input: Mach number (M []) supported data types: float, list[float], ndarray Parameters ---------- *args : Any arguments (optional input): Mach number value(s) **kwargs : Any keyword-value pairs (optional input): valid keywords: 'M' Returns ------- float, ndarray friction factor Examples -------- Basic usage: $_>>> from g3d import cflow $_>>> ff = cflow.friction.get_friction_factor(M=2.0) """ return self._eval(["M"], self.__friction_factor, *args, **kwargs)
[docs] def get_L_star(self, *args: Any, **kwargs: Any) -> Union[Union[tuple[Any, ...], list[Any]], Any]: """Calculates choke length (L* [m]) for specified Mach number input: Mach number (M []), average Darcy friction factor (f []), pipe diameter (D [m]) supported data types: float, list[float], ndarray Parameters ---------- *args : Any arguments (optional input): 1. Mach number 2. average Darcy friction factor 3. pipe diameter [m] variable value(s) in above-listed order **kwargs : Any keyword-value pairs (optional input): valid keywords: 'M', 'f', 'D' Returns ------- float, ndarray choking length [m] Examples -------- Basic usage: $_>>> from g3d import cflow $_>>> L_star = cflow.friction.get_L_star(M=2.0, f=0.005, D=0.1) """ return self._eval(["M", "f", "D"], self.__get_L_star, *args, **kwargs)
def __get_L_star(self, M: float = None, f: float = None, D: float = None) -> float: if f is None: f = self.__f.value if D is None: D = self.__D.value return self.__friction_factor(M) * (D / (4. * f)) def __Mach_factor(self, M: float = None) -> float: if M is None: M = self.__M.value return self._gas.gp1 / (2. + self._gas.gm1 * M * M)
[docs] def get_T_star(self, *args: Any, **kwargs: Any) -> Union[Union[tuple[Any, ...], list[Any]], Any]: """Calculates choke temperature (T* [K]) for specified Mach number (M) and temperature (T [K], T=1. if omitted) input: Mach number (M []), temperature (T [K]) supported data types: float, list[float], ndarray Parameters ---------- *args : Any arguments (optional input): 1. Mach number 2. temperature [K] variable value(s) in above-listed order **kwargs : Any keyword-value pairs (optional input): valid keywords: 'M', 'T' Returns ------- float, ndarray choked flow temperature [K] Examples -------- Basic usage: $_>>> from g3d import cflow $_>>> T_star = cflow.friction.get_T_star(M=2.0, T=300.) """ return self._eval(["M", "T"], self.__get_T_star, *args, **kwargs)
def __get_T_star(self, M: float = None, T: float = None) -> float: if T is None: T = self.__T.value return T / self.__Mach_factor(M)
[docs] def get_P_star(self, *args: Any, **kwargs: Any) -> Union[Union[tuple[Any, ...], list[Any]], Any]: """Calculates choke pressure (P* [Pa]) for specified Mach number (M []) and pressure (P [Pa], P=1. if omitted) input: Mach number (M []), pressure (P [Pa]) supported data types: float, list[float], ndarray Parameters ---------- *args : Any arguments (optional input): 1. Mach number 2. pressure [Pa] variable value(s) in above-listed order **kwargs : Any keyword-value pairs (optional input): valid keywords: 'M', 'P' Returns ------- float, ndarray choked flow pressure [Pa] Examples -------- Basic usage: $_>>> from g3d import cflow $_>>> P_star = cflow.friction.get_P_star(M=2.0, P=1.e5) """ return self._eval(["M", "P"], self.__get_P_star, *args, **kwargs)
def __get_P_star(self, M: float = None, P: float = None) -> float: if M is None: M = self.__M.value if P is None: P = self.__P.value return P * M / np.sqrt(self.__Mach_factor(M))
[docs] def get_RO_star(self, *args: Any, **kwargs: Any) -> Union[Union[tuple[Any, ...], list[Any]], Any]: """Calculates choke density (RO* [kg/m^3]) for specified Mach number (M []) and density (RO [kg/m^3], RO=1. if omitted) input: Mach number (M []), density (RO [kg/m^3]) supported data types: float, list[float], ndarray Parameters ---------- *args : Any arguments (optional input): 1. Mach number 2. density [kg/m^3] variable value(s) in above-listed order **kwargs : Any keyword-value pairs (optional input): valid keywords: 'M', 'RO' Returns ------- float, ndarray choked flow density [kg/m^3] Examples -------- Basic usage: $_>>> from g3d import cflow $_>>> RO_star = cflow.friction.get_RO_star(M=2.0, RO=1.2) """ return self._eval(["M", "RO"], self.__get_RO_star, *args, **kwargs)
def __get_RO_star(self, M: float = None, RO: float = None) -> float: if M is None: M = self.__M.value if RO is None: RO = self.__RO.value return RO * M / np.sqrt(1. / self.__Mach_factor(M))
[docs] def get_P0_star(self, *args: Any, **kwargs: Any) -> Union[Union[tuple[Any, ...], list[Any]], Any]: """ .. deprecated:: 2.6 redirects to :func:`get_Po_star` """ return self.get_Po_star(*args, **kwargs)
[docs] def get_Po_star(self, *args: Any, **kwargs: Any) -> Union[Union[tuple[Any, ...], list[Any]], Any]: """Calculates choke density (Po* [Pa]) for specified Mach number (M []) and total pressure (Po [Pa], Po=1. if omitted) input: Mach number (M []), total pressure (Po [Pa]) supported data types: float, list[float], ndarray Parameters ---------- *args : Any arguments (optional input): 1. Mach number 2. total pressure [Pa] variable value(s) in above-listed order **kwargs : Any keyword-value pairs (optional input): valid keywords: 'M', 'Po' Returns ------- float, ndarray choked flow total pressure [Pa] Examples -------- Basic usage: $_>>> from g3d import cflow $_>>> Po_star = cflow.friction.get_Po_star(M=2.0, Po=1.e5) """ return self._eval(["M", "Po"], self.__get_Po_star, *args, **kwargs)
def __get_Po_star(self, M: float = None, Po: float = None) -> float: if M is None: M = self.__M.value if Po is None: Po = self.__Po.value return Po * M / np.power((1. / self.__Mach_factor(M)), (self._gas.gp1 / (2. * self._gas.gm1)))
[docs] def get_T(self, *args: Any, **kwargs: Any) -> Union[Union[tuple[Any, ...], list[Any]], Any]: """Calculates temperature (T [K]) for specified Mach number (M []) and choke temperature (T* [K], T*=1. if omitted) input: Mach number (M []), choke temperature (T* [K]) supported data types: float, list[float], ndarray Parameters ---------- *args : Any arguments (optional input): 1. Mach number 2. choked temperature [K] variable value(s) in above-listed order **kwargs : Any keyword-value pairs (optional input): valid keywords: 'M', 'Ts' Returns ------- float, ndarray flow temperature [K] Examples -------- Basic usage: $_>>> from g3d import cflow $_>>> T = cflow.friction.get_T(M=2.0, Ts=300.) """ return self._eval(["M", "Ts"], self.__get_T, *args, **kwargs)
def __get_T(self, M: float = None, Ts: float = None) -> float: if M is None: M = self.__M.value if Ts is None: Ts = self.__Ts.value return Ts / self.__get_T_star(M, 1.)
[docs] def get_P(self, *args: Any, **kwargs: Any) -> Union[Union[tuple[Any, ...], list[Any]], Any]: """Calculates pressure (P [Pa]) for specified Mach number (M) and choke pressure (P* [Pa], P*=1. if omitted) input: Mach number (M []), choke pressure (P* [Pa]) supported data types: float, list[float], ndarray Parameters ---------- *args : Any arguments (optional input): 1. Mach number 2. choked pressure [Pa] variable value(s) in above-listed order **kwargs : Any keyword-value pairs (optional input): valid keywords: 'M', 'Ps' Returns ------- float, ndarray flow pressure [K] Examples -------- Basic usage: $_>>> from g3d import cflow $_>>> P = cflow.friction.get_P(M=2.0, Ps=1.e5) """ return self._eval(["M", "Ps"], self.__get_P, *args, **kwargs)
def __get_P(self, M: float = None, Ps: float = None) -> float: if M is None: M = self.__M.value if Ps is None: Ps = self.__Ps.value return Ps / self.__get_P_star(M, 1.)
[docs] def get_RO(self, *args: Any, **kwargs: Any) -> Union[Union[tuple[Any, ...], list[Any]], Any]: """Calculates density (RO [kg/m^3]) for specified Mach number (M []) and choke density (RO* [kg/m^3], RO*=1. if omitted) input: Mach number (M []), choke density (RO* [kg/m^3]) supported data types: float, list[float], ndarray Parameters ---------- *args : Any arguments (optional input): 1. Mach number 2. choked density [kg/m^3] variable value(s) in above-listed order **kwargs : Any keyword-value pairs (optional input): valid keywords: 'M', 'ROs' Returns ------- float, ndarray flow density [kg/m^3] Examples -------- Basic usage: $_>>> from g3d import cflow $_>>> RO = cflow.friction.get_RO(M=2.0, ROs=1.2) """ return self._eval(["M", "ROs"], self.__get_RO, *args, **kwargs)
def __get_RO(self, M: float = None, ROs: float = None) -> float: if M is None: M = self.__M.value if ROs is None: ROs = self.__ROs.value return ROs / self.__get_RO_star(M, 1.)
[docs] def get_P0(self, *args: Any, **kwargs: Any) -> Union[Union[tuple[Any, ...], list[Any]], Any]: """ .. deprecated:: 2.6 redirects to :func:`get_Po` """ return self.get_Po(*args, **kwargs)
[docs] def get_Po(self, *args: Any, **kwargs: Any) -> Union[Union[tuple[Any, ...], list[Any]], Any]: """Calculates total pressure (Po [Pa]) for specified Mach number (M []) and choked flow total pressure (Po* [Pa], Po*=1. if omitted) input: Mach number (M), choke total pressure (Po*) [Pa] supported data types: float, list[float], ndarray Parameters ---------- *args : Any arguments (optional input): 1. Mach number 2. choked total pressure [Pa] variable value(s) in above-listed order **kwargs : Any keyword-value pairs (optional input): valid keywords: 'M', 'Pos' Returns ------- float, ndarray total pressure [Pa] Examples -------- Basic usage: $_>>> from g3d import cflow $_>>> Po = cflow.friction.get_Po(M=2.0, Pos=1.e5) """ return self._eval(["M", "Pos"], self.__get_Po, *args, **kwargs)
def __get_Po(self, M: float = None, Pos: float = None) -> float: if M is None: M = self.__M.value if Pos is None: Pos = self.__Pos.value return Pos / self.__get_Po_star(M, 1.)
[docs] def find_Mach_from_temperature_ratio(self, *args: Any, **kwargs: Any) -> Union[Union[tuple[Any, ...], list[Any]], Any]: """ .. deprecated:: 2.6 redirects to :func:`get_Mach_from_temperature_ratio` """ return self.get_Mach_from_temperature_ratio(*args, **kwargs)
[docs] def get_Mach_from_temperature_ratio(self, *args: Any, **kwargs: Any) -> Union[Union[tuple[Any, ...], list[Any]], Any]: """Finds the Mach number (M []) matching the specified temperature ratio (given by a local temperature (T [K]) and a choked temperature (Ts [K])) The Mach number is estimated using the built-in Newton-Raphson solver input: local temperature (T [K]) and choked temperature (Ts [K]) supported data types: float, list[float], ndarray Parameters ---------- *args : Any arguments (optional input): 1. temperature [K] 2. choked temperature [K] variable value(s) in above-listed order **kwargs : Any keyword-value pairs (optional input): valid keywords: 'T', 'Ts' Returns ------- float, ndarray Mach number Examples -------- Basic usage: $_>>> from g3d import cflow $_>>> M = cflow.friction.get_Mach_from_temperature_ratio(T=300., Ts=600.) """ return self._eval(["T", "Ts"], self.__get_Mach_from_temperature_ratio, *args, **kwargs)
def __get_Mach_from_temperature_ratio(self, T: float = None, Ts: float = None) -> float: if T is None: T = self.__T.value if Ts is None: Ts = self.__Ts.value return np.sqrt((self._gas.gp1 * Ts - 2. * T) / (self._gas.gm1 * T))
[docs] def find_Mach_from_L_star(self, *args: Any, **kwargs: Any) -> Union[Union[tuple[Any, ...], list[Any]], Any]: """ .. deprecated:: 2.6 redirects to :func:`get_Mach_from_L_star` """ return self.get_Mach_from_L_star(*args, **kwargs)
[docs] def get_Mach_from_L_star(self, *args: Any, **kwargs: Any) -> Union[Union[tuple[Any, ...], list[Any]], Any]: """Finds the Mach number (M []) matching the specified choked length (L* [m]) The Mach number is estimated using the built-in Newton-Raphson solver input: choke length (Ls [m]), average Darcy friction factor (f []), pipe diameter (D [m]) optional input: mode 'subsonic' (default) or 'supersonic' supported data types: float, list[float], ndarray Parameters ---------- *args : Any arguments (optional input): 1. choke length [m] 2. average Darcy friction factor 3. pipe diameter [m] variable value(s) in above-listed order **kwargs : Any keyword-value pairs (optional input): valid keywords: 'Ls', 'f', 'D', 'mode' Returns ------- float, ndarray Mach number Examples -------- Basic usage: $_>>> from g3d import cflow $_>>> M = cflow.friction.get_Mach_from_L_star(Ls=10., f=0.005, D=0.1, mode='subsonic') """ self._reset_eval(mode=CFlowRegime.SUBSONIC) self._newton.reset() return self._eval(["Ls", "f", "D"], self.__get_Mach_from_L_star, *args, **kwargs)
def __get_Mach_from_L_star(self, Ls: float = None, f: float = None, D: float = None) -> float: if Ls is None: Ls = self.__Ls.value if f is None: f = self.__f.value if D is None: D = self.__D.value # find a start value by doing a coarse search newton = self._get_newton_kernel() newton.target_value = 4. * Ls * f / D newton.start_value = 1.0 newton.end_value = 0.1 if self._mode == CFlowRegime.SUPERSONIC: newton.end_value = 10. newton.lower_bound = 1. else: newton.upper_bound = 1. newton.find_start_value(self.__friction_factor) # run Newton solver to find Mach number return newton.solve(self.__friction_factor)
[docs] def find_Mach_from_pressure_ratio(self, *args: Any, **kwargs: Any) -> Union[np.float64, list[np.float64], float]: """ .. deprecated:: 2.6 redirects to :func:`get_Mach_from_pressure_ratio` """ return self.get_Mach_from_pressure_ratio(*args, **kwargs)
[docs] def get_Mach_from_pressure_ratio(self, *args: Any, **kwargs: Any) -> Union[np.float64, list[np.float64], float]: """Finds the Mach number (M []) matching the specified pressure ratio (given by a local pressure (P [Pa]) and a choked pressure (Ps [Pa])) The Mach number is estimated using the built-in Newton-Raphson solver input: local pressure (P [Pa]) and choked pressure (Ps [Pa]) optional input: mode 'subsonic' (default) or 'supersonic' supported data types: float, list[float], ndarray Parameters ---------- *args : Any arguments (optional input): 1. pressure [Pa] 2. choked pressure [Pa] variable value(s) in above-listed order **kwargs : Any keyword-value pairs (optional input): valid keywords: 'P', 'Ps', 'mode' Returns ------- float, ndarray Mach number Examples -------- Basic usage: $_>>> from g3d import cflow $_>>> M = cflow.friction.get_Mach_from_pressure_ratio(P=1.e5, Ps=1.6e5, mode='subsonic') """ self._reset_eval(mode=CFlowRegime.SUBSONIC) self._newton.reset() return self._eval(["P", "Ps"], self.__get_Mach_from_pressure_ratio, *args, **kwargs)
def __get_Mach_from_pressure_ratio(self, P: float = None, Ps: float = None) -> float: if P is None: P = self.__P.value if Ps is None: Ps = self.__Ps.value # find a start value by doing a coarse search newton = self._get_newton_kernel() newton.target_value = Ps / P newton.start_value = 1.0 newton.end_value = 0.1 if self._mode == CFlowRegime.SUPERSONIC: newton.end_value = 10. newton.lower_bound = 1. else: newton.upper_bound = 1. if P != 1.: self.__P.value = 1. newton.find_start_value(self.__get_P_star) # run Newton solver to find Mach number M = newton.solve(self.__get_P_star) if P != 1.: self.__P.value = P return M
[docs] def find_Mach_from_total_pressure_ratio(self, *args: Any, **kwargs: Any) \ -> Union[np.float64, list[np.float64], float]: """ .. deprecated:: 2.6 redirects to :func:`get_Mach_from_total_pressure_ratio` """ return self.get_Mach_from_total_pressure_ratio(*args, **kwargs)
[docs] def get_Mach_from_total_pressure_ratio(self, *args: Any, **kwargs: Any) \ -> Union[np.float64, list[np.float64], float]: """Finds the Mach number (M []) matching the specified total pressure ratio (given by a local total pressure (Po [Pa]) and a choked total pressure (Pos [Pa])) The Mach number is estimated using the built-in Newton-Raphson solver input: local total pressure (Po [Pa]) and choked total pressure (Pos [Pa]) optional input: mode 'subsonic' (default) or 'supersonic' supported data types: float, list[float], ndarray Parameters ---------- *args : Any arguments (optional input): 1. total pressure [Pa] 2. choked total pressure [Pa] variable value(s) in above-listed order **kwargs : Any keyword-value pairs (optional input): valid keywords: 'Po', 'Pos', 'mode' Returns ------- float, ndarray Mach number Examples -------- Basic usage: $_>>> from g3d import cflow $_>>> M = cflow.friction.get_Mach_from_total_pressure_ratio(Po=1.e5, Pos=8.5e4, mode='subsonic') """ self._reset_eval(mode=CFlowRegime.SUBSONIC) self._newton.reset() return self._eval(["Po", "Pos"], self.__get_Mach_from_total_pressure_ratio, *args, **kwargs)
def __get_Mach_from_total_pressure_ratio(self, Po: float = None, Pos: float = None) -> float: if Po is None: Po = self.__Po.value if Pos is None: Pos = self.__Pos.value # calculate target value newton = self._get_newton_kernel() newton.target_value = Pos / Po newton.start_value = 0.1 if self._mode == CFlowRegime.SUPERSONIC: newton.start_value = 1.5 newton.lower_bound = 1. else: newton.upper_bound = 1. # run Newton solver to find Mach number if Po != 1.: self.__Po.value = 1. M = newton.solve(self.__get_Po_star) if Po != 1.: self.__Po.value = Po return M
[docs] def get_TR_from_Mach(self, *args: Any, **kwargs: Any) -> Union[np.float64, list[np.float64], float]: """Get temperature ratio (TR []) from upstream Mach number (M1 []) and downstream Mach number (M2 []) input: upstream Mach number (M1 []) and downstream Mach number (M2 []) supported data types: float, list[float], ndarray Parameters ---------- *args : Any arguments (optional input): 1. upstream Mach number 2. downstream Mach number variable value(s) in above-listed order **kwargs : Any keyword-value pairs (optional input): valid keywords: 'M1', 'M2' Returns ------- float, ndarray temperature ratio Examples -------- Basic usage: $_>>> from g3d import cflow $_>>> TR = cflow.friction.get_TR_from_Mach(M1=2.0, M2=1.5) """ return self._eval(["M1", "M2"], self.__get_TR_from_Mach, *args, **kwargs)
def __get_TR_from_Mach(self, M1: float = None, M2: float = None) -> float: if M1 is None: M1 = self.__M1.value if M2 is None: M2 = self.__M2.value return (2. + self._gas.gm1 * M1 * M1) / (2. + self._gas.gm1 * M2 * M2)
[docs] def get_PR_from_Mach(self, *args: Any, **kwargs: Any) -> Union[np.float64, list[np.float64], float]: """Get pressure ratio (PR []) from upstream Mach number (M1 []) and downstream Mach number (M2 []) input: upstream Mach number (M1 []) and downstream Mach number (M2 []) supported data types: float, list[float], ndarray Parameters ---------- *args : Any arguments (optional input): 1. upstream Mach number 2. downstream Mach number variable value(s) in above-listed order **kwargs : Any keyword-value pairs (optional input): valid keywords: 'M1', 'M2' Returns ------- float, ndarray pressure ratio Examples -------- Basic usage: $_>>> from g3d import cflow $_>>> PR = cflow.friction.get_PR_from_Mach(M1=2.0, M2=1.5) """ return self._eval(["M1", "M2"], self.__get_PR_from_Mach, *args, **kwargs)
def __get_PR_from_Mach(self, M1: float = None, M2: float = None) -> float: if M1 is None: M1 = self.__M1.value if M2 is None: M2 = self.__M2.value return (M1 / M2) * np.sqrt(self.__get_TR_from_Mach(M1, M2))
[docs] def get_RR_from_Mach(self, *args: Any, **kwargs: Any) -> Union[np.float64, list[np.float64], float]: """Get density ratio (RR []) from upstream Mach number (M1 []) and downstream Mach number (M2 []) input: upstream Mach number (M1 []) and downstream Mach number (M2 []) supported data types: float, list[float], ndarray Parameters ---------- *args : Any arguments (optional input): 1. upstream Mach number 2. downstream Mach number variable value(s) in above-listed order **kwargs : Any keyword-value pairs (optional input): valid keywords: 'M1', 'M2' Returns ------- float, ndarray density ratio Examples -------- Basic usage: $_>>> from g3d import cflow $_>>> RR = cflow.friction.get_RR_from_Mach(M1=2.0, M2=1.5) """ return self._eval(["M1", "M2"], self.__get_RR_from_Mach, *args, **kwargs)
def __get_RR_from_Mach(self, M1: float = None, M2: float = None) -> float: if M1 is None: M1 = self.__M1.value if M2 is None: M2 = self.__M2.value return (M1 / M2) / np.sqrt(self.__get_TR_from_Mach(M1, M2))
[docs] def get_PoR_from_Mach(self, *args: Any, **kwargs: Any) -> Union[np.float64, list[np.float64], float]: """Get total pressure ratio (PoR []) from upstream Mach number (M1 []) and downstream Mach number (M2 []) input: upstream Mach number (M1 []) and downstream Mach number (M2 []) supported data types: float, list[float], ndarray Parameters ---------- *args : Any arguments (optional input): 1. upstream Mach number 2. downstream Mach number variable value(s) in above-listed order **kwargs : Any keyword-value pairs (optional input): valid keywords: 'M1', 'M2' Returns ------- float, ndarray total pressure ratio Examples -------- Basic usage: $_>>> from g3d import cflow $_>>> PoR = cflow.friction.get_PoR_from_Mach(M1=2.0, M2=1.5) """ return self._eval(["M1", "M2"], self.__get_PoR_from_Mach, *args, **kwargs)
def __get_PoR_from_Mach(self, M1: float = None, M2: float = None) -> float: if M1 is None: M1 = self.__M1.value if M2 is None: M2 = self.__M2.value return (M1 / M2) * (self.__get_TR_from_Mach(M1, M2) ** (self._gas.gp1 / (2. * self._gas.gm1)))
[docs] def get_downstream_Mach_from_PR(self, *args: Any, **kwargs: Any) -> Union[np.float64, list[np.float64], float]: """Get downstream Mach number (M2 []) from upstream Mach number (M1 []) and pressure ratio (PR []) input: upstream Mach number (M1 []) and pressure ratio (PR []) example: M2 = get_downstream_Mach_from_PR(M1=M1, PR=PR) supported data types: float, list[float], ndarray Parameters ---------- *args : Any arguments (optional input): 1. upstream Mach number 2. pressure ratio variable value(s) in above-listed order **kwargs : Any keyword-value pairs (optional input): valid keywords: 'M1', 'PR' Returns ------- float, ndarray downstream Mach number Examples -------- Basic usage: $_>>> from g3d import cflow $_>>> M2 = cflow.friction.get_downstream_Mach_from_PR(M1=2.0, PR=0.2) """ return self._eval(["PR", "M1"], self.__get_downstream_Mach_from_PR, *args, **kwargs)
def __get_downstream_Mach_from_PR(self, PR: float = None, M1: float = None) -> float: if M1 is None: M1 = self.__M1.value if PR is None: PR = self.__PR.value MM = M1 * M1 A = MM * (2. + self._gas.gm1 * MM) / ((PR * PR) * self._gas.gm1) B = 1. / self._gas.gm1 return np.sqrt(-B + np.sqrt(B * B + A))
[docs] def get_upstream_Mach_from_PR(self, *args: Any, **kwargs: Any) -> Union[np.float64, list[np.float64], float]: """Get upstream Mach number (M1 []) from downstream Mach number (M2 []) and pressure ratio (PR []) input: downstream Mach number (M2 []) and pressure ratio (PR []) supported data types: float, list[float], ndarray Parameters ---------- *args : Any arguments (optional input): 1. downstream Mach number 2. pressure ratio variable value(s) in above-listed order **kwargs : Any keyword-value pairs (optional input): valid keywords: 'M2', 'PR' Returns ------- float, ndarray upstream Mach number Examples -------- Basic usage: $_>>> from g3d import cflow $_>>> M1 = cflow.friction.get_upstream_Mach_from_PR(M2=0.8, PR=0.2) """ return self._eval(["PR", "M2"], self.__get_upstream_Mach_from_PR, *args, **kwargs)
def __get_upstream_Mach_from_PR(self, PR: float = None, M2: float = None) -> float: if M2 is None: M2 = self.__M2.value if PR is None: PR = self.__PR.value MM = M2 * M2 A = MM * (2. + self._gas.gm1 * MM) * PR * PR / self._gas.gm1 B = 1. / self._gas.gm1 return np.sqrt(-B + np.sqrt(B * B + A))
[docs] def get_downstream_Mach_from_TR(self, *args: Any, **kwargs: Any) -> Union[np.float64, list[np.float64], float]: """Get downstream Mach number (M2 []) from upstream Mach number (M1 []) and temperature ratio (TR []) input: upstream Mach number (M1 []) and temperature ratio (TR []) supported data types: float, list[float], ndarray Parameters ---------- *args : Any arguments (optional input): 1. upstream Mach number 2. temperature ratio variable value(s) in above-listed order **kwargs : Any keyword-value pairs (optional input): valid keywords: 'M1', 'TR' Returns ------- float, ndarray downstream Mach number Examples -------- Basic usage: $_>>> from g3d import cflow $_>>> M2 = cflow.friction.get_downstream_Mach_from_TR(M1=2.0, TR=0.9) """ return self._eval(["TR", "M1"], self.__get_downstream_Mach_from_TR, *args, **kwargs)
def __get_downstream_Mach_from_TR(self, TR: float = None, M1: float = None) -> float: if M1 is None: M1 = self.__M1.value if TR is None: TR = self.__TR.value MM = M1 * M1 return np.sqrt((((2. + self._gas.gm1 * MM) / TR) - 2) / self._gas.gm1)
[docs] def get_upstream_Mach_from_TR(self, *args: Any, **kwargs: Any) -> Union[np.float64, list[np.float64], float]: """Get upstream Mach number (M1 []) from downstream Mach number (M2 []) and temperature ratio (TR []) input: downstream Mach number (M2 []) and temperature ratio (TR []) supported data types: float, list[float], ndarray Parameters ---------- *args : Any arguments (optional input): 1. downstream Mach number 2. temperature ratio variable value(s) in above-listed order **kwargs : Any keyword-value pairs (optional input): valid keywords: 'M2', 'TR' Returns ------- float, ndarray upstream Mach number Examples -------- Basic usage: $_>>> from g3d import cflow $_>>> M1 = cflow.friction.get_upstream_Mach_from_TR(M2=0.8, TR=0.9) """ return self._eval(["TR", "M2"], self.__get_upstream_Mach_from_TR, *args, **kwargs)
def __get_upstream_Mach_from_TR(self, TR: float = None, M2: float = None) -> float: if M2 is None: M2 = self.__M2.value if TR is None: TR = self.__TR.value MM = M2 * M2 return np.sqrt((((2. + self._gas.gm1 * MM) * TR) - 2) / self._gas.gm1)
[docs] def get_downstream_Mach_from_RR(self, *args: Any, **kwargs: Any) -> Union[np.float64, list[np.float64], float]: """Get downstream Mach number (M2 []) from upstream Mach number (M1 []) and density ratio (RR []) input: upstream Mach number (M1 []) and density ratio (RR []) supported data types: float, list[float], ndarray Parameters ---------- *args : Any arguments (optional input): 1. upstream Mach number 2. density ratio variable value(s) in above-listed order **kwargs : Any keyword-value pairs (optional input): valid keywords: 'M1', 'RR' Returns ------- float, ndarray downstream Mach number Examples -------- Basic usage: $_>>> from g3d import cflow $_>>> M2 = cflow.friction.get_downstream_Mach_from_RR(M1=2.0, RR=0.25) """ return self._eval(["RR", "M1"], self.__get_downstream_Mach_from_RR, *args, **kwargs)
def __get_downstream_Mach_from_RR(self, RR: float = None, M1: float = None) -> float: if M1 is None: M1 = self.__M1.value if RR is None: RR = self.__RR.value MM = M1 * M1 return np.sqrt(2. / (RR * RR * ((2. / MM) + self._gas.gm1) - self._gas.gm1))
[docs] def get_upstream_Mach_from_RR(self, *args: Any, **kwargs: Any) -> Union[np.float64, list[np.float64], float]: """Get upstream Mach number (M1 []) from downstream Mach number (M2 []) and density ratio (RR []) input: downstream Mach number (M2 []) and density ratio (RR []) supported data types: float, list[float], ndarray Parameters ---------- *args : Any arguments (optional input): 1. downstream Mach number 2. density ratio variable value(s) in above-listed order **kwargs : Any keyword-value pairs (optional input): valid keywords: 'M2', 'RR' Returns ------- float, ndarray upstream Mach number Examples -------- Basic usage: $_>>> from g3d import cflow $_>>> M1 = cflow.friction.get_downstream_Mach_from_RR(M2=0.8, RR=0.25) """ return self._eval(["RR", "M2"], self.__get_upstream_Mach_from_RR, *args, **kwargs)
def __get_upstream_Mach_from_RR(self, RR: float = None, M2: float = None) -> float: if M2 is None: M2 = self.__M2.value if RR is None: RR = self.__RR.value MM = M2 * M2 return np.sqrt(2. / (((2. / MM) + self._gas.gm1) / (RR * RR) - self._gas.gm1))
[docs] def choked_supersonic_find_shock_Mach(self, *args: Any, **kwargs: Any) \ -> Union[np.float64, list[np.float64], float]: """ .. deprecated:: 2.6 redirects to :func:`choked_supersonic_get_shock_Mach` """ return self.choked_supersonic_get_shock_Mach(*args, **kwargs)
[docs] def choked_supersonic_get_shock_Mach(self, *args: Any, **kwargs: Any) \ -> Union[np.float64, list[np.float64], float]: """Finds Mach number (M []) upstream of shock in an over-choked (length longer than choked length) supersonic one-dimensional flow with friction. The Mach number is estimated using the built-in Newton-Raphson solver. input: inlet Mach number (M1 []), inlet temperature (T1 [K]), pipe length (L [m]), average Darcy friction factor (f []), and pipe diameter (D [m]) supported data types: float, list[float], ndarray Parameters ---------- *args : Any arguments (optional input): 1. inlet Mach number 2. inlet temperature [K] 3. pipe length [m] 4. average Darcy friction factor 5. pipe diameter [m] variable value(s) in above-listed order **kwargs : Any keyword-value pairs (optional input): valid keywords: 'M1', 'T1', 'f', 'D' Returns ------- float, ndarray shock Mach number Examples -------- Basic usage: $_>>> from g3d import cflow $_>>> M = cflow.friction.choked_supersonic_get_shock_Mach(M1=0.7, T1=300., f=0.005, D=0.1) """ self._newton.reset() return self._eval(["M1", "T1", "L", "f", "D"], self.__choked_supersonic_get_shock_Mach, *args, **kwargs)
def __choked_supersonic_get_shock_Mach(self, M1: float = None, T1: float = None, L: float = None, f: float = None, D: float = None) -> float: if M1 is None: M1 = self.__M1.value if L is None: L = self.__L.value if f is None: f = self.__f.value if D is None: D = self.__D.value if T1 is not None: self.__T1.value = T1 L = self.__calculate_length(M1, L, D, f) tolerance = self._newton.tolerance max_iter = self._newton.max_iter # verify that station 1 is supersonic if M1 <= 1.: print('shock location only works for supersonic flows') return -1 # verify that the specified length is longer than the supersonic choked length L1s = self.__get_L_star(M1, f, D) if L <= L1s: print('the specified length is shorter than the supersonic choked length - no shock needed') return M1 # test shock at station 1 to and verify that the specified pipe length is shorter than # the corresponding subsonic choked length M2 = self.__normal_shock.get_downstream_Mach(M1) L2s = self.__get_L_star(M2, f, D) if L > L2s: print('pipe length exceeds subsonic choked length - internal shock solution not possible') return -1 La = 0. dL = 0.1 self._mode = CFlowRegime.SUPERSONIC length_iter = 0 while length_iter < max_iter: length_iter += 1 Las = L1s - La Ma = self.__get_Mach_from_L_star(Las, f, D) Mb = self.__normal_shock.get_downstream_Mach(Ma) Lbs = self.__get_L_star(Mb, f, D) if np.abs(Lbs - (L - La)) > tolerance: if Lbs < (L - La): La -= dL dL = dL / 10. La += dL else: return Ma return M1
[docs] def get_L_star_from_diameter_and_massflow(self, *args: Any, **kwargs: Any) \ -> Union[np.float64, list[np.float64], float]: """Get choked length (Ls [m]) from pipe diameter (D [m]) and massflow (mp [kg/s]) input: pipe diameter (D [m]), massflow (mp [kg/s]), inlet pressure (P1 [Pa]), inlet temperature (T1 [K]), and average Darcy friction factor (f []) supported data types: float, list[float], ndarray Parameters ---------- *args : Any arguments (optional input): 1. pipe diameter [m] 2. massflow [kg/s] 3. inlet pressure [Pa] 4. inlet temperature [K] 5. average Darcy friction factor variable value(s) in above-listed order **kwargs : Any keyword-value pairs (optional input): valid keywords: 'D', 'mp', 'P1', 'T1', 'f' Returns ------- float, ndarray choked length [m] Examples -------- Basic usage: $_>>> from g3d import cflow $_>>> L_star = cflow.friction.get_L_star_from_diameter_and_massflow(D=0.1, mp=4.75, P1=1.e5, T1=300., f=0.005) """ return self._eval(["D", "mp", "P1", "T1", "f"], self.__get_L_star_from_diameter_and_massflow, *args, **kwargs)
def __get_L_star_from_diameter_and_massflow(self, D: float = None, mp: float = None, P1: float = None, T1: float = None, f: float = None) -> float: if D is None: D = self.__D.value if mp is None: mp = self.__mp.value if P1 is None: P1 = self.__P1.value if T1 is None: T1 = self.__T1.value if f is None: f = self.__f.value rho1 = self._gas.get_density(P1, T1) u1 = mp / (rho1 * 0.25 * np.pi * D ** 2) M1 = u1 / self._gas.get_speed_of_sound(T1) return self.__get_L_star(M1, f, D)
[docs] def find_pipe_diameter_from_massflow(self, *args: Any, **kwargs: Any) -> Union[np.float64, list[np.float64], float]: """ .. deprecated:: 2.6 redirects to :func:`get_pipe_diameter_from_massflow` """ return self.get_pipe_diameter_from_massflow(*args, **kwargs)
[docs] def get_pipe_diameter_from_massflow(self, *args: Any, **kwargs: Any) -> Union[np.float64, list[np.float64], float]: """Finds pipe diameter (D [m]) from specified massflow (mp [kg/s]). The pipe diameter is estimated using the built-in Newton-Raphson solver input: inlet temperature (T1 [K]), inlet pressure (P1 [Pa]), pipe length (L [m]), massflow (mp [kg/s]), and average Darcy friction factor (f []) supported data types: float, list[float], ndarray Parameters ---------- *args : Any arguments (optional input): 1. inlet temperature [K] 2. inlet pressure [Pa] 3. pipe length [m] 4. massflow [kg/s] 5. average Darcy friction factor variable value(s) in above-listed order **kwargs : Any keyword-value pairs (optional input): valid keywords: 'T1', 'P1', 'L', 'mp', 'f' Returns ------- float, ndarray diameter [m] Examples -------- Basic usage: $_>>> from g3d import cflow $_>>> D = cflow.friction.get_pipe_diameter_from_massflow(T1=300, P1=1.e5, L=2.0, mp=3.0, f=0.005) """ self._newton.reset() return self._eval(["T1", "P1", "L", "mp", "f"], self.__get_pipe_diameter_from_massflow, *args, **kwargs)
def __get_pipe_diameter_from_massflow(self, T1: float = None, P1: float = None, L: float = None, mp: float = None, f: float = None) -> float: if L is None: L = self.__L.value if T1 is not None: self.__T1.value = T1 if P1 is not None: self.__P1.value = P1 if mp is not None: self.__mp.value = mp if f is not None: self.__f.value = f newton = self._get_newton_kernel() newton.start_value = 0.1 newton.target_value = L return newton.solve(self.__get_L_star_from_diameter_and_massflow) # ================================================================ # TWO-STATION PROBLEMS # ================================================================ def __calculate_length(self, M1: float, L: float, D: float, f: float) -> float: if self._add_mode in [CFlowAdditionMode.FACTOR, CFlowAdditionMode.PERCENT]: if self._add_mode is CFlowAdditionMode.PERCENT: L /= 100. if L < 0: L *= self.__get_L_star(M1, f, D) / (1. + L) else: L *= self.__get_L_star(M1, f, D) self._add_mode = CFlowAdditionMode.ABSOLUTE return L
[docs] def get_upstream_flow_state_after_overchoking(self, *args: Any, **kwargs: Any) \ -> Union[Tuple[np.float64, ...], list[Tuple[np.float64, ...]]]: """Calculates upstream flow state under overchoking conditions (L>L*, subsonic) The upstream flow state is calculated based on prescribed total conditions at the upstream flow station (To [K], Po [Pa]), exit static pressure (P2 [Pa]), pipe length (L [m]) input: inlet total temperature (To [K]), inlet total pressure (Po [Pa]), exit static pressure (P2 [pa]), pipe length (L [m]), pipe diameter (D [m]), average Darcy friction factor (f []) supported data types: float, list[float], ndarray Parameters ---------- *args : Any arguments (optional input): 1. inlet total temperature [K] 2. inlet total pressure [Pa] 3. exit static pressure [Pa] 4. pipe length [m] 5. pipe diameter [m] 6. average Darcy friction factor variable value(s) in above-listed order **kwargs : Any keyword-value pairs (optional input): valid keywords: 'To', 'Po', 'P2', 'L', 'D', 'f' Returns ------- tuple[float], tuple[ndarray] upstream flow state: Mach number, temperature and pressure Examples -------- Basic usage: $_>>> from g3d import cflow $_>>> M1, T1, P1 = cflow.friction.get_upstream_flow_state_after_overchoking(To=300., Po=1.e5, P2=7.5e4, L=3., D=0.1, f=0.005) """ self._reset_eval(mode=CFlowRegime.SUBSONIC) self._newton.reset() return self._eval(["To", "Po", "P2", "L", "D", "f"], self.__get_upstream_flow_state_after_overchoking, *args, **kwargs, outdim=3)
def __get_upstream_flow_state_after_overchoking(self, To: float = None, Po: float = None, P2: float = None, L: float = None, D: float = None, f: float = None) -> tuple[float, float, float]: if To is None: To = self.__To.value if Po is None: Po = self.__Po.value if P2 is None: P2 = self.__P2.value if L is None: L = self.__L.value if D is None: D = self.__D.value if f is None: f = self.__f.value # calculate starting guess of the station 1 Mach number M1 = self.__get_Mach_from_L_star(L, f, D) P1 = self._stagnation.get_static_pressure(M=M1, Po=Po) Pe = self.__get_downstream_pressure(M1, P1, L, D, f) while Pe < P2: M1 *= 0.9 P1 = self._stagnation.get_static_pressure(M=M1, Po=Po) Pe = self.__get_downstream_pressure(M1, P1, L, D, f) dM = 0.1 while np.abs(Pe - P2) / P2 > self._newton.tolerance: M_tmp = M1 + dM P_tmp = self._stagnation.get_static_pressure(M=M_tmp, Po=Po) if self.__get_downstream_pressure(M_tmp, P_tmp, L, D, f) > P2: M1 += dM P1 = self._stagnation.get_static_pressure(M=M1, Po=Po) Pe = self.__get_downstream_pressure(M1, P1, L, D, f) else: dM /= 10. T1 = self._stagnation.get_static_temperature(M=M1, To=To) return M1, T1, P1
[docs] def get_upstream_flow_state_after_overchoking_2(self, *args: Any, **kwargs: Any) \ -> Union[Tuple[np.float64, ...], list[Tuple[np.float64, ...]]]: """Calculates upstream flow state under overchoking conditions (L>L*, subsonic) The upstream flow state is calculated based on prescribed total conditions at the upstream flow station (To [K], Po [Pa]), exit static pressure (P2 [Pa]), pipe length (L [m]) input: inlet mach number (M1 []), inlet static temperature (T1 [K]), inlet static pressure (P1 [Pa]), pipe length (L [m]), pipe diameter (D [m]), average Darcy friction factor (f []) supported data types: float, list[float], ndarray Parameters ---------- *args : Any arguments (optional input): 1. inlet mach number 2. inlet static temperature [K] 3. inlet static pressure [Pa] 4. pipe length [m] 5. pipe diameter [m] 6. average Darcy friction factor variable value(s) in above-listed order **kwargs : Any keyword-value pairs (optional input): valid keywords: 'M1', 'T1', 'P1', 'L', 'D', 'f' Returns ------- tuple[float], tuple[ndarray] upstream flow state: Mach number, temperature [K] and pressure [Pa] Examples -------- Basic usage: $_>>> from g3d import cflow $_>>> M1, T1, P1 = cflow.friction.get_upstream_flow_state_after_overchoking_2(M1=2.0, T1=300., P1=1.e5, L=10., D=0.1, f=0.005) """ self._reset_eval(mode=CFlowRegime.SUBSONIC) self._newton.reset() return self._eval(["M1", "T1", "P1", "L", "D", "f"], self.__get_upstream_flow_state_after_overchoking_2, *args, **kwargs, outdim=3)
def __get_upstream_flow_state_after_overchoking_2(self, M1: float = None, T1: float = None, P1: float = None, L: float = None, D: float = None, f: float = None) -> tuple[float, float, float]: if M1 is None: M1 = self.__M1.value if T1 is None: T1 = self.__T1.value if P1 is None: P1 = self.__P1.value if L is None: L = self.__L.value if D is None: D = self.__D.value if f is None: f = self.__f.value L = self.__calculate_length(M1, L, D, f) Po = self._stagnation.get_total_pressure(M=M1, P=P1) To = self._stagnation.get_total_temperature(M=M1, T=T1) Ps = self.__get_P_star(M1, P1) return self.__get_upstream_flow_state_after_overchoking(To, Po, Ps, L, D, f)
[docs] def get_downstream_pressure(self, *args: Any, **kwargs: Any) -> Union[np.float64, list[np.float64], float]: """Two-station problem: Calculates downstream pressure (P2 [Pa]) based on upstream pressure (P1 [Pa]), upstream Mach number (M1 []), and pipe length (L [m]) input: upstream Mach number (M1 []), upstream static pressure (P1 [Pa]), pipe length (L [m]), pipe diameter (D [m]), average Darcy friction factor (f []) additional input: mode = 'subsonic' (default if not specified) or mode = 'supersonic' supported data types: float, list[float], ndarray Parameters ---------- *args : Any arguments (optional input): 1. upstream Mach number 2. upstream static pressure [Pa] 3. pipe length [m] 4. pipe diameter [m] 5. average Darcy friction factor variable value(s) in above-listed order **kwargs : Any keyword-value pairs (optional input): valid keywords: 'M1', 'P1', 'L', 'D', 'f', 'mode' Returns ------- float, ndarray downstream pressure [Pa] Examples -------- Basic usage: $_>>> from g3d import cflow $_>>> P2 = cflow.friction.get_downstream_pressure(M1=2.0, P1=1.e5, L=10., D=0.1, f=0.005, mode='subsonic') """ self._reset_eval(mode=CFlowRegime.SUBSONIC) self._newton.reset() return self._eval(["M1", "P1", "L", "D", "f"], self.__get_downstream_pressure, *args, **kwargs)
def __get_downstream_pressure(self, M1: float = None, P1: float = None, L: float = None, D: float = None, f: float = None) -> float: if M1 is None: M1 = self.__M1.value if P1 is None: P1 = self.__P1.value if L is None: L = self.__L.value if D is None: D = self.__D.value if f is None: f = self.__f.value L = self.__calculate_length(M1, L, D, f) Ps = self.__get_P_star(M1, P1) Ls1 = self.__get_L_star(M1, f, D) Ls2 = Ls1 - L if Ls2 < 0: return -1 M2 = self.__get_Mach_from_L_star(Ls2, f, D) P2 = self.__get_P(M2, Ps) return P2
[docs] def get_upstream_pressure(self, *args: Any, **kwargs: Any) -> Union[np.float64, list[np.float64], float]: """Two-station problem: Calculates upstream pressure (P1 [Pa]) based on downstream pressure (P2 [Pa]), downstream Mach number (M2 []), and pipe length (L [m]) input: downstream Mach number (M2 []), downstream static pressure (P2 [Pa]), pipe length (L [m]), pipe diameter (D [m]), average Darcy friction factor (f []) additional input: mode = 'subsonic' (default if not specified) or mode = 'supersonic' supported data types: float, list[float], ndarray Parameters ---------- *args : Any arguments (optional input): 1. downstream Mach number 2. downstream static pressure [Pa] 3. pipe length [m] 4. pipe diameter [m] 5. average Darcy friction factor variable value(s) in above-listed order **kwargs : Any keyword-value pairs (optional input): valid keywords: 'M2', 'P2', 'L', 'D', 'f', 'mode' Returns ------- float, ndarray upstream pressure [Pa] Examples -------- Basic usage: $_>>> from g3d import cflow $_>>> P1 = cflow.friction.get_upstream_pressure(M2=0.8, P2=1.e5, L=10., D=0.1, f=0.005, mode='subsonic') """ self._reset_eval(mode=CFlowRegime.SUBSONIC) self._newton.reset() return self._eval(["M2", "P2", "L", "D", "f"], self.__get_upstream_pressure, *args, **kwargs)
def __get_upstream_pressure(self, M2: float = None, P2: float = None, L: float = None, D: float = None, f: float = None) -> float: if M2 is None: M2 = self.__M2.value if P2 is None: P2 = self.__P2.value if L is None: L = self.__L.value return self.__get_downstream_pressure(M2, P2, -L, D, f)
[docs] def get_downstream_Mach(self, *args: Any, **kwargs: Any) -> Union[np.float64, list[np.float64], float]: """Two-station problem: Calculates downstream Mach number (M2 []) based on upstream Mach number (M1 []) and pipe length (L [m]) input: upstream Mach number (M1 []), pipe length (L [m]), pipe diameter (D [m]), average Darcy friction factor (f []) additional input: mode = 'subsonic' (default if not specified) or mode = 'supersonic' supported data types: float, list[float], ndarray Parameters ---------- *args : Any arguments (optional input): 1. upstream Mach number 2. pipe length [m] 3. pipe diameter [m] 4. average Darcy friction factor variable value(s) in above-listed order **kwargs : Any keyword-value pairs (optional input): valid keywords: 'M1', 'L', 'D', 'f', 'mode' Returns ------- float, ndarray downstream Mach number Examples -------- Basic usage: $_>>> from g3d import cflow $_>>> M2 = cflow.friction.get_downstream_Mach(M1=2.0, L=10., D=0.1, f=0.005, mode='subsonic') """ self._reset_eval(mode=CFlowRegime.SUBSONIC) self._newton.reset() return self._eval(["M1", "L", "D", "f"], self.__get_downstream_Mach, *args, **kwargs)
def __get_downstream_Mach(self, M1: float = None, L: float = None, D: float = None, f: float = None) -> float: if M1 is None: M1 = self.__M1.value if L is None: L = self.__L.value if D is None: D = self.__D.value if f is None: f = self.__f.value L = self.__calculate_length(M1, L, D, f) Ls1 = self.__get_L_star(M1, f, D) Ls2 = Ls1 - L if Ls2 < 0: return -1 M2 = self.__get_Mach_from_L_star(Ls2, f, D) return M2
[docs] def get_upstream_Mach(self, *args: Any, **kwargs: Any) -> Union[np.float64, list[np.float64], float]: """Two-station problem: Calculates upstream Mach number (M1 []) based on downstream Mach number (M2 []) and pipe length (L [m]) input: downstream Mach number (M2 []), pipe length (L [m]), pipe diameter (D [m]), average Darcy friction factor (f []) additional input: mode = 'subsonic' (default if not specified) or mode = 'supersonic' supported data types: float, list[float], ndarray Parameters ---------- *args : Any arguments (optional input): 1. downstream Mach number 2. pipe length [m] 3. pipe diameter [m] 4. average Darcy friction factor variable value(s) in above-listed order **kwargs : Any keyword-value pairs (optional input): valid keywords: 'M2', 'L', 'D', 'f', 'mode' Returns ------- float, ndarray upstream Mach number Examples -------- Basic usage: $_>>> from g3d import cflow $_>>> M1 = cflow.friction.get_upstream_Mach(M2=0.8, L=10., D=0.1, f=0.005, mode='subsonic') """ self._reset_eval(mode=CFlowRegime.SUBSONIC) self._newton.reset() return self._eval(["M2", "L", "D", "f"], self.__get_upstream_Mach, *args, **kwargs)
def __get_upstream_Mach(self, M2: float = None, L: float = None, D: float = None, f: float = None) -> float: if M2 is None: M2 = self.__M2.value if L is None: L = self.__L.value if D is None: D = self.__D.value if f is None: f = self.__f.value return self.__get_downstream_Mach(M2, -L, D, f)
[docs] def get_downstream_temperature(self, *args: Any, **kwargs: Any) -> Union[np.float64, list[np.float64], float]: """Two-station problem: Calculates downstream temperature (T2 [K]) based on upstream temperature (T1 [K]), upstream Mach number (M1 []), and pipe length (L [m]) input: upstream Mach number (M1 []), upstream static temperature (T1 [K]), pipe length (L [m]), pipe diameter (D [m]), average Darcy friction factor (f []) additional input: mode = 'subsonic' (default if not specified) or mode = 'supersonic' supported data types: float, list[float], ndarray Parameters ---------- *args : Any arguments (optional input): 1. upstream Mach number 2. upstream static temperature [K] 3. pipe length [m] 4. pipe diameter [m] 5. average Darcy friction factor variable value(s) in above-listed order **kwargs : Any keyword-value pairs (optional input): valid keywords: 'M1', 'T1', 'L', 'D', 'f', 'mode' Returns ------- float, ndarray downstream temperature [K] Examples -------- Basic usage: $_>>> from g3d import cflow $_>>> T2 = cflow.friction.get_downstream_temperature(M1=0.8, T1=300., L=10., D=0.1, f=0.005, mode='subsonic') """ self._reset_eval(mode=CFlowRegime.SUBSONIC) self._newton.reset() return self._eval(["M1", "T1", "L", "D", "f"], self.__get_downstream_temperature, *args, **kwargs)
def __get_downstream_temperature(self, M1: float = None, T1: float = None, L: float = None, D: float = None, f: float = None) -> float: if M1 is None: M1 = self.__M1.value if T1 is None: T1 = self.__T1.value if L is None: L = self.__L.value if D is None: D = self.__D.value if f is None: f = self.__f.value L = self.__calculate_length(M1, L, D, f) Ts = self.__get_T_star(M1, T1) Ls1 = self.__get_L_star(M1, f, D) Ls2 = Ls1 - L if Ls2 < 0: return -1 M2 = self.__get_Mach_from_L_star(Ls2, f, D) T2 = self.__get_T(M2, Ts) return T2
[docs] def get_upstream_temperature(self, *args: Any, **kwargs: Any) -> Union[np.float64, list[np.float64], float]: """Two-station problem: Calculates upstream temperature (T1 [K]) based on downstream temperature (T2 [K]), downstream Mach number (M2 []), and pipe length (L [m]) input: downstream Mach number (M2 []), downstream static temperature (T2 [K]), pipe length (L [m]), pipe diameter (D [m]), average Darcy friction factor (f []) additional input: mode = 'subsonic' (default if not specified) or mode = 'supersonic' supported data types: float, list[float], ndarray Parameters ---------- *args : Any arguments (optional input): 1. downstream Mach number 2. downstream static temperature [K] 3. pipe length [m] 4. pipe diameter [m] 5. average Darcy friction factor variable value(s) in above-listed order **kwargs : Any keyword-value pairs (optional input): valid keywords: 'M2', 'T2', 'L', 'D', 'f', 'mode' Returns ------- float, ndarray upstream temperature [K] Examples -------- Basic usage: $_>>> from g3d import cflow $_>>> T1 = cflow.friction.get_upstream_temperature(M2=0.8, T2=300., L=10., D=0.1, f=0.005, mode='subsonic') """ self._reset_eval(mode=CFlowRegime.SUBSONIC) self._newton.reset() return self._eval(["M2", "T2", "L", "D", "f"], self.__get_upstream_temperature, *args, **kwargs)
def __get_upstream_temperature(self, M2: float = None, T2: float = None, L: float = None, D: float = None, f: float = None) -> float: if M2 is None: M2 = self.__M2.value if T2 is None: T2 = self.__T2.value if L is None: L = self.__L.value return self.__get_downstream_temperature(M2, T2, -L, D, f)
[docs] def get_downstream_flow_state(self, *args: Any, **kwargs: Any) \ -> Union[Tuple[np.float64, ...], list[Tuple[np.float64, ...]]]: """Two-station problem: Calculates downstream flow state (Mach number (M2 []), temperature (T2 [K]), and pressure (P2 [Pa])) based on upstream flow state (Mach number (M1 []), temperature (T1 [K]), and pressure (P1 [Pa])), and pipe length (L [m]) input: upstream Mach number (M1 []), upstream static temperature (T1 [K]), upstream static pressure (P1 [Pa]), pipe length (L [m]), pipe diameter (D [m]), average Darcy friction factor (f []) additional input: mode = 'subsonic' (default if not specified) or mode = 'supersonic' supported data types: float, list[float], ndarray Parameters ---------- *args : Any arguments (optional input): 1. upstream Mach number 2. upstream static temperature [K] 3. upstream static pressure [Pa] 4. pipe length [m] 5. pipe diameter [m] 6. average Darcy friction factor variable value(s) in above-listed order **kwargs : Any keyword-value pairs (optional input): valid keywords: 'M1', 'T1', 'P1', 'L', 'D', 'f', 'mode' Returns ------- tuple[float], tuple[ndarray] downstream flowstate: Mach number, temperature [K], pressure [Pa] Examples -------- Basic usage: $_>>> from g3d import cflow $_>>> M2, T2, P2 = cflow.friction.get_downstream_flow_state(M1=2.0, T1=300., P1=1.e5, L=10., D=0.1, f=0.005, mode='subsonic') """ self._reset_eval(mode=CFlowRegime.SUBSONIC) self._newton.reset() return self._eval(["M1", "T1", "P1", "L", "D", "f"], self.__get_downstream_flow_state, *args, **kwargs, outdim=3)
def __get_downstream_flow_state(self, M1: float = None, T1: float = None, P1: float = None, L: float = None, D: float = None, f: float = None) -> tuple[float, float, float]: if M1 is None: M1 = self.__M1.value if T1 is None: T1 = self.__T1.value if P1 is None: P1 = self.__P1.value if L is None: L = self.__L.value if D is None: D = self.__D.value if f is None: f = self.__f.value L = self.__calculate_length(M1, L, D, f) Ts = self.__get_T_star(M1, T1) Ps = self.__get_P_star(M1, P1) Ls1 = self.__get_L_star(M1, f, D) Ls2 = Ls1 - L if Ls2 < 0: print('over choking') return -1, -1, -1 # if self._mode is CFlowRegime.SUPERSONIC: # return 1., Ts, Ps # else: # Po = self._stagnation.get_total_pressure(M=M1, P=P1) # To = self._stagnation.get_total_temperature(M=M1, T=T1) # M1, T1, P1 = self.__get_upstream_flow_state_after_overchoking(To, Po, Ps, L, D, f) # Ts = self.__get_T_star(M1, T1) # Ps = self.__get_P_star(M1, P1) # Ls1 = self.__get_L_star(M1, f, D) # Ls2 = Ls1 - L M2 = self.__get_Mach_from_L_star(Ls2, f, D) T2 = self.__get_T(M2, Ts) P2 = self.__get_P(M2, Ps) return M2, T2, P2
[docs] def get_upstream_flow_state(self, *args: Any, **kwargs: Any) \ -> Union[Tuple[np.float64, ...], list[Tuple[np.float64, ...]]]: """Two-station problem: Calculates upstream flow state (Mach number (M1 []), temperature (T1 [K]), and pressure (P1 [Pa])) based on downstream flow state (Mach number (M2 []), temperature (T2 [K]), and pressure (P2 [Pa])), and pipe length (L [m]) input: downstream Mach number (M2 []), downstream static temperature (T2 [K]), downstream static pressure (P2 [Pa]), pipe length (L [m]), pipe diameter (D [m]), average Darcy friction factor (f []) additional input: mode = 'subsonic' (default if not specified) or mode = 'supersonic' supported data types: float, list[float], ndarray Parameters ---------- *args : Any arguments (optional input): 1. downstream Mach number 2. downstream static temperature [K] 3. downstream static pressure [Pa] 4. pipe length [m] 5. pipe diameter [m] 6. average Darcy friction factor variable value(s) in above-listed order **kwargs : Any keyword-value pairs (optional input): valid keywords: 'M2', 'T2', 'P2', 'L', 'D', 'f', 'mode' Returns ------- tuple[float], tuple[ndarray] upstream flowstate: Mach number, temperature [K], pressure [Pa] Examples -------- Basic usage: $_>>> from g3d import cflow $_>>> M1, T1, P1 = cflow.friction.get_upstream_flow_state(M2=0.8, T2=300., P2=1.e5, L=10., D=0.1, f=0.005, mode='subsonic') """ self._reset_eval(mode=CFlowRegime.SUBSONIC) self._newton.reset() return self._eval(["M2", "T2", "P2", "L", "D", "f"], self.__get_upstream_flow_state, *args, **kwargs, outdim=3)
def __get_upstream_flow_state(self, M2: float = None, T2: float = None, P2: float = None, L: float = None, D: float = None, f: float = None) -> tuple[float, float, float]: if M2 is None: M2 = self.__M2.value if T2 is None: T2 = self.__T2.value if P2 is None: P2 = self.__P2.value if L is None: L = self.__L.value return self.__get_downstream_flow_state(M2, T2, P2, -L, D, f) # ================================================================ # PROCESS DIAGRAM DATA GENERATION # ================================================================
[docs] def process_diagram_get_HS(self, M: Union[float, list[float], ndarray]) \ -> Union[Tuple[float, float], Tuple[list[float], list[float]], Tuple[ndarray, ndarray]]: """Extract HS-diagram data for one dimensional flow with friction input: Mach number (M []) Parameters ---------- M : float, list[float], or ndarray : Mach number(s) Returns ------- tuple H, Ds tuple[float, float], tuple[list[float], list[float]], tuple[ndarray, ndarray] Examples -------- Basic usage: $_>>> from g3d import cflow $_>>> H, Ds = cflow.friction.process_diagram_get_HS(M) """ H = self._stagnation.get_total_temperature(M) ** (-1) A = ((H ** (-1)) - 1.) ** (self._gas.gm1 / (2. * self._gas.gamma)) B = (2. / self._gas.gm1) ** (self._gas.gm1 / (2. * self._gas.gamma)) C = (self._gas.gp1 / 2.) ** (self._gas.gp1 / (2. * self._gas.gamma)) D = H ** (self._gas.gp1 / (2. * self._gas.gamma)) DS = np.log(A * B * C * D) return H, DS
def __process_diagram_TS_get_delta(self, M: float, T: float, ds: float) -> tuple[float, float]: M2 = M * M C1 = (1. / (self._gas.R * (1. - M2))) * ds dT = T * (1. - self._gas.gamma) * M2 * C1 dM = M * (1. + 0.5 * self._gas.gm1 * M2) * C1 return dT, dM
[docs] def process_diagram_get_TS(self, T1: float, S1: float, M1: float, Ds: float, N: int) -> Tuple[np.ndarray, ...]: """Extract Ts-diagram data for one dimensional flow with friction input: initial temperature (T1 [K]), initial entropy (S1 [J/K]), initial Mach number (M1 []), entropy increment (Ds [J/K]), number of points (N) Parameters ---------- T1 : float : temperature (T1) [K] S1 : float : entropy (S1) [J/K] M1 : float : Mach number Ds : float : entropy change [J/K] N : int : number of points Returns ------- tuple T, S tuple[ndarray, ...] Examples -------- Basic usage: $_>>> from g3d import cflow $_>>> T, S = cflow.friction.process_diagram_get_TS(T1, S1, M1, Ds, N) """ ds = Ds / float(N) T = T1 S = S1 M = M1 T_array = np.zeros(N) S_array = np.zeros(N) T_array[0] = T S_array[0] = S for i in range(1, N): dT, dM = self.__process_diagram_TS_get_delta(M, T, ds) T = T + dT S = S + ds M = M + dM T_array[i] = T S_array[i] = S return T_array, S_array