"""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