Module CompAero.Calculator.calculator_main
This module encompasses the entire compaero ui
Expand source code
"""
This module encompasses the entire compaero ui
"""
import sys
from math import nan
from typing import Optional, TypedDict, Union
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtWidgets import QMainWindow
from CompAero.Calculator.CalculatorUI import Ui_MainWindow
from CompAero.Calculator.decorators import error_message_decorator
from CompAero.fanno_flow_relations import FANNO_FLOW_VALID_OPTIONS, FannoFlowChoice
from CompAero.fanno_flow_relations import FannoFlowRelations as FFR
from CompAero.isentropic_relations import (
ISENTROPIC_CHOICE,
ISENTROPIC_VALID_OPTIONS,
IsentropicRelations,
)
from CompAero.normal_shock_relations import NORMAL_SHOCK_CHOICE, NORMAL_SHOCK_VALID_OPTIONS
from CompAero.normal_shock_relations import NormalShockRelations as NSR
from CompAero.oblique_shock_relations import OBLIQUE_SHOCK_VALID_OPTIONS, ObliqueShockChoice
from CompAero.oblique_shock_relations import ObliqueShockRelations as OSR
from CompAero.prandtl_meyer import PRANDTL_MEYER_OPTIONS
from CompAero.prandtl_meyer import PrandtlMeyer as PM
from CompAero.prandtl_meyer import PrandtlMeyerChoice
from CompAero.rayleigh_flow_relations import RAYLEIGH_FLOW_VALID_OPTIONS, RayleighFlowChoice
from CompAero.rayleigh_flow_relations import RayleighFlowRelations as RFR
from CompAero.rocket_nozzle import (
max_thrust_coefficient,
min_thrust_coefficient,
thrust_coefficient,
)
from CompAero.types import FlowState, ShockType
QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling, True) # type: ignore
QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_UseHighDpiPixmaps, True) # type: ignore
PRECISION = 6
def to_str(value: Union[int, float], decimal: int = PRECISION) -> str:
"""
This funciton rounds the value and converts in to a string
Args:
decimal (int): how many digits to round the value to
value (float | int): value to be rounded and converted to a string
Returns: a string version of value rounded to decimal digits
"""
return str(round(value, decimal))
PRANDTL_MEYER_DICT_TYPE = TypedDict(
"PRANDTL_MEYER_DICT_TYPE", {"gamma": float, "in_degrees": bool, "deflection_angle": float}
)
RAY_FANNO_DICT_TYPE = TypedDict("RAY_FANNO_DICT_TYPE", {"gamma": float, "flow_type": FlowState})
OBLIQUE_SHOCK_REL_DICT_TYPE = TypedDict(
"OBLIQUE_SHOCK_REL_DICT_TYPE",
{"gamma": float, "use_degrees": bool, "shock_type": ShockType, "shock_angle": float},
)
class UI(QMainWindow, Ui_MainWindow):
"""Class defines the comp aero ui"""
def __init__(self) -> None:
super().__init__()
self.setupUi(self)
self.show()
self.layout().setContentsMargins(0, 0, 0, 0) # type: ignore
self._error_box = QtWidgets.QErrorMessage()
# Combos
self.isentropicOptionCombo.addItems(ISENTROPIC_VALID_OPTIONS)
self.isentropicFlowTypeCombo.addItems(
[FlowState.SUPER_SONIC.name, FlowState.SUB_SONIC.name]
)
self.normalShockOptionCombo.addItems(NORMAL_SHOCK_VALID_OPTIONS)
self.obliqueShockOptionCombo.addItems(OBLIQUE_SHOCK_VALID_OPTIONS)
self.obliqueshock_typeCombo.addItems([x.value for x in ShockType])
self.fannoOptionCombo.addItems(FANNO_FLOW_VALID_OPTIONS)
self.fannoFlowTypeCombo.addItems([x.value for x in FlowState])
self.rayleighOptionCombo.addItems(RAYLEIGH_FLOW_VALID_OPTIONS)
self.rayleighFlowTypeCombo.addItems([x.value for x in FlowState])
self.prandtlMeyerOptionCombo.addItems(PRANDTL_MEYER_OPTIONS)
# Buttons
self.isentropicCalcBtn.clicked.connect(self.calc_isentropic_state)
self.normalShockCalculate.clicked.connect(self.calc_normal_shock_state)
self.obliqueShockCalcBtn.clicked.connect(self.calc_oblique_shock_state)
self.obliqueShockDegreeChkBtn.clicked.connect(self.oblique_shock_degrees_chk_box_update)
self.prandtlMeyerDegreeChkBtn.clicked.connect(self.prandtl_meyer_degrees_chk_box_update)
self.fannoCalculateBtn.clicked.connect(self.calc_fanno_flow_state)
self.fannoApplyPipeParamBtn.clicked.connect(self.calc_fanno_friction_addition)
self.rayleighCalculateBtn.clicked.connect(self.calc_rayleigh_flow_state)
self.rayleighApplyPipeParamBtn.clicked.connect(self.calc_rayleigh_heat_addition)
self.prandtlMeyerCalculateBtn.clicked.connect(self.calc_prantl_meyer_state)
self.rocketNozzleCalculateBtn.clicked.connect(self.calc_rocket_nozzle_state)
# Saved states
self._fanno_state: Optional[FFR] = None
self._rayleigh_state: Optional[RFR] = None
def show_error(self, msg: str) -> None:
"""
Shows the error popup with a message
Args:
msg (str): msg to show in the popup
"""
self._error_box.showMessage(msg)
def oblique_shock_degrees_chk_box_update(self) -> None:
"""Changes the text on the button to reflect the oblique shock angle units"""
if self.obliqueShockDegreeChkBtn.isChecked():
self.obliqueShockDegreeChkBtn.setText("Radians")
else:
self.obliqueShockDegreeChkBtn.setText("Degrees")
@error_message_decorator
def prandtl_meyer_degrees_chk_box_update(self) -> None:
"""Changes the text on the button to reflect the prantl meyer angle units"""
if self.prandtlMeyerDegreeChkBtn.isChecked():
self.prandtlMeyerDegreeChkBtn.setText("Radians")
else:
self.prandtlMeyerDegreeChkBtn.setText("Degrees")
@error_message_decorator
def calc_isentropic_state(self) -> None:
"""Calculates the isentropic state and sets the entry box values"""
if not self.isentropicGammaEntry.text():
return
gamma = float(self.isentropicGammaEntry.text())
choice = self.isentropicOptionCombo.currentText()
if not choice:
return
state = None
if choice == ISENTROPIC_CHOICE.MACH and self.isentropicMachEntry.text():
state = IsentropicRelations(gamma=gamma, mach=float(self.isentropicMachEntry.text()))
elif choice == ISENTROPIC_CHOICE.P0_P and self.isentropicP0PEntry.text():
state = IsentropicRelations(gamma, p0_p=float(self.isentropicP0PEntry.text()))
elif choice == ISENTROPIC_CHOICE.RHO0_RHO and self.isentropicRho0RhoEntry.text():
state = IsentropicRelations(gamma, rho0_rho=float(self.isentropicRho0RhoEntry.text()))
elif choice == ISENTROPIC_CHOICE.T0_T and self.isentropicT0TEntry.text():
state = IsentropicRelations(gamma, t0_t=float(self.isentropicT0TEntry.text()))
elif (
choice == ISENTROPIC_CHOICE.a_a_star
and self.isentropicAAStarEntry.text()
and self.isentropicFlowTypeCombo.currentText()
):
flowtype = FlowState(self.isentropicFlowTypeCombo.currentText())
aa_star = float(self.isentropicAAStarEntry.text())
state = IsentropicRelations(gamma, a_a_star=aa_star, flow_type=flowtype)
if state is not None:
self.isentropicMachEntry.setText(to_str(state.mach))
self.isentropicP0PEntry.setText(to_str(state.p0_p))
self.isentropicAAStarEntry.setText(to_str(state.a_a_star))
self.isentropicT0TEntry.setText(to_str(state.t0_t))
self.isentropicRho0RhoEntry.setText(to_str(state.rho0_rho))
@error_message_decorator
def calc_normal_shock_state(self) -> None:
"""Calculates the normal shock state and sets the entry box values"""
if not self.normalShockGammaEntry.text():
return
gamma = float(self.normalShockGammaEntry.text())
choice = NORMAL_SHOCK_CHOICE(self.normalShockOptionCombo.currentText())
if not choice:
return
state = None
if choice == NORMAL_SHOCK_CHOICE.MACH and self.normalShockM1Entry.text():
state = NSR(gamma, mach=float(self.normalShockM1Entry.text()))
elif choice == NORMAL_SHOCK_CHOICE.P2_P1 and self.normalShockP2P1Entry.text():
state = NSR(gamma, p2_p1=float(self.normalShockP2P1Entry.text()))
elif choice == NORMAL_SHOCK_CHOICE.RHO2_RHO1 and self.normalShockRho2Rho1Entry.text():
state = NSR(gamma, rho2_rho1=float(self.normalShockRho2Rho1Entry.text()))
elif choice == NORMAL_SHOCK_CHOICE.T2_T1 and self.normalShockT2T1Entry.text():
state = NSR(gamma, t2_t1=float(self.normalShockT2T1Entry.text()))
elif choice == NORMAL_SHOCK_CHOICE.PO2_PO1 and self.normalShockP02P01Entry.text():
state = NSR(gamma, po2_po1=float(self.normalShockP02P01Entry.text()))
elif choice == NORMAL_SHOCK_CHOICE.PO2_P1 and self.normalShockP02P1Entry.text():
state = NSR(gamma, po2_p1=float(self.normalShockP02P1Entry.text()))
elif choice == NORMAL_SHOCK_CHOICE.M2 and self.normalShockM2Entry.text():
state = NSR(gamma, m2=float(self.normalShockM2Entry.text()))
else:
print("Invalid Choice ")
if state is not None:
self.normalShockM1Entry.setText(to_str(state.mach))
self.normalShockM2Entry.setText(to_str(state.mach2))
self.normalShockP2P1Entry.setText(to_str(state.p2_p1))
self.normalShockRho2Rho1Entry.setText(to_str(state.rho2_rho1))
self.normalShockT2T1Entry.setText(to_str(state.t2_t1))
self.normalShockP02P01Entry.setText(to_str(state.po2_po1))
self.normalShockP02P1Entry.setText(to_str(state.po2_p1))
@error_message_decorator
def calc_oblique_shock_state(self) -> None:
# pylint: disable=too-many-statements
# pylint: disable=too-many-branches
# pylint: disable=too-many-locals
"""Calculates the oblique shock state and sets the entry box values"""
if not self.obliqueShockGammaEntry.text():
return
gamma = float(self.obliqueShockGammaEntry.text())
choice = ObliqueShockChoice(self.obliqueShockOptionCombo.currentText())
shock_type = ShockType(self.obliqueshock_typeCombo.currentText())
wedge_angle_valid = bool(self.obliqueShockwedge_angleEdit.text())
shock_angle_valid = bool(self.obliqueshock_angleEdit.text())
m1_valid = bool(self.obliqueShockM1Edit.text())
mn1_valid = bool(self.obliqueShockMn1Edit.text())
mn2_valid = bool(self.obiqueShockMn2Edit.text())
m2_valid = bool(self.obliqueShockM2Edit.text())
p2p1_valid = bool(self.obliqueShockP2P1Edit.text())
rho2_rho1_valid = bool(self.obliqueShockRho2Rho1Edit.text())
po2_p1_valid = bool(self.obliqueShockPo2P1Edit.text())
t2_t1_valid = bool(self.obliqueShockT2T1Edit.text())
po2_po1_valid = bool(self.obliqueShockPo2Po1Edit.text())
degrees = bool(not self.obliqueShockDegreeChkBtn.isChecked())
if not choice:
return
state = None
# common options
opts: OBLIQUE_SHOCK_REL_DICT_TYPE = {
"gamma": gamma,
"use_degrees": degrees,
"shock_type": shock_type,
"shock_angle": nan,
}
if choice == ObliqueShockChoice.MACH_WEDGE_ANGLE and m1_valid and wedge_angle_valid:
m = float(self.obliqueShockM1Edit.text())
wa = float(self.obliqueShockwedge_angleEdit.text())
state = OSR(**opts, mach=m, wedge_angle=wa)
if not shock_angle_valid:
return
opts["shock_angle"] = float(self.obliqueshock_angleEdit.text())
if choice == ObliqueShockChoice.MACH_SHOCK_ANGLE and m1_valid:
m = float(self.obliqueShockM1Edit.text())
state = OSR(**opts, mach=m)
elif choice == ObliqueShockChoice.MACH_N_1_SHOCK_ANGLE and mn1_valid:
m = float(self.obliqueShockMn1Edit.text())
state = OSR(**opts, mn1=m)
elif choice == ObliqueShockChoice.M2_WEDGE_SHOCK_ANGLE and m2_valid and wedge_angle_valid:
m2 = float(self.obliqueShockM2Edit.text())
wa = float(self.obliqueShockwedge_angleEdit.text())
state = OSR(**opts, m2=m2, wedge_angle=wa)
elif choice == ObliqueShockChoice.P2_P1_SHOCK_ANGLE and p2p1_valid:
p2p1 = float(self.obliqueShockP2P1Edit.text())
state = OSR(**opts, p2_p1=p2p1)
elif choice == ObliqueShockChoice.RHO2_RHO1_SHOCK_ANGLE and rho2_rho1_valid:
r2r1 = float(self.obliqueShockRho2Rho1Edit.text())
state = OSR(**opts, rho2_rho1=r2r1)
elif choice == ObliqueShockChoice.T2_T1_SHOCK_ANGLE and t2_t1_valid:
t2t1 = float(self.obliqueShockT2T1Edit.text())
state = OSR(**opts, t2_t1=t2t1)
elif choice == ObliqueShockChoice.PO2_PO1_SHOCK_ANGLE and po2_po1_valid:
p = float(self.obliqueShockPo2Po1Edit.text())
state = OSR(**opts, po2_po1=p)
elif choice == ObliqueShockChoice.PO2_P1_SHOCK_ANGLE and po2_p1_valid:
p = float(self.obliqueShockPo2P1Edit.text())
state = OSR(**opts, po2_p1=p)
elif choice == ObliqueShockChoice.MN2_SHOCK_ANGLE and mn2_valid:
m = float(self.obiqueShockMn2Edit.text())
state = OSR(**opts, mn2=m)
if state:
self.obliqueShockwedge_angleEdit.setText(to_str(state.wedge_angle))
self.obliqueshock_angleEdit.setText(to_str(state.shock_angle))
self.obliqueShockM1Edit.setText(to_str(state.mach))
self.obliqueShockMn1Edit.setText(to_str(state.mach_normal_1))
self.obiqueShockMn2Edit.setText(to_str(state.mach_normal_2))
self.obliqueShockM2Edit.setText(to_str(state.mach2))
self.obliqueShockP2P1Edit.setText(to_str(state.p2_p1))
self.obliqueShockRho2Rho1Edit.setText(to_str(state.rho2_rho1))
self.obliqueShockPo2P1Edit.setText(to_str(state.po2_p1))
self.obliqueShockT2T1Edit.setText(to_str(state.t2_t1))
self.obliqueShockPo2Po1Edit.setText(to_str(state.po2_po1))
@error_message_decorator
def calc_fanno_flow_state(self) -> None:
# pylint: disable=too-many-locals
"""Calculates the fanno flow state and sets the entry box values"""
if not self.fannoGammaEntry.text():
return
gamma = float(self.fannoGammaEntry.text())
choice = FannoFlowChoice(self.fannoOptionCombo.currentText())
flow_type: FlowState = FlowState(self.fannoFlowTypeCombo.currentText())
m_valid = bool(self.fannoUpstreamMachEdit.text())
tt_valid = bool(self.fannoTTStEdit.text())
pp_valid = bool(self.fannoPPStEdit.text())
rr_valid = bool(self.fannoRhoRhoStEdit.text())
popo_valid = bool(self.fannoPoPoStEdit.text())
fric_valid = bool(self.fanno4FLStDEdit.text())
uu_valid = bool(self.fannoUUStEdit.text())
state = None
opts: RAY_FANNO_DICT_TYPE = {"gamma": gamma, "flow_type": flow_type}
if choice == FannoFlowChoice.GAMMA_MACH and m_valid:
m = float(self.fannoUpstreamMachEdit.text())
state = FFR(**opts, mach=m)
elif choice == FannoFlowChoice.GAMMA_T_T_ST and tt_valid:
tt = float(self.fannoTTStEdit.text())
state = FFR(**opts, t_t_st=tt)
elif choice == FannoFlowChoice.GAMMA_P_P_ST and pp_valid:
pp = float(self.fannoPPStEdit.text())
state = FFR(**opts, p_p_st=pp)
elif choice == FannoFlowChoice.GAMMA_RHO_RHO_ST and rr_valid:
rr = float(self.fannoRhoRhoStEdit.text())
state = FFR(**opts, rho_rho_st=rr)
elif choice == FannoFlowChoice.GAMMA_PO_PO_ST and popo_valid:
popo = float(self.fannoPoPoStEdit.text())
state = FFR(**opts, po_po_st=popo)
elif choice == FannoFlowChoice.GAMMA_4FLSTD_FLOW_TYPE and fric_valid:
fric = float(self.fanno4FLStDEdit.text())
state = FFR(**opts, f4lst_d=fric)
elif choice == FannoFlowChoice.GAMMA_U_U_ST and uu_valid:
uu = float(self.fannoUUStEdit.text())
state = FFR(**opts, u_u_st=uu)
if state:
self.fannoUpstreamMachEdit.setText(to_str(state.mach))
self.fannoTTStEdit.setText(to_str(state.mach))
self.fannoPPStEdit.setText(to_str(state.p_p_st))
self.fannoRhoRhoStEdit.setText(to_str(state.rho_rho_st))
self.fannoPoPoStEdit.setText(to_str(state.po_po_st))
self.fanno4FLStDEdit.setText(to_str(state.f4lst_d))
self.fannoUUStEdit.setText(to_str(state.u_u_st))
self._fanno_state = state
@error_message_decorator
def calc_fanno_friction_addition(self) -> None:
"""Calculates the addition of friction to the fanno state and sets the entry box values"""
if self._fanno_state is None:
return
valid_params = bool(self.fannoPipeDiameterEdit.text())
valid_params &= bool(self.fannoFrictionCoeffEdit.text())
valid_params &= bool(self.fannoPipeLenEdit.text())
if not valid_params:
return
d = float(self.fannoPipeDiameterEdit.text())
f = float(self.fannoFrictionCoeffEdit.text())
l = float(self.fannoPipeLenEdit.text())
self._fanno_state.apply_pipe_parameters(d, l, f)
s = self._fanno_state
# Down stream conditions
self.fannoDwnStrmMachEdit.setText(to_str(s.dwn_strm_mach))
self.fannoDwnStrmTTStEdit.setText(to_str(s.dwn_strm_t_t_st))
self.fannoDwnStrmPPStEdit.setText(to_str(s.dwn_strm_p_p_st))
self.fannoDwnStrmRhoRhoStEdit.setText(to_str(s.dwn_strm_rho_rho_st))
self.fannoDwnStrmPoPoStrEdit.setText(to_str(s.dwn_strm_f4lst_d))
self.fannoDwnStrmUUStEdit.setText(to_str(s.dwn_strm_u_u_st))
self.fannoChokedLengthEdit.setText(to_str(s.choked_length))
# Ratio of down stream to upstream conditions
self.fannoT2T1Edit.setText(to_str(s.t2_t1))
self.fannoP2P1Edit.setText(to_str(s.p2_p1))
self.fannoU2U1Edit.setText(to_str(s.u2_u1))
self.fannoRho2Rho1Edit.setText(to_str(s.rho2_rho1))
self.fannoPo2Po1Edit.setText(to_str(s.po2_po1))
self.fanno4FLStD24FLStD1Edit.setText(to_str(s.f4ld2_f4ld1))
@error_message_decorator
def calc_rayleigh_flow_state(self) -> None:
"""Calculates the rayleigh flow state and sets the entry box values"""
if not self.rayleighGammaEntry.text():
return
gamma = float(self.rayleighGammaEntry.text())
flow_type = FlowState(self.rayleighFlowTypeCombo.currentText())
choice = RayleighFlowChoice(self.rayleighOptionCombo.currentText())
m_valid = bool(self.rayleighUpstreamMachEdit.text())
tt_valid = bool(self.rayleighTTStEdit.text())
pp_valid = bool(self.rayleighPPStEdit.text())
rr_valid = bool(self.rayleighRhoRhoStEdit.text())
popo_valid = bool(self.rayleighPoPoStEdit.text())
toto_valid = bool(self.rayleighToToStEdit.text())
uu_valid = bool(self.rayleighUUStEdit.text())
state = None
opts: RAY_FANNO_DICT_TYPE = {"gamma": gamma, "flow_type": flow_type}
if choice == RayleighFlowChoice.GAMMA_MACH and m_valid:
state = RFR(**opts, mach=float(self.rayleighUpstreamMachEdit.text()))
elif choice == RayleighFlowChoice.GAMMA_T_T_ST and tt_valid:
state = RFR(**opts, t_t_st=float(self.rayleighTTStEdit.text()))
elif choice == RayleighFlowChoice.GAMMA_P_P_ST and pp_valid:
state = RFR(**opts, p_p_st=float(self.rayleighPPStEdit.text()))
elif choice == RayleighFlowChoice.GAMMA_RHO_RHO_ST and rr_valid:
state = RFR(**opts, rho_rho_st=float(self.rayleighRhoRhoStEdit.text()))
elif choice == RayleighFlowChoice.GAMMA_PO_PO_ST and popo_valid:
state = RFR(**opts, po_po_st=float(self.rayleighPoPoStEdit.text()))
elif choice == RayleighFlowChoice.GAMMA_TO_TO_FLOW_TYPE and toto_valid:
state = RFR(**opts, to_to_st=float(self.rayleighToToStEdit.text()))
elif choice == RayleighFlowChoice.GAMMA_U_U_ST and uu_valid:
state = RFR(**opts, u_u_st=float(self.rayleighUUStEdit.text()))
self._rayleigh_state = state
if state:
s = state
self.rayleighUpstreamMachEdit.setText(to_str(s.mach))
self.rayleighTTStEdit.setText(to_str(s.t_t_st))
self.rayleighPPStEdit.setText(to_str(s.p_p_st))
self.rayleighRhoRhoStEdit.setText(to_str(s.rho_rho_st))
self.rayleighPoPoStEdit.setText(to_str(s.po_po_st))
self.rayleighToToStEdit.setText(to_str(s.to_to_st))
self.rayleighUUStEdit.setText(to_str(s.u_u_st))
@error_message_decorator
def calc_rayleigh_heat_addition(self) -> None:
"""Calculates the addition of heat to the rayleigh state and sets the entry box values"""
if self._rayleigh_state is None:
return
valid_params = bool(self.rayleighHeatEdit.text())
valid_params &= bool(self.rayleighGasConstantEdit.text())
valid_params &= bool(self.rayleighHeatTo1Edit.text())
if not valid_params:
return
h = float(self.rayleighHeatEdit.text())
r = float(self.rayleighGasConstantEdit.text())
t = float(self.rayleighHeatTo1Edit.text())
self._rayleigh_state.simulate_heat_addition(h, t, r)
s = self._rayleigh_state
# Down stream conditions
self.rayleighDwnStrmMachEdit.setText(to_str(s.dwn_strm_mach))
self.rayleighDwnStrmTTStEdit.setText(to_str(s.dwn_strm_t_t_st))
self.rayleighDwnStrmPPStEdit.setText(to_str(s.dwn_strm_p_p_st))
self.rayleighDwnStrmRhoRhoStEdit.setText(to_str(s.dwn_strm_rho_rho_st))
self.rayleighDwnStrmPoPoStrEdit.setText(to_str(s.dwn_strm_po_po_st))
self.rayleighDwnStrmToToStEdit.setText(to_str(s.dwn_strm_to_to_st))
self.rayleighDwnStrmUUStEdit.setText(to_str(s.dwn_strm_u_u_st))
self.rayleighChokedHeatEdit.setText(to_str(s.choked_heat))
# Ratio of down stream to upstream conditions
self.rayleighT2T1Edit.setText(to_str(s.t2_t1))
self.rayleighP2P1Edit.setText(to_str(s.p2_p1))
self.rayleighU2U1Edit.setText(to_str(s.u2_u1))
self.rayleighRho2Rho1Edit.setText(to_str(s.rho2_rho1))
self.rayleighPo2Po1Edit.setText(to_str(s.po2_po1))
self.rayleighTo2To1Edit.setText(to_str(s.to2_to1))
self.rayleighTo2Edit.setText(to_str(s.to2))
@error_message_decorator
def calc_prantl_meyer_state(self) -> None:
"""Calculates prantl meyer state and sets the entry box values"""
if not self.prandtlMeyerGammaEntry.text():
return
gamma = float(self.prandtlMeyerGammaEntry.text())
choice = PrandtlMeyerChoice(self.prandtlMeyerOptionCombo.currentText())
m_valid = bool(self.prandtlMeyerUpstreamMachEdit.text())
nu_valid = bool(self.prandtlMeyerNuEdit.text())
mu_valid = bool(self.prandtlMeyerMuEdit.text())
angle_valid = bool(self.prandtlMeyerDeflectionAngleEdit.text())
d_m_valid = bool(self.prandtlMeyerDwnStrmMachEdit.text())
d_nu_valid = bool(self.prandtlMeyerDwnStrmNuEdit.text())
d_mu_valid = bool(self.prandtlMeyerDwnStrmMuEdit.text())
degrees = not self.prandtlMeyerDegreeChkBtn.isChecked()
state = None
opts: PRANDTL_MEYER_DICT_TYPE = {
"gamma": gamma,
"in_degrees": degrees,
"deflection_angle": nan,
}
if angle_valid:
opts["deflection_angle"] = float(self.prandtlMeyerDeflectionAngleEdit.text())
if choice == PrandtlMeyerChoice.GAMMA_MACH and m_valid:
state = PM(**opts, mach=float(self.prandtlMeyerUpstreamMachEdit.text()))
elif choice == PrandtlMeyerChoice.GAMMA_NU and nu_valid:
state = PM(**opts, nu=float(self.prandtlMeyerNuEdit.text()))
elif choice == PrandtlMeyerChoice.GAMMA_MU and mu_valid:
state = PM(**opts, mu=float(self.prandtlMeyerMuEdit.text()))
elif choice == PrandtlMeyerChoice.GAMMA_DEFLECTION_DWN_STRM_MACH and d_m_valid:
state = PM(**opts, down_stream_mach=float(self.prandtlMeyerDwnStrmMachEdit.text()))
elif choice == PrandtlMeyerChoice.GAMMA_DEFLECTION_DWN_STRM_MU and d_mu_valid:
state = PM(**opts, down_stream_mu=float(self.prandtlMeyerDwnStrmMuEdit.text()))
elif choice == PrandtlMeyerChoice.GAMMA_DEFLECTION_DWN_STRM_NU and d_nu_valid:
state = PM(**opts, down_stream_nu=float(self.prandtlMeyerDwnStrmNuEdit.text()))
if state:
s = state
self.prandtlMeyerUpstreamMachEdit.setText(to_str(s.mach))
self.prandtlMeyerNuEdit.setText(to_str(s.nu))
self.prandtlMeyerMuEdit.setText(to_str(s.mu))
self.prandtlMeyerDwnStrmMachEdit.setText(to_str(s.down_stream_mach))
self.prandtlMeyerDwnStrmMuEdit.setText(to_str(s.down_stream_mu))
self.prandtlMeyerDwnStrmNuEdit.setText(to_str(s.down_stream_nu))
@error_message_decorator
def calc_rocket_nozzle_state(self) -> None:
"""Calculates rocket nozzle state and sets the entry box values"""
gamma_valid = bool(self.rocketNozzleGammaEntry.text())
ar_valid = bool(self.rocketNozzleAreaRatioEdit.text())
pepc_valid = bool(self.rocketNozzlePePcEdit.text())
papc_valid = bool(self.rocketNozzlePaPcEdit.text())
gamma, ar, pe_pc, pa_pc = (0.0, 0.0, 0.0, 0.0)
if gamma_valid:
gamma = float(self.rocketNozzleGammaEntry.text())
if ar_valid:
ar = float(self.rocketNozzleAreaRatioEdit.text())
if pepc_valid:
pe_pc = float(self.rocketNozzlePePcEdit.text())
if papc_valid:
pa_pc = float(self.rocketNozzlePaPcEdit.text())
if ar_valid:
min_coeff = min_thrust_coefficient(ar)
self.rocketNozzleMinThrustCoeffEdit.setText(to_str(min_coeff))
if gamma_valid and ar_valid and pepc_valid:
max_coeff = max_thrust_coefficient(gamma, ar, pe_pc)
self.rocketNozzleMaxThrustCoeffEdit.setText(to_str(max_coeff))
if gamma_valid and ar_valid and pepc_valid and papc_valid:
coeff = thrust_coefficient(gamma, ar, pe_pc, pa_pc)
self.rocketNozzleThrustCoeffEdit.setText(to_str(coeff))
def main() -> None:
"""Main function of application"""
app = QtWidgets.QApplication(sys.argv)
_ = UI()
app.exec_()
if __name__ == "__main__":
main()
Functions
def main() ‑> None
-
Main function of application
Expand source code
def main() -> None: """Main function of application""" app = QtWidgets.QApplication(sys.argv) _ = UI() app.exec_()
def to_str(value: Union[int, float], decimal: int = 6) ‑> str
-
This funciton rounds the value and converts in to a string
Args
decimal
:int
- how many digits to round the value to
value (float | int): value to be rounded and converted to a string Returns: a string version of value rounded to decimal digits
Expand source code
def to_str(value: Union[int, float], decimal: int = PRECISION) -> str: """ This funciton rounds the value and converts in to a string Args: decimal (int): how many digits to round the value to value (float | int): value to be rounded and converted to a string Returns: a string version of value rounded to decimal digits """ return str(round(value, decimal))
Classes
class OBLIQUE_SHOCK_REL_DICT_TYPE (*args, **kwargs)
-
dict() -> new empty dictionary dict(mapping) -> new dictionary initialized from a mapping object's (key, value) pairs dict(iterable) -> new dictionary initialized as if via: d = {} for k, v in iterable: d[k] = v dict(**kwargs) -> new dictionary initialized with the name=value pairs in the keyword argument list. For example: dict(one=1, two=2)
Ancestors
- builtins.dict
Class variables
var gamma : float
var shock_angle : float
var shock_type : ShockType
var use_degrees : bool
class PRANDTL_MEYER_DICT_TYPE (*args, **kwargs)
-
dict() -> new empty dictionary dict(mapping) -> new dictionary initialized from a mapping object's (key, value) pairs dict(iterable) -> new dictionary initialized as if via: d = {} for k, v in iterable: d[k] = v dict(**kwargs) -> new dictionary initialized with the name=value pairs in the keyword argument list. For example: dict(one=1, two=2)
Ancestors
- builtins.dict
Class variables
var deflection_angle : float
var gamma : float
var in_degrees : bool
class RAY_FANNO_DICT_TYPE (*args, **kwargs)
-
dict() -> new empty dictionary dict(mapping) -> new dictionary initialized from a mapping object's (key, value) pairs dict(iterable) -> new dictionary initialized as if via: d = {} for k, v in iterable: d[k] = v dict(**kwargs) -> new dictionary initialized with the name=value pairs in the keyword argument list. For example: dict(one=1, two=2)
Ancestors
- builtins.dict
Class variables
var flow_type : FlowState
var gamma : float
class UI
-
Class defines the comp aero ui
Expand source code
class UI(QMainWindow, Ui_MainWindow): """Class defines the comp aero ui""" def __init__(self) -> None: super().__init__() self.setupUi(self) self.show() self.layout().setContentsMargins(0, 0, 0, 0) # type: ignore self._error_box = QtWidgets.QErrorMessage() # Combos self.isentropicOptionCombo.addItems(ISENTROPIC_VALID_OPTIONS) self.isentropicFlowTypeCombo.addItems( [FlowState.SUPER_SONIC.name, FlowState.SUB_SONIC.name] ) self.normalShockOptionCombo.addItems(NORMAL_SHOCK_VALID_OPTIONS) self.obliqueShockOptionCombo.addItems(OBLIQUE_SHOCK_VALID_OPTIONS) self.obliqueshock_typeCombo.addItems([x.value for x in ShockType]) self.fannoOptionCombo.addItems(FANNO_FLOW_VALID_OPTIONS) self.fannoFlowTypeCombo.addItems([x.value for x in FlowState]) self.rayleighOptionCombo.addItems(RAYLEIGH_FLOW_VALID_OPTIONS) self.rayleighFlowTypeCombo.addItems([x.value for x in FlowState]) self.prandtlMeyerOptionCombo.addItems(PRANDTL_MEYER_OPTIONS) # Buttons self.isentropicCalcBtn.clicked.connect(self.calc_isentropic_state) self.normalShockCalculate.clicked.connect(self.calc_normal_shock_state) self.obliqueShockCalcBtn.clicked.connect(self.calc_oblique_shock_state) self.obliqueShockDegreeChkBtn.clicked.connect(self.oblique_shock_degrees_chk_box_update) self.prandtlMeyerDegreeChkBtn.clicked.connect(self.prandtl_meyer_degrees_chk_box_update) self.fannoCalculateBtn.clicked.connect(self.calc_fanno_flow_state) self.fannoApplyPipeParamBtn.clicked.connect(self.calc_fanno_friction_addition) self.rayleighCalculateBtn.clicked.connect(self.calc_rayleigh_flow_state) self.rayleighApplyPipeParamBtn.clicked.connect(self.calc_rayleigh_heat_addition) self.prandtlMeyerCalculateBtn.clicked.connect(self.calc_prantl_meyer_state) self.rocketNozzleCalculateBtn.clicked.connect(self.calc_rocket_nozzle_state) # Saved states self._fanno_state: Optional[FFR] = None self._rayleigh_state: Optional[RFR] = None def show_error(self, msg: str) -> None: """ Shows the error popup with a message Args: msg (str): msg to show in the popup """ self._error_box.showMessage(msg) def oblique_shock_degrees_chk_box_update(self) -> None: """Changes the text on the button to reflect the oblique shock angle units""" if self.obliqueShockDegreeChkBtn.isChecked(): self.obliqueShockDegreeChkBtn.setText("Radians") else: self.obliqueShockDegreeChkBtn.setText("Degrees") @error_message_decorator def prandtl_meyer_degrees_chk_box_update(self) -> None: """Changes the text on the button to reflect the prantl meyer angle units""" if self.prandtlMeyerDegreeChkBtn.isChecked(): self.prandtlMeyerDegreeChkBtn.setText("Radians") else: self.prandtlMeyerDegreeChkBtn.setText("Degrees") @error_message_decorator def calc_isentropic_state(self) -> None: """Calculates the isentropic state and sets the entry box values""" if not self.isentropicGammaEntry.text(): return gamma = float(self.isentropicGammaEntry.text()) choice = self.isentropicOptionCombo.currentText() if not choice: return state = None if choice == ISENTROPIC_CHOICE.MACH and self.isentropicMachEntry.text(): state = IsentropicRelations(gamma=gamma, mach=float(self.isentropicMachEntry.text())) elif choice == ISENTROPIC_CHOICE.P0_P and self.isentropicP0PEntry.text(): state = IsentropicRelations(gamma, p0_p=float(self.isentropicP0PEntry.text())) elif choice == ISENTROPIC_CHOICE.RHO0_RHO and self.isentropicRho0RhoEntry.text(): state = IsentropicRelations(gamma, rho0_rho=float(self.isentropicRho0RhoEntry.text())) elif choice == ISENTROPIC_CHOICE.T0_T and self.isentropicT0TEntry.text(): state = IsentropicRelations(gamma, t0_t=float(self.isentropicT0TEntry.text())) elif ( choice == ISENTROPIC_CHOICE.a_a_star and self.isentropicAAStarEntry.text() and self.isentropicFlowTypeCombo.currentText() ): flowtype = FlowState(self.isentropicFlowTypeCombo.currentText()) aa_star = float(self.isentropicAAStarEntry.text()) state = IsentropicRelations(gamma, a_a_star=aa_star, flow_type=flowtype) if state is not None: self.isentropicMachEntry.setText(to_str(state.mach)) self.isentropicP0PEntry.setText(to_str(state.p0_p)) self.isentropicAAStarEntry.setText(to_str(state.a_a_star)) self.isentropicT0TEntry.setText(to_str(state.t0_t)) self.isentropicRho0RhoEntry.setText(to_str(state.rho0_rho)) @error_message_decorator def calc_normal_shock_state(self) -> None: """Calculates the normal shock state and sets the entry box values""" if not self.normalShockGammaEntry.text(): return gamma = float(self.normalShockGammaEntry.text()) choice = NORMAL_SHOCK_CHOICE(self.normalShockOptionCombo.currentText()) if not choice: return state = None if choice == NORMAL_SHOCK_CHOICE.MACH and self.normalShockM1Entry.text(): state = NSR(gamma, mach=float(self.normalShockM1Entry.text())) elif choice == NORMAL_SHOCK_CHOICE.P2_P1 and self.normalShockP2P1Entry.text(): state = NSR(gamma, p2_p1=float(self.normalShockP2P1Entry.text())) elif choice == NORMAL_SHOCK_CHOICE.RHO2_RHO1 and self.normalShockRho2Rho1Entry.text(): state = NSR(gamma, rho2_rho1=float(self.normalShockRho2Rho1Entry.text())) elif choice == NORMAL_SHOCK_CHOICE.T2_T1 and self.normalShockT2T1Entry.text(): state = NSR(gamma, t2_t1=float(self.normalShockT2T1Entry.text())) elif choice == NORMAL_SHOCK_CHOICE.PO2_PO1 and self.normalShockP02P01Entry.text(): state = NSR(gamma, po2_po1=float(self.normalShockP02P01Entry.text())) elif choice == NORMAL_SHOCK_CHOICE.PO2_P1 and self.normalShockP02P1Entry.text(): state = NSR(gamma, po2_p1=float(self.normalShockP02P1Entry.text())) elif choice == NORMAL_SHOCK_CHOICE.M2 and self.normalShockM2Entry.text(): state = NSR(gamma, m2=float(self.normalShockM2Entry.text())) else: print("Invalid Choice ") if state is not None: self.normalShockM1Entry.setText(to_str(state.mach)) self.normalShockM2Entry.setText(to_str(state.mach2)) self.normalShockP2P1Entry.setText(to_str(state.p2_p1)) self.normalShockRho2Rho1Entry.setText(to_str(state.rho2_rho1)) self.normalShockT2T1Entry.setText(to_str(state.t2_t1)) self.normalShockP02P01Entry.setText(to_str(state.po2_po1)) self.normalShockP02P1Entry.setText(to_str(state.po2_p1)) @error_message_decorator def calc_oblique_shock_state(self) -> None: # pylint: disable=too-many-statements # pylint: disable=too-many-branches # pylint: disable=too-many-locals """Calculates the oblique shock state and sets the entry box values""" if not self.obliqueShockGammaEntry.text(): return gamma = float(self.obliqueShockGammaEntry.text()) choice = ObliqueShockChoice(self.obliqueShockOptionCombo.currentText()) shock_type = ShockType(self.obliqueshock_typeCombo.currentText()) wedge_angle_valid = bool(self.obliqueShockwedge_angleEdit.text()) shock_angle_valid = bool(self.obliqueshock_angleEdit.text()) m1_valid = bool(self.obliqueShockM1Edit.text()) mn1_valid = bool(self.obliqueShockMn1Edit.text()) mn2_valid = bool(self.obiqueShockMn2Edit.text()) m2_valid = bool(self.obliqueShockM2Edit.text()) p2p1_valid = bool(self.obliqueShockP2P1Edit.text()) rho2_rho1_valid = bool(self.obliqueShockRho2Rho1Edit.text()) po2_p1_valid = bool(self.obliqueShockPo2P1Edit.text()) t2_t1_valid = bool(self.obliqueShockT2T1Edit.text()) po2_po1_valid = bool(self.obliqueShockPo2Po1Edit.text()) degrees = bool(not self.obliqueShockDegreeChkBtn.isChecked()) if not choice: return state = None # common options opts: OBLIQUE_SHOCK_REL_DICT_TYPE = { "gamma": gamma, "use_degrees": degrees, "shock_type": shock_type, "shock_angle": nan, } if choice == ObliqueShockChoice.MACH_WEDGE_ANGLE and m1_valid and wedge_angle_valid: m = float(self.obliqueShockM1Edit.text()) wa = float(self.obliqueShockwedge_angleEdit.text()) state = OSR(**opts, mach=m, wedge_angle=wa) if not shock_angle_valid: return opts["shock_angle"] = float(self.obliqueshock_angleEdit.text()) if choice == ObliqueShockChoice.MACH_SHOCK_ANGLE and m1_valid: m = float(self.obliqueShockM1Edit.text()) state = OSR(**opts, mach=m) elif choice == ObliqueShockChoice.MACH_N_1_SHOCK_ANGLE and mn1_valid: m = float(self.obliqueShockMn1Edit.text()) state = OSR(**opts, mn1=m) elif choice == ObliqueShockChoice.M2_WEDGE_SHOCK_ANGLE and m2_valid and wedge_angle_valid: m2 = float(self.obliqueShockM2Edit.text()) wa = float(self.obliqueShockwedge_angleEdit.text()) state = OSR(**opts, m2=m2, wedge_angle=wa) elif choice == ObliqueShockChoice.P2_P1_SHOCK_ANGLE and p2p1_valid: p2p1 = float(self.obliqueShockP2P1Edit.text()) state = OSR(**opts, p2_p1=p2p1) elif choice == ObliqueShockChoice.RHO2_RHO1_SHOCK_ANGLE and rho2_rho1_valid: r2r1 = float(self.obliqueShockRho2Rho1Edit.text()) state = OSR(**opts, rho2_rho1=r2r1) elif choice == ObliqueShockChoice.T2_T1_SHOCK_ANGLE and t2_t1_valid: t2t1 = float(self.obliqueShockT2T1Edit.text()) state = OSR(**opts, t2_t1=t2t1) elif choice == ObliqueShockChoice.PO2_PO1_SHOCK_ANGLE and po2_po1_valid: p = float(self.obliqueShockPo2Po1Edit.text()) state = OSR(**opts, po2_po1=p) elif choice == ObliqueShockChoice.PO2_P1_SHOCK_ANGLE and po2_p1_valid: p = float(self.obliqueShockPo2P1Edit.text()) state = OSR(**opts, po2_p1=p) elif choice == ObliqueShockChoice.MN2_SHOCK_ANGLE and mn2_valid: m = float(self.obiqueShockMn2Edit.text()) state = OSR(**opts, mn2=m) if state: self.obliqueShockwedge_angleEdit.setText(to_str(state.wedge_angle)) self.obliqueshock_angleEdit.setText(to_str(state.shock_angle)) self.obliqueShockM1Edit.setText(to_str(state.mach)) self.obliqueShockMn1Edit.setText(to_str(state.mach_normal_1)) self.obiqueShockMn2Edit.setText(to_str(state.mach_normal_2)) self.obliqueShockM2Edit.setText(to_str(state.mach2)) self.obliqueShockP2P1Edit.setText(to_str(state.p2_p1)) self.obliqueShockRho2Rho1Edit.setText(to_str(state.rho2_rho1)) self.obliqueShockPo2P1Edit.setText(to_str(state.po2_p1)) self.obliqueShockT2T1Edit.setText(to_str(state.t2_t1)) self.obliqueShockPo2Po1Edit.setText(to_str(state.po2_po1)) @error_message_decorator def calc_fanno_flow_state(self) -> None: # pylint: disable=too-many-locals """Calculates the fanno flow state and sets the entry box values""" if not self.fannoGammaEntry.text(): return gamma = float(self.fannoGammaEntry.text()) choice = FannoFlowChoice(self.fannoOptionCombo.currentText()) flow_type: FlowState = FlowState(self.fannoFlowTypeCombo.currentText()) m_valid = bool(self.fannoUpstreamMachEdit.text()) tt_valid = bool(self.fannoTTStEdit.text()) pp_valid = bool(self.fannoPPStEdit.text()) rr_valid = bool(self.fannoRhoRhoStEdit.text()) popo_valid = bool(self.fannoPoPoStEdit.text()) fric_valid = bool(self.fanno4FLStDEdit.text()) uu_valid = bool(self.fannoUUStEdit.text()) state = None opts: RAY_FANNO_DICT_TYPE = {"gamma": gamma, "flow_type": flow_type} if choice == FannoFlowChoice.GAMMA_MACH and m_valid: m = float(self.fannoUpstreamMachEdit.text()) state = FFR(**opts, mach=m) elif choice == FannoFlowChoice.GAMMA_T_T_ST and tt_valid: tt = float(self.fannoTTStEdit.text()) state = FFR(**opts, t_t_st=tt) elif choice == FannoFlowChoice.GAMMA_P_P_ST and pp_valid: pp = float(self.fannoPPStEdit.text()) state = FFR(**opts, p_p_st=pp) elif choice == FannoFlowChoice.GAMMA_RHO_RHO_ST and rr_valid: rr = float(self.fannoRhoRhoStEdit.text()) state = FFR(**opts, rho_rho_st=rr) elif choice == FannoFlowChoice.GAMMA_PO_PO_ST and popo_valid: popo = float(self.fannoPoPoStEdit.text()) state = FFR(**opts, po_po_st=popo) elif choice == FannoFlowChoice.GAMMA_4FLSTD_FLOW_TYPE and fric_valid: fric = float(self.fanno4FLStDEdit.text()) state = FFR(**opts, f4lst_d=fric) elif choice == FannoFlowChoice.GAMMA_U_U_ST and uu_valid: uu = float(self.fannoUUStEdit.text()) state = FFR(**opts, u_u_st=uu) if state: self.fannoUpstreamMachEdit.setText(to_str(state.mach)) self.fannoTTStEdit.setText(to_str(state.mach)) self.fannoPPStEdit.setText(to_str(state.p_p_st)) self.fannoRhoRhoStEdit.setText(to_str(state.rho_rho_st)) self.fannoPoPoStEdit.setText(to_str(state.po_po_st)) self.fanno4FLStDEdit.setText(to_str(state.f4lst_d)) self.fannoUUStEdit.setText(to_str(state.u_u_st)) self._fanno_state = state @error_message_decorator def calc_fanno_friction_addition(self) -> None: """Calculates the addition of friction to the fanno state and sets the entry box values""" if self._fanno_state is None: return valid_params = bool(self.fannoPipeDiameterEdit.text()) valid_params &= bool(self.fannoFrictionCoeffEdit.text()) valid_params &= bool(self.fannoPipeLenEdit.text()) if not valid_params: return d = float(self.fannoPipeDiameterEdit.text()) f = float(self.fannoFrictionCoeffEdit.text()) l = float(self.fannoPipeLenEdit.text()) self._fanno_state.apply_pipe_parameters(d, l, f) s = self._fanno_state # Down stream conditions self.fannoDwnStrmMachEdit.setText(to_str(s.dwn_strm_mach)) self.fannoDwnStrmTTStEdit.setText(to_str(s.dwn_strm_t_t_st)) self.fannoDwnStrmPPStEdit.setText(to_str(s.dwn_strm_p_p_st)) self.fannoDwnStrmRhoRhoStEdit.setText(to_str(s.dwn_strm_rho_rho_st)) self.fannoDwnStrmPoPoStrEdit.setText(to_str(s.dwn_strm_f4lst_d)) self.fannoDwnStrmUUStEdit.setText(to_str(s.dwn_strm_u_u_st)) self.fannoChokedLengthEdit.setText(to_str(s.choked_length)) # Ratio of down stream to upstream conditions self.fannoT2T1Edit.setText(to_str(s.t2_t1)) self.fannoP2P1Edit.setText(to_str(s.p2_p1)) self.fannoU2U1Edit.setText(to_str(s.u2_u1)) self.fannoRho2Rho1Edit.setText(to_str(s.rho2_rho1)) self.fannoPo2Po1Edit.setText(to_str(s.po2_po1)) self.fanno4FLStD24FLStD1Edit.setText(to_str(s.f4ld2_f4ld1)) @error_message_decorator def calc_rayleigh_flow_state(self) -> None: """Calculates the rayleigh flow state and sets the entry box values""" if not self.rayleighGammaEntry.text(): return gamma = float(self.rayleighGammaEntry.text()) flow_type = FlowState(self.rayleighFlowTypeCombo.currentText()) choice = RayleighFlowChoice(self.rayleighOptionCombo.currentText()) m_valid = bool(self.rayleighUpstreamMachEdit.text()) tt_valid = bool(self.rayleighTTStEdit.text()) pp_valid = bool(self.rayleighPPStEdit.text()) rr_valid = bool(self.rayleighRhoRhoStEdit.text()) popo_valid = bool(self.rayleighPoPoStEdit.text()) toto_valid = bool(self.rayleighToToStEdit.text()) uu_valid = bool(self.rayleighUUStEdit.text()) state = None opts: RAY_FANNO_DICT_TYPE = {"gamma": gamma, "flow_type": flow_type} if choice == RayleighFlowChoice.GAMMA_MACH and m_valid: state = RFR(**opts, mach=float(self.rayleighUpstreamMachEdit.text())) elif choice == RayleighFlowChoice.GAMMA_T_T_ST and tt_valid: state = RFR(**opts, t_t_st=float(self.rayleighTTStEdit.text())) elif choice == RayleighFlowChoice.GAMMA_P_P_ST and pp_valid: state = RFR(**opts, p_p_st=float(self.rayleighPPStEdit.text())) elif choice == RayleighFlowChoice.GAMMA_RHO_RHO_ST and rr_valid: state = RFR(**opts, rho_rho_st=float(self.rayleighRhoRhoStEdit.text())) elif choice == RayleighFlowChoice.GAMMA_PO_PO_ST and popo_valid: state = RFR(**opts, po_po_st=float(self.rayleighPoPoStEdit.text())) elif choice == RayleighFlowChoice.GAMMA_TO_TO_FLOW_TYPE and toto_valid: state = RFR(**opts, to_to_st=float(self.rayleighToToStEdit.text())) elif choice == RayleighFlowChoice.GAMMA_U_U_ST and uu_valid: state = RFR(**opts, u_u_st=float(self.rayleighUUStEdit.text())) self._rayleigh_state = state if state: s = state self.rayleighUpstreamMachEdit.setText(to_str(s.mach)) self.rayleighTTStEdit.setText(to_str(s.t_t_st)) self.rayleighPPStEdit.setText(to_str(s.p_p_st)) self.rayleighRhoRhoStEdit.setText(to_str(s.rho_rho_st)) self.rayleighPoPoStEdit.setText(to_str(s.po_po_st)) self.rayleighToToStEdit.setText(to_str(s.to_to_st)) self.rayleighUUStEdit.setText(to_str(s.u_u_st)) @error_message_decorator def calc_rayleigh_heat_addition(self) -> None: """Calculates the addition of heat to the rayleigh state and sets the entry box values""" if self._rayleigh_state is None: return valid_params = bool(self.rayleighHeatEdit.text()) valid_params &= bool(self.rayleighGasConstantEdit.text()) valid_params &= bool(self.rayleighHeatTo1Edit.text()) if not valid_params: return h = float(self.rayleighHeatEdit.text()) r = float(self.rayleighGasConstantEdit.text()) t = float(self.rayleighHeatTo1Edit.text()) self._rayleigh_state.simulate_heat_addition(h, t, r) s = self._rayleigh_state # Down stream conditions self.rayleighDwnStrmMachEdit.setText(to_str(s.dwn_strm_mach)) self.rayleighDwnStrmTTStEdit.setText(to_str(s.dwn_strm_t_t_st)) self.rayleighDwnStrmPPStEdit.setText(to_str(s.dwn_strm_p_p_st)) self.rayleighDwnStrmRhoRhoStEdit.setText(to_str(s.dwn_strm_rho_rho_st)) self.rayleighDwnStrmPoPoStrEdit.setText(to_str(s.dwn_strm_po_po_st)) self.rayleighDwnStrmToToStEdit.setText(to_str(s.dwn_strm_to_to_st)) self.rayleighDwnStrmUUStEdit.setText(to_str(s.dwn_strm_u_u_st)) self.rayleighChokedHeatEdit.setText(to_str(s.choked_heat)) # Ratio of down stream to upstream conditions self.rayleighT2T1Edit.setText(to_str(s.t2_t1)) self.rayleighP2P1Edit.setText(to_str(s.p2_p1)) self.rayleighU2U1Edit.setText(to_str(s.u2_u1)) self.rayleighRho2Rho1Edit.setText(to_str(s.rho2_rho1)) self.rayleighPo2Po1Edit.setText(to_str(s.po2_po1)) self.rayleighTo2To1Edit.setText(to_str(s.to2_to1)) self.rayleighTo2Edit.setText(to_str(s.to2)) @error_message_decorator def calc_prantl_meyer_state(self) -> None: """Calculates prantl meyer state and sets the entry box values""" if not self.prandtlMeyerGammaEntry.text(): return gamma = float(self.prandtlMeyerGammaEntry.text()) choice = PrandtlMeyerChoice(self.prandtlMeyerOptionCombo.currentText()) m_valid = bool(self.prandtlMeyerUpstreamMachEdit.text()) nu_valid = bool(self.prandtlMeyerNuEdit.text()) mu_valid = bool(self.prandtlMeyerMuEdit.text()) angle_valid = bool(self.prandtlMeyerDeflectionAngleEdit.text()) d_m_valid = bool(self.prandtlMeyerDwnStrmMachEdit.text()) d_nu_valid = bool(self.prandtlMeyerDwnStrmNuEdit.text()) d_mu_valid = bool(self.prandtlMeyerDwnStrmMuEdit.text()) degrees = not self.prandtlMeyerDegreeChkBtn.isChecked() state = None opts: PRANDTL_MEYER_DICT_TYPE = { "gamma": gamma, "in_degrees": degrees, "deflection_angle": nan, } if angle_valid: opts["deflection_angle"] = float(self.prandtlMeyerDeflectionAngleEdit.text()) if choice == PrandtlMeyerChoice.GAMMA_MACH and m_valid: state = PM(**opts, mach=float(self.prandtlMeyerUpstreamMachEdit.text())) elif choice == PrandtlMeyerChoice.GAMMA_NU and nu_valid: state = PM(**opts, nu=float(self.prandtlMeyerNuEdit.text())) elif choice == PrandtlMeyerChoice.GAMMA_MU and mu_valid: state = PM(**opts, mu=float(self.prandtlMeyerMuEdit.text())) elif choice == PrandtlMeyerChoice.GAMMA_DEFLECTION_DWN_STRM_MACH and d_m_valid: state = PM(**opts, down_stream_mach=float(self.prandtlMeyerDwnStrmMachEdit.text())) elif choice == PrandtlMeyerChoice.GAMMA_DEFLECTION_DWN_STRM_MU and d_mu_valid: state = PM(**opts, down_stream_mu=float(self.prandtlMeyerDwnStrmMuEdit.text())) elif choice == PrandtlMeyerChoice.GAMMA_DEFLECTION_DWN_STRM_NU and d_nu_valid: state = PM(**opts, down_stream_nu=float(self.prandtlMeyerDwnStrmNuEdit.text())) if state: s = state self.prandtlMeyerUpstreamMachEdit.setText(to_str(s.mach)) self.prandtlMeyerNuEdit.setText(to_str(s.nu)) self.prandtlMeyerMuEdit.setText(to_str(s.mu)) self.prandtlMeyerDwnStrmMachEdit.setText(to_str(s.down_stream_mach)) self.prandtlMeyerDwnStrmMuEdit.setText(to_str(s.down_stream_mu)) self.prandtlMeyerDwnStrmNuEdit.setText(to_str(s.down_stream_nu)) @error_message_decorator def calc_rocket_nozzle_state(self) -> None: """Calculates rocket nozzle state and sets the entry box values""" gamma_valid = bool(self.rocketNozzleGammaEntry.text()) ar_valid = bool(self.rocketNozzleAreaRatioEdit.text()) pepc_valid = bool(self.rocketNozzlePePcEdit.text()) papc_valid = bool(self.rocketNozzlePaPcEdit.text()) gamma, ar, pe_pc, pa_pc = (0.0, 0.0, 0.0, 0.0) if gamma_valid: gamma = float(self.rocketNozzleGammaEntry.text()) if ar_valid: ar = float(self.rocketNozzleAreaRatioEdit.text()) if pepc_valid: pe_pc = float(self.rocketNozzlePePcEdit.text()) if papc_valid: pa_pc = float(self.rocketNozzlePaPcEdit.text()) if ar_valid: min_coeff = min_thrust_coefficient(ar) self.rocketNozzleMinThrustCoeffEdit.setText(to_str(min_coeff)) if gamma_valid and ar_valid and pepc_valid: max_coeff = max_thrust_coefficient(gamma, ar, pe_pc) self.rocketNozzleMaxThrustCoeffEdit.setText(to_str(max_coeff)) if gamma_valid and ar_valid and pepc_valid and papc_valid: coeff = thrust_coefficient(gamma, ar, pe_pc, pa_pc) self.rocketNozzleThrustCoeffEdit.setText(to_str(coeff))
Ancestors
- PyQt5.QtWidgets.QMainWindow
- PyQt5.QtWidgets.QWidget
- PyQt5.QtCore.QObject
- sip.wrapper
- PyQt5.QtGui.QPaintDevice
- sip.simplewrapper
- Ui_MainWindow
Methods
def calc_fanno_flow_state(self)
-
Expand source code
def _wrapped_func(self): result = None try: result = func(self) except ValueError as e: self.show_error(f"Error Occured! \n {e}") return result
def calc_fanno_friction_addition(self)
-
Expand source code
def _wrapped_func(self): result = None try: result = func(self) except ValueError as e: self.show_error(f"Error Occured! \n {e}") return result
def calc_isentropic_state(self)
-
Expand source code
def _wrapped_func(self): result = None try: result = func(self) except ValueError as e: self.show_error(f"Error Occured! \n {e}") return result
def calc_normal_shock_state(self)
-
Expand source code
def _wrapped_func(self): result = None try: result = func(self) except ValueError as e: self.show_error(f"Error Occured! \n {e}") return result
def calc_oblique_shock_state(self)
-
Expand source code
def _wrapped_func(self): result = None try: result = func(self) except ValueError as e: self.show_error(f"Error Occured! \n {e}") return result
def calc_prantl_meyer_state(self)
-
Expand source code
def _wrapped_func(self): result = None try: result = func(self) except ValueError as e: self.show_error(f"Error Occured! \n {e}") return result
def calc_rayleigh_flow_state(self)
-
Expand source code
def _wrapped_func(self): result = None try: result = func(self) except ValueError as e: self.show_error(f"Error Occured! \n {e}") return result
def calc_rayleigh_heat_addition(self)
-
Expand source code
def _wrapped_func(self): result = None try: result = func(self) except ValueError as e: self.show_error(f"Error Occured! \n {e}") return result
def calc_rocket_nozzle_state(self)
-
Expand source code
def _wrapped_func(self): result = None try: result = func(self) except ValueError as e: self.show_error(f"Error Occured! \n {e}") return result
def oblique_shock_degrees_chk_box_update(self) ‑> None
-
Changes the text on the button to reflect the oblique shock angle units
Expand source code
def oblique_shock_degrees_chk_box_update(self) -> None: """Changes the text on the button to reflect the oblique shock angle units""" if self.obliqueShockDegreeChkBtn.isChecked(): self.obliqueShockDegreeChkBtn.setText("Radians") else: self.obliqueShockDegreeChkBtn.setText("Degrees")
def prandtl_meyer_degrees_chk_box_update(self)
-
Expand source code
def _wrapped_func(self): result = None try: result = func(self) except ValueError as e: self.show_error(f"Error Occured! \n {e}") return result
def show_error(self, msg: str) ‑> None
-
Shows the error popup with a message
Args
msg
:str
- msg to show in the popup
Expand source code
def show_error(self, msg: str) -> None: """ Shows the error popup with a message Args: msg (str): msg to show in the popup """ self._error_box.showMessage(msg)