"""
Date: 08/27/2023
Author: Martin E. Liza
File: aerodynamics.py
Def: Contains aerodynamics helper functions.
"""
import molmass
import numpy as np
import scipy.constants as s_consts
from haot import constants_tables
[docs]
def sutherland_law_viscosity(temperature_K, molecule="Air"):
"""
Calculates the Sutherland's law of viscosity
Parameters:
temperature_K (float): reference temperature
molecule (str): Air (default), Argon, N2, O2
Returns:
dynamic_viscosity (float): [kg/ms]
"""
const = constants_tables.sutherland_constants(molecule)
dynamic_viscosity = const["temperature_ref"] + const["sutherland_visc"]
dynamic_viscosity /= temperature_K + const["sutherland_visc"]
dynamic_viscosity *= (temperature_K / const["temperature_ref"]) ** (3 / 2)
return const["viscosity_ref"] * dynamic_viscosity # [kg/ms]
[docs]
def sutherland_law_conductivity(temperature_K, molecule="Air"):
"""
Calculates the Sutherland's law of thermal conductivity
Parameters:
temperature_K (float): reference temperature
molecule (str): Air (default), Argon, N2, O2
Returns:
thermal_conductivity (float): [W/mK]
"""
const = constants_tables.sutherland_constants(molecule)
thermal_conductivity = const["sutherland_cond"]
thermal_conductivity += const["temperature_ref"]
thermal_conductivity /= temperature_K + const["sutherland_cond"]
thermal_conductivity *= temperature_K / const["temperature_ref"]
thermal_conductivity **= 3 / 2
return const["conductivity_ref"] * thermal_conductivity # [W/mK]
[docs]
def air_atomic_molar_mass():
"""Returns the atomic molar mass of an 11-species air in [g/mol]"""
molecules = ["N+", "O+", "NO+", "N2+", "O2+", "N", "O", "NO", "N2", "O2"]
air_atomic_dict = {}
for i in molecules:
air_atomic_dict[i] = molmass.Formula(i).mass
return air_atomic_dict # [g/mol]
[docs]
def speed_of_sound(temperature_K, adiabatic_indx=1.4):
"""
Calculates the speed of sound
Parameters:
temperature_K (float): reference temperature
adiabatic_indx (double): adiabatic index, 1.4 (default)
Returns:
spd_of_sound (float): speed of sound in [m/s]
"""
gas_const = s_consts.R # [J/mol*K]
air_atomic_mass = air_atomic_molar_mass() # [g/mol]
air_molecular_mass = (
0.7803 * air_atomic_mass["N2"] # [kg/mol]
+ 0.2099 * air_atomic_mass["O2"]
+ 0.0003 * air_atomic_mass["CO2"]
) * 1e-3
spd_of_sound = np.sqrt(
adiabatic_indx * temperature_K * gas_const / air_molecular_mass
)
return spd_of_sound # [m/s]
[docs]
def normal_shock_relations(mach_1, adiabatic_indx=1.4):
"""
Calculates normal shock relations
Reference:
https://www.grc.nasa.gov/www/k-12/airplane/normal.html
Parameters:
mach_1 (float): pre-shock mach number
adiabatic_indx (double): adiabatic index, 1.4 (default)
Returns:
normal_shock_dic: dictionary with normal shock properties
mach_2 (float): post-shock mach number [ ]
pressure_r (float): pressure ratio (post-shock / pre-shock) [ ]
temperature_r (float): temperature ratio (post-shock / pre-shock) [ ]
density_r (float): density ratio (post-shock / pre-shock) [ ]
pressure_tr (float): stagnation pressure ratio (post-shock / pre-shock) [ ]
temperature_tr (float): stagnation temperature ratio (post-shock / pre-shock) [ ]
"""
gamma_minus = adiabatic_indx - 1
gamma_plus = adiabatic_indx + 1
mach_11 = mach_1**2
mach_2 = gamma_minus * mach_11 + 2
mach_2 /= 2 * adiabatic_indx * mach_11 - gamma_minus
mach_2 **= 0.5
pressure_r = (2 * adiabatic_indx * mach_11 - gamma_minus) / gamma_plus
temperature_r = 2 * adiabatic_indx * mach_11 - gamma_minus
temperature_r *= gamma_minus * mach_11 + 2
temperature_r /= gamma_plus**2 * mach_11
density_r = gamma_plus * mach_11 / (gamma_minus * mach_11 + 2)
pressure_tr1 = gamma_plus / (2 * adiabatic_indx * mach_11 - gamma_minus)
pressure_tr1 **= 1 / gamma_minus
pressure_tr2 = gamma_plus * mach_11 / (gamma_minus * mach_11 + 2)
pressure_tr2 **= adiabatic_indx / gamma_minus
pressure_tr = pressure_tr1 * pressure_tr2
# Return Dictionary
normal_shock_dict = {
"mach_2": mach_2,
"pressure_r": pressure_r,
"temperature_r": temperature_r,
"density_r": density_r,
"pressure_tr": pressure_tr,
"temperature_tr": 1.0,
}
return normal_shock_dict # [ ]
# Oblique shock relations
# TODO: Update this doc string on this
[docs]
def oblique_shock_relations(mach_1, shock_angle_deg, adiabatic_indx=1.4):
# REF : Modern Compressible Flows With Historical Ref., eq 4.7 - 4.11
# NOTE: Equations only work for weak shocks
# Note ratio = var_1 / var_2
shock_angle = np.radians(shock_angle_deg) # radians
mach_n1 = mach_1 * np.sin(shock_angle) # normal mach number
mach_n11 = mach_n1**2 # normal mach number square
# Calculates Deflection angle (Eq. 4.17)
tan_deflection_ang = (2 / np.tan(shock_angle)) * (
(mach_n11 - 1) / (mach_1**2 * (adiabatic_indx + np.cos(2 * shock_angle)) + 2)
)
deflection_angle_deg = np.degrees(np.arctan(1 / tan_deflection_ang))
# Calculates properties downstream the shock
density_r = ((adiabatic_indx + 1) * mach_n1**2) / (
(adiabatic_indx - 1) * mach_n1**2 + 2
)
pressure_r = 1 + 2 * adiabatic_indx * (mach_n1**2 - 1) / (adiabatic_indx + 1)
temperature_r = pressure_r * 1 / density_r
# Calculates mach 2
mach_n2 = np.sqrt(
(mach_n1**2 + (2 / (adiabatic_indx - 1)))
/ ((2 * adiabatic_indx / (adiabatic_indx - 1)) * mach_n1**2 - 1)
)
mach_2 = mach_n2 / np.sin(np.radians(shock_angle_deg - deflection_angle_deg))
# Dictionary
oblique_shock_dict = {
"mach_2": mach_2,
"pressure_r": pressure_r,
"temperature_r": temperature_r,
"density_r": density_r,
"deflection_angle_degs": deflection_angle_deg,
}
return oblique_shock_dict