"""Expansion wave calculator"""
import os
if os.environ.get('__USE_CUDA', '0') == '1':
import cupy as np
else:
import numpy as np
from typing import Tuple, Union, Any
from .calculator import G3DCalculator
from g3d.defs import CFlowVariableType
from g3d.defs import AngleType
[docs]
class G3DExpansionWaveCalculator(G3DCalculator):
"""Class collecting functions related to Prandtl-Meyer expansions"""
def __init__(self, *args: Any, **kwargs: Any) -> None:
"""Initialize calculator parameters"""
super().__init__(*args, **kwargs)
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="Mach number")
self.__theta = self._vars.add(name="theta", long_name="Flow deflection angle", type=CFlowVariableType.RADIANS)
[docs]
def get_Prandtl_Meyer_function(self, *args: Any, **kwargs: Any) -> Union[Union[tuple[Any, ...], list[Any]], Any]:
"""Evaluates Prandtl-Meyer function for specified Mach number
the value calculated is given in radians unless angle_type=AngleType.DEGREES is specified
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', 'angle_type'
Returns
-------
float, ndarray
Prandtl-Meyer function value (nu) [rad or deg]
Examples
--------
Basic usage:
$_>>> from g3d import cflow
$_>>> nu = cflow.expansion.get_Prandtl_Meyer_function(M=2.5, angle_type=AngleType.DEGREES)
"""
return self._eval(["M"], self.__get_Prandtl_Meyer_function, *args, **kwargs)
def __get_Prandtl_Meyer_function(self, M: float = None) -> float:
if M is None:
M = self.__M.value
return (np.sqrt(self._gas.gp1 / self._gas.gm1)
* np.arctan(np.sqrt((self._gas.gm1 / self._gas.gp1) * (M * M - 1.)))
- np.arctan(np.sqrt(M * M - 1.)))
[docs]
def find_Mach(self, *args: Any, **kwargs: Any) -> Union[Union[tuple[Any, ...], list[Any]], Any]:
"""
.. deprecated:: 2.6
redirects to :func:`get_Mach`
"""
return self.get_Mach(*args, **kwargs)
[docs]
def get_Mach(self, *args: Any, **kwargs: Any) -> Union[Union[tuple[Any, ...], list[Any]], Any]:
"""Finds Mach number corresponding to specified Prandtl-Meyer function value using the built-in Newton-Raphson
solver the Prandtl-Meyer function value should be specified in radians unless angle_type=AngleType.DEGREES is
specified
input: Prandtl-Meyer value (theta [rad or deg])
supported data types: float, list[float], ndarray
Parameters
----------
*args : Any
arguments (optional input):
Prandtl-Meyer [rad or deg] value(s)
**kwargs : Any
keyword-value pairs (optional input):
valid keywords: 'theta', 'angle_type'
Returns
-------
float, ndarray
Mach number
Examples
--------
Basic usage:
$_>>> from g3d import cflow
$_>>> M = cflow.expansion.get_Mach(theta=10., angle_type=AngleType.DEGREES)
"""
self._newton.reset()
return self._eval(["theta"], self.__get_Mach, *args, **kwargs)
def __get_Mach(self, theta: float = None, angle_type: Any = AngleType.UNDEFINED) -> float:
if theta is None:
theta = self.__theta.value
theta = self._angle_import(theta, angle_type=angle_type)
newton = self._get_newton_kernel()
newton.start_value = 1.5
newton.target_value = theta
# run Newton solver to find deflection angle
return newton.solve(self.__get_Prandtl_Meyer_function)
[docs]
def analyze_expansion_region(self, *args: Any, **kwargs: Any) \
-> Union[Tuple[np.float64, ...], list[Tuple[np.float64, ...]]]:
"""Calculate pressure ratio (PR21 []), temperature ratio (TR21 []), and downstream Mach number (M2 []) for
specified upstream Mach number (M1 []) and flow deflection (theta)
flow deflection should be given in radians unless angle_type=AngleType.DEGREES is specified
input: upstream Mach number (M1 []) and flow deflection (theta [rad or deg])
supported data types: float, list[float], ndarray
Parameters
----------
*args : Any
arguments (optional input):
1. upstream Mach number
2. flow deflection [rad or deg]
variable value(s) in above-listed order
**kwargs : Any
keyword-value pairs (optional input):
valid keywords: 'M1', 'theta', 'angle_type'
Returns
-------
tuple[float], tuple[ndarray]
flow expansion properties: downstream Mach number, pressure ratio, temperature ratio
Examples
--------
Basic usage:
$_>>> from g3d import cflow
$_>>> M2, PR21, TR21 = cflow.expansion.analyze_expansion_region(M1=2.5, theta=10., angle_type=AngleType.DEGREES)
"""
self._reset_eval(outdim=3)
return self._eval(["M1", "theta"], self.__analyze_expansion_region, *args, **kwargs)
def __analyze_expansion_region(self, M1: float = None, theta: float = None,
angle_type: Any = AngleType.UNDEFINED) -> tuple[float, float, float]:
if M1 is None:
M1 = self.__M1.value
if theta is None:
theta = self.__theta.value
self.__M.value = M1
theta = self._angle_import(theta, angle_type=angle_type)
nu1 = self.__get_Prandtl_Meyer_function(M1)
nu2 = nu1 + theta
M2 = self.__get_Mach(nu2, AngleType.RADIANS)
PR21 = self._stagnation.get_total_pressure(M1, 1.) / self._stagnation.get_total_pressure(M2, 1.)
TR21 = self._stagnation.get_total_temperature(M1, 1.) / self._stagnation.get_total_temperature(M2, 1.)
return M2, PR21, TR21