import numpy as np
from pysagas.geometry import Vector
[docs]
class GasState:
"""An ideal gas state defined by Mach number, pressure and
temperature.
"""
gamma = 1.4
R = 287 # J/kg·K.3
[docs]
def __init__(
self, mach: float, pressure: float, temperature: float, gamma: float = 1.4
) -> None:
"""Define a new gas state.
Parameters
-----------
mach : float
The flow Mach number.
pressure : float
The flow pressure (Pa).
temperature : float
The flow temperature (K).
gamma : float, optional
The ratio of specific heats. The default is 1.4.
"""
# Assign properties
self._T = temperature
self._P = pressure
self._M = mach
self._gamma = gamma
def __str__(self) -> str:
return f"Mach {self.M} flow condition with P = {self.P}, T = {self.T}."
def __repr__(self) -> str:
return f"Flow(M={self.M}, P={self.P}, T={self.T})"
def __eq__(self, other: object) -> bool:
if not isinstance(other, GasState):
raise Exception(f"Cannot compare {type(other)} to GasState.")
return (
(self._T == other._T)
& (self._P == other._P)
& (self._M == other._M)
& (self._gamma == other._gamma)
)
@property
def T(self):
return self._T
@property
def P(self):
return self._P
@property
def M(self):
return self._M
@property
def a(self):
return (self.gamma * self.R * self.T) ** 0.5
@property
def rho(self):
return self.P / (self.R * self.T)
@property
def v(self):
return self.M * self.a
@property
def q(self):
return 0.5 * self.rho * self.v**2
@property
def gamma(self):
return self._gamma
[docs]
class FlowState(GasState):
"""An ideal gas state defined by Mach number, pressure and
temperature, with a flow direction.
"""
[docs]
def __init__(
self,
mach: float,
pressure: float,
temperature: float,
direction: Vector = None,
aoa: float = 0.0,
gamma: float = 1.4,
) -> None:
"""Define a new flow state.
Parameters
-----------
mach : float
The flow Mach number.
pressure : float
The flow pressure (Pa).
temperature : float
The flow temperature (K).
direction : Vector, optional
The direction vector of the flow. The default is Vector(1,0,0).
aoa : float, optional
The angle of attack of the flow. The default is 0.0 (specified in
degrees).
gamma : float, optional
The ratio of specific heats. The default is 1.4.
"""
super().__init__(mach, pressure, temperature, gamma)
if direction:
# Use direction provided
self.direction = direction.unit
else:
# Use AoA to calculate direction
self.direction = Vector(1, 1 * np.tan(np.deg2rad(aoa)), 0).unit
def __eq__(self, other: object) -> bool:
if not isinstance(other, FlowState):
raise Exception(f"Cannot compare {type(other)} to FlowState.")
same_gs = super().__eq__(other)
return same_gs & (self.direction == other.direction)
@property
def vx(self):
return self.Vector.x
@property
def vy(self):
return self.Vector.y
@property
def vz(self):
return self.Vector.z
@property
def vec(self):
return self.Vector.vec
@property
def Vector(self) -> Vector:
return self.direction * self.v
@property
def aoa(self):
aoa = np.rad2deg(np.arctan(self.vec[1] / self.vec[0]))
return round(aoa, 6)
if __name__ == "__main__":
flow = FlowState(6, 700, 70)