"""Moving shock wave calculator"""
import os
from typing import Union, Any
if os.environ.get('__USE_CUDA', '0') == '1':
import cupy as np
else:
import numpy as np
from .calculator import G3DCalculator
from g3d.defs import CFlowVariableType
from .normal_shock import G3DNormalShockCalculator
[docs]
class G3DMovingShockCalculator(G3DCalculator):
"""Class collecting functions related to moving shock waves"""
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.__Ms = self._vars.add(name="Ms", long_name="Mach number of incident shock wave")
self.__Mr = self._vars.add(name="Mr", long_name="Mach number of reflected shock wave")
self.__Up = self._vars.add(name="Up", long_name="Induced flow velocity", type=CFlowVariableType.VELOCITY)
self.__PR21 = self._vars.add(name="PR21", long_name="Pressure ratio P2/P1")
self.__PR51 = self._vars.add(name="PR51", long_name="Pressure ratio P5/P1")
self.__TR51 = self._vars.add(name="TR51", long_name="Temperature ratio T5/T1")
self.__T1 = self._vars.add(name="T1", long_name="Temperature (region 1)", type=CFlowVariableType.TEMPERATURE)
def _associate(self) -> None:
super()._associate()
self.__normal_shock.gas = self._gas
[docs]
def get_Ms(self, *args: Any, **kwargs: Any) -> Union[Union[tuple[Any, ...], list[Any]], Any]:
"""
calculates incident shock Mach number (Ms []) corresponding to specified shock pressure ratio (PR21 [])
input: shock pressure ratio (PR21 [])
example: Ms = get_Ms(PR21=PR21)
"""
return self._eval(["PR21"], self.__get_Ms, *args, **kwargs)
def __get_Ms(self, PR21: float = None) -> float:
if PR21 is None:
PR21 = self.__PR21.value
return np.sqrt((self._gas.gp1 / (2. * self._gas.gamma)) * (PR21 - 1.) + 1.)
[docs]
def get_up(self, *args: Any, **kwargs: Any) -> Union[Union[tuple[Any, ...], list[Any]], Any]:
"""
calculates induced flow velocity (Up [m/s], velocity behind incident shock) corresponding to specified
shock pressure ratio (PR21 []) and temperature in front of incident shock (T1 [K])
input: shock pressure ratio (PR21 []), temperature in front of incident shock (T1 [K])
example: Up = get_up(PR21=PR21, T1=T1)
"""
return self._eval(["PR21", "T1"], self.__get_up, *args, **kwargs)
def __get_up(self, PR21: float = None, T1: float = None) -> float:
if PR21 is None:
PR21 = self.__PR21.value
if T1 is None:
T1 = self.__T1.value
return ((self._gas.get_speed_of_sound(T1) / self._gas.gamma) * (PR21 - 1.)
* np.sqrt((2. * self._gas.gamma / self._gas.gp1)
/ (PR21 + self._gas.gm1 / self._gas.gp1)))
[docs]
def get_temperature_ratio(self, *args: Any, **kwargs: Any) -> Union[Union[tuple[Any, ...], list[Any]], Any]:
"""
calculates shock temperature ratio (TR21 []) corresponding to specified shock pressure ratio (PR21 [])
input: shock pressure ratio (PR21 [])
example TR21 = get_temperature_ratio(PR21=PR21)
"""
return self._eval(["PR21"], self.__get_temperature_ratio, *args, **kwargs)
def __get_temperature_ratio(self, PR21: float = None) -> float:
if PR21 is None:
PR21 = self.__PR21.value
return PR21 * (((self._gas.gp1 / self._gas.gm1) + PR21) / (1. + (self._gas.gp1 / self._gas.gm1) * PR21))
[docs]
def get_density_ratio(self, *args: Any, **kwargs: Any) -> Union[Union[tuple[Any, ...], list[Any]], Any]:
"""
calculates shock density ratio (RR21 []) corresponding to specified shock pressure ratio (PR21 [])
input: shock pressure ratio (PR21 [])
example RR21 = get_density_ratio(PR21=PR21)
"""
return self._eval(["PR21"], self.__get_density_ratio, *args, **kwargs)
def __get_density_ratio(self, PR21: float = None) -> float:
if PR21 is None:
PR21 = self.__PR21.value
return (1. + (self._gas.gp1 / self._gas.gm1) * PR21) / ((self._gas.gp1 / self._gas.gm1) + PR21)
[docs]
def get_Mr(self, *args: Any, **kwargs: Any) -> Union[Union[tuple[Any, ...], list[Any]], Any]:
"""
calculates reflected shock Mach number (Mr []) corresponding to specified incident shock Mach number (Ms [])
input: incident shock Mach number (Ms [])
example: Mr = get_Mr(Ms=Ms)
"""
return self._eval(["Ms"], self.__get_Mr, *args, **kwargs)
def __get_Mr(self, Ms: float = None) -> float:
if Ms is None:
Ms = self.__Ms.value
a = (Ms / (Ms * Ms - 1.)) * np.sqrt(1. + (2. * self._gas.gm1 * (Ms * Ms - 1.)
* (self._gas.gamma + (1. / (Ms * Ms)))
/ (self._gas.gp1 * self._gas.gp1)))
b = (1. / (2. * a))
return b + np.sqrt(b * b + 1.)
[docs]
def get_Mr_from_PR21(self, *args: Any, **kwargs: Any) -> Union[Union[tuple[Any, ...], list[Any]], Any]:
"""
calculates reflected shock Mach number (Mr []) corresponding to specified
incident shock pressure ratio (PR21 [])
input: incident shock Mach number (Ms [])
example: Mr = get_Mr_from_PR21(PR21=PR21)
"""
return self._eval(["PR21"], self.__get_Mr_from_PR21, *args, **kwargs)
def __get_Mr_from_PR21(self, PR21: float = None) -> float:
if PR21 is None:
PR21 = self.__PR21.value
return self.__get_Mr(self.__get_Ms(PR21))
[docs]
def get_PR51_from_PR21(self, *args: Any, **kwargs: Any) -> Union[Union[tuple[Any, ...], list[Any]], Any]:
"""
calculates ratio of pressure behind reflected shock (P5) and pressure in the undisturbed flow ahead of the
incident shock (P1) (PR51 []) from specified incident shock pressure ratio (PR21 [])
input: incident shock pressure ratio (PR21 [])
example: PR51 = get_PR51_from_PR21(PR21=PR21)
"""
return self._eval(["PR21"], self.__get_PR51_from_PR21, *args, **kwargs)
def __get_PR51_from_PR21(self, PR21: float = None) -> float:
if PR21 is None:
PR21 = self.__PR21.value
return PR21 * self.__normal_shock.get_downstream_pressure(self.get_Mr_from_PR21(PR21))
[docs]
def get_TR51_from_PR21(self, *args: Any, **kwargs: Any) -> Union[Union[tuple[Any, ...], list[Any]], Any]:
"""
calculates ratio of temperature behind reflected shock (T5) and temperature in the undisturbed flow ahead of the
incident shock (T1) (TR51 []) from specified incident shock pressure ratio (PR21 [])
input: incident shock pressure ratio (PR21 [])
example: TR51 = get_TR51_from_PR21(PR21=PR21)
"""
return self._eval(["PR21"], self.__get_TR51_from_PR21, *args, **kwargs)
def __get_TR51_from_PR21(self, PR21: float = None) -> float:
if PR21 is None:
PR21 = self.__PR21.value
return self.__get_temperature_ratio(PR21) * \
self.__normal_shock.get_downstream_temperature(self.__get_Mr_from_PR21(PR21))
[docs]
def find_PR21_from_Ms(self, *args: Any, **kwargs: Any) -> Union[Union[tuple[Any, ...], list[Any]], Any]:
"""
.. deprecated:: 2.6
redirects to :func:`get_PR21_from_Ms`
"""
return self.get_PR21_from_Ms(*args, **kwargs)
[docs]
def get_PR21_from_Ms(self, *args: Any, **kwargs: Any) -> Union[Union[tuple[Any, ...], list[Any]], Any]:
"""
calculates pressure ratio of incident shock (PR21 []) from shock Mach number (Ms [])
input: incident shock Mach number (Ms [])
example PR21 = get_PR21_from_Ms(Ms=Ms)
"""
return self._eval(["Ms"], self.__get_PR21_from_Ms, *args, **kwargs)
def __get_PR21_from_Ms(self, Ms: float = None) -> float:
if Ms is None:
Ms = self.__Ms.value
return ((Ms ** 2 - 1.0) * 2.0 * self._gas.gamma / self._gas.gp1) + 1.0
[docs]
def find_PR21_from_Mr(self, *args: Any, **kwargs: Any) -> Union[Union[tuple[Any, ...], list[Any]], Any]:
"""
.. deprecated:: 2.6
redirects to :func:`get_PR21_from_Mr`
"""
return self.get_PR21_from_Mr(*args, **kwargs)
[docs]
def get_PR21_from_Mr(self, *args: Any, **kwargs: Any) -> Union[Union[tuple[Any, ...], list[Any]], Any]:
"""
calculates pressure ratio of incident shock (PR21 []) from reflected shock Mach number (Mr [])
the pressure ratio is calculated using the built-in Newton-Raphson solver
input: reflected shock Mach number (Mr [])
example PR21 = get_PR21_from_Mr(Mr=Mr)
"""
self._newton.reset()
return self._eval(["Mr"], self.__get_PR21_from_Mr, *args, **kwargs)
def __get_PR21_from_Mr(self, Mr: float = None) -> float:
if Mr is None:
Mr = self.__Mr.value
newton = self._get_newton_kernel()
newton.target_value = Mr
newton.start_value = 1.5
# run Newton solver to find deflection angle
return newton.solve(self.__get_Mr_from_PR21)
[docs]
def find_PR21_from_up(self, *args: Any, **kwargs: Any) -> Union[Union[tuple[Any, ...], list[Any]], Any]:
"""
.. deprecated:: 2.6
redirects to :func:`get_PR21_from_up`
"""
return self.get_PR21_from_up(*args, **kwargs)
[docs]
def get_PR21_from_up(self, *args: Any, **kwargs: Any) -> Union[Union[tuple[Any, ...], list[Any]], Any]:
"""
calculates pressure ratio of incident shock (PR21 []) from induced flow velocity (Up [m/s])
the pressure ratio is calculated using the built-in Newton-Raphson solver
input: induced flow velocity (Up [m/s]), temperature of the undisturbed flow ahead of
the incident shock (T1 [K])
example PR21 = get_PR21_from_up(Up=Up, T1=T1)
"""
self._newton.reset()
return self._eval(["Up", "T1"], self.__get_PR21_from_up, *args, **kwargs)
def __get_PR21_from_up(self, Up: float = None, T1: float = None) -> float:
if Up is None:
Up = self.__Up.value
if T1 is not None:
self.__T1.value = T1
newton = self._get_newton_kernel()
newton.target_value = Up
newton.start_value = 1.5
# run Newton solver to find deflection angle
return newton.solve(self.__get_up)
[docs]
def find_PR21_from_PR51(self, *args: Any, **kwargs: Any) -> Union[Union[tuple[Any, ...], list[Any]], Any]:
"""
.. deprecated:: 2.6
redirects to :func:`get_PR21_from_PR51`
"""
return self.get_PR21_from_PR51(*args, **kwargs)
[docs]
def get_PR21_from_PR51(self, *args: Any, **kwargs: Any) -> Union[Union[tuple[Any, ...], list[Any]], Any]:
"""
calculates pressure ratio of incident shock (PR21 []) from the ratio of pressure
behind the reflected shock (P5) and the pressure in the undisturbed flow ahead of the
incident shock (P1) (PR51 [])
the pressure ratio is calculated using the built-in Newton-Raphson solver
input: reflected shock to undisturbed flow pressure ratio (PR51 [])
example PR21 = get_PR21_from_PR51(PR51=PR51)
"""
self._newton.reset()
return self._eval(["PR51"], self.__get_PR21_from_PR51, *args, **kwargs)
def __get_PR21_from_PR51(self, PR51: float = None) -> float:
if PR51 is None:
PR51 = self.__PR51.value
newton = self._get_newton_kernel()
newton.target_value = PR51
newton.start_value = 1.5
# run Newton solver to find deflection angle
return newton.solve(self.__get_PR51_from_PR21)
[docs]
def find_PR21_from_TR51(self, *args: Any, **kwargs: Any) -> Union[np.float64, list[np.float64], float]:
"""
.. deprecated:: 2.6
redirects to :func:`get_PR21_from_TR51`
"""
return self.get_PR21_from_TR51(*args, **kwargs)
[docs]
def get_PR21_from_TR51(self, *args: Any, **kwargs: Any) -> Union[np.float64, list[np.float64], float]:
"""
calculates pressure ratio of incident shock (PR21 []) from the ratio of temperature
behind the reflected shock (T5) and the temperature in the undisturbed flow ahead of the
incident shock (T1) (TR51 [])
the pressure ratio is calculated using the built-in Newton-Raphson solver
input: reflected shock to undisturbed flow temperature ratio (TR51 [])
example PR21 = get_PR21_from_TR51(TR51=TR51)
"""
self._newton.reset()
return self._eval(["TR51"], self.__get_PR21_from_TR51, *args, **kwargs)
def __get_PR21_from_TR51(self, TR51: float = None) -> float:
if TR51 is None:
TR51 = self.__TR51.value
newton = self._get_newton_kernel()
newton.target_value = TR51
newton.start_value = 1.5
# run Newton solver to find deflection angle
return newton.solve(self.__get_TR51_from_PR21)