Example #1
0
    def test_table(self):
        # Test if the table of the original paper can be reproduced Span2000
        # Page 1410 of Span2000
        fp = FluidProperties("nitrogen")

        pressure = 1e5  # 1 bar of pressure

        # T in, density out
        # Density taken in kg/mol from table, divided by molar mass
        in_out = ((300, 1.12328452104, 4), (330, 1.0209512786000001, 4),
                  (450, 0.74846415864, 4), (600, 0.5613060987599999,
                                            4), (1000, 0.33680607004, 4))

        for T, rho, places in in_out:
            res_rho = fp.get_density(T=T, p=pressure)
            self.assertAlmostEqual(res_rho, rho, places=places)

        # Same again but for different pressure
        pressure = 1e6  # 10 bars of pressure

        # T in, density out
        # Density taken in kg/mol from table, divided by molar mass
        in_out = ((300, 11.248812894, 4), (330, 10.2058710336, 3),
                  (450, 7.459989724000001, 3), (600, 5.591490608,
                                                3), (1000, 3.3576957128, 3))

        for T, rho, places in in_out:
            res_rho = fp.get_density(T=T, p=pressure)
            self.assertAlmostEqual(res_rho, rho, places=places)
Example #2
0
    def test_table(self):
        # Page 1410 of Span2000
        fp = FluidProperties("nitrogen")

        pressure = 1e5  # 1 bar of pressure
        molar_mass = 0.02801348  # [kg/mol] also from Span2000

        # T in, enthalpy out
        # Enthalpy taken in J/mol from table
        in_out = ((300, 8717.7, 0), (330, 9593.0, -1), (450, 13105, -1),
                  (600, 17564, -1), (1000, 30135, -2))

        for T, h, places in in_out:
            res_h = fp.get_enthalpy(T=T, p=pressure)
            self.assertAlmostEqual(
                res_h, h / molar_mass, places=places
            )  # Must be divided by molar mass as CoolProp gives enthalpy for J/kg

        # Testing again, but for another pressure

        pressure = 1e6
        in_out = ((300, 8662.5, -1), (320, 9253.6, -1), (400, 11612, -1),
                  (550, 16060, -2), (800, 23728, -2), (1000, 30152, -2))

        for T, h, places in in_out:
            res_h = fp.get_enthalpy(T=T, p=pressure)
            self.assertAlmostEqual(
                res_h, h / molar_mass, places=places
            )  # Must be divided by molar mass as CoolProp gives enthalpy for J/kg
Example #3
0
    def test_table(self):
        # Page 1410 of Span2000 and further. Values must be converted to kg/m^3 from mol/dm^3 with molar mass = 0.02801348e3
        fp = FluidProperties("nitrogen")
        # Just use a single temperature
        T = 300  # [K]

        # density in, pressure out
        in_out = ((1.1232845210400002, 1e5, -1), (2.2469612308, 2e5, -1),
                  (5.6200643576000004, 5e5, -2), (11.248812894, 10e5, -1),
                  (16.883724396, 15e5, -2), (22.523398189599998, 20e5, -1))

        for rho, p, places in in_out:
            res_p = fp.get_pressure(T=T, rho=rho)
            self.assertAlmostEqual(res_p, p, places=places)

        # Again, but different temperature
        T = 1000  # [K]

        in_out = ((0.33680607004, 1e5, 0), (0.67338803224, 2e5, -1), (
            1.68170523136,
            5e5,
            -1,
        ), (3.35775173976, 10e5, -2), (5.027859390400001, 15e5, -2),
                  (6.6921402372, 20e5, -2))

        for rho, p, places in in_out:
            res_p = fp.get_pressure(T=T, rho=rho)
            self.assertAlmostEqual(res_p, p, places=places)
Example #4
0
    def test_table(self):
        # Test reported values of gamma by taking cp/cv from Span2000 (page 1410 and below)
        # Test if the table of the original paper can be reproduced Span2000
        # Page 1410 of Span2000
        fp = FluidProperties("nitrogen")

        pressure = 1e5  # 1 bar of pressure

        # T in, gamma out
        # gamma not explicitly in table, but cp/cv is put in here instead
        in_out = ((300, 1.402784445511282, 2), (330, 1.4021113243761996, 2),
                  (450, 1.3956356736242885, 3), (600, 1.3821100917431193, 3),
                  (1000, 1.3411234112341124, 3))

        for T, gamma, places in in_out:
            res_gamma = fp.get_specific_heat_ratio(T=T, p=pressure)
            self.assertAlmostEqual(res_gamma, gamma, places=places)

        # Again but with different pressure
        pressure = 1e6  # 10 bar of pressure

        # T in, gamma out
        # gamma not explicitly in table, but cp/cv is put in here instead
        in_out = ((300, 1.41666666666666672, 2), (330, 1.4126376256582096, 2),
                  (450, 1.400947867298578, 3), (600, 1.3846859238881248, 3),
                  (1000, 1.3419434194341942, 3))

        for T, gamma, places in in_out:
            res_gamma = fp.get_specific_heat_ratio(T=T, p=pressure)
            self.assertAlmostEqual(res_gamma, gamma, places=places)
Example #5
0
def plotGammaCurve():
    fp = FluidProperties("water")
    temperature = np.linspace(start=500, stop=1000, num=200)
    pressure = np.linspace(start=1.0e5, stop=5.0e5, num=3)

    gamma = np.zeros((pressure.size, temperature.size))

    p_iter = np.nditer(pressure, flags=['c_index'])
    T_iter = np.nditer(temperature, flags=['c_index'])

    for p in p_iter:
        i = p_iter.index
        T_iter.reset()
        for T in T_iter:
            j = T_iter.index
            gamma[i, j] = fp.get_specific_heat_ratio(T=float(T), p=float(p))

    plt.figure()
    p_iter.reset()
    for p in p_iter:
        i = p_iter.index
        plt.plot(temperature,
                 gamma[i, :],
                 label="{:1.0f} bar".format(p * 1e-5))

    plt.xlabel("Temperature - $T$ [K]")
    plt.ylabel("Specific heat ratio - $\\gamma$ [-] ")
    plt.grid()
    plt.legend(title="Pressure")
    plt.title("Specific heat ratio of water")
    plt.tight_layout()
Example #6
0
    def test_table(self):
        # Page 1410 of Span2000
        fp = FluidProperties("nitrogen")

        pressure = 1e5  # 1 bar of pressureM
        # T in, cpout
        in_out = ((300, 1041.2844102196514, 0), (330, 1041.6413812207552, 0),
                  (450, 1049.4947432450376, 0), (600, 1075.1966553245081, 0),
                  (1000, 1167.2951736092768, 0))

        for T, cp, places in in_out:
            res_cp = fp.get_cp(T=T, p=pressure)
            self.assertAlmostEqual(res_cp, cp, places=places)

        # Testing again, but for another pressure

        pressure = 1e6
        in_out = ((300, 1055.9202212649052, 0), (320, 1054.1353662593865, 0),
                  (400, 1052.3505112538678, 0), (550, 1068.4142063035367, 0),
                  (800, 1123.7447114746187, 0), (1000, 1168.3660866125879, 0))

        for T, cp, places in in_out:
            res_cp = fp.get_cp(T=T, p=pressure)
            self.assertAlmostEqual(
                res_cp, cp, places=places
            )  # Must be divided by molar mass as CoolProp gives enthalpy for J/kg
Example #7
0
def plotSaturationCurve():
    fp = FluidProperties("water")
    p_sat = np.linspace(start=0.01e5, stop=10.0e5, num=100)  # [P] Pressure
    T_sat = fp.get_saturation_temperature(p_sat)  # [K]

    plt.figure()
    plt.plot(T_sat, p_sat * 1e-5)
    plt.xlabel("Saturation temperature - $T_{{sat}}$ [K]")
    plt.ylabel("Saturation pressure - $p_{{sat}}$ [bar]")
    plt.grid()
    plt.title("Saturation curve for water")
    plt.tight_layout()
Example #8
0
    def test_table(self):
        # Table V from Lemmon2004 has density as inputs, which is not interesting for our purposes, so first the pressure must be obtained

        fp = FluidProperties("nitrogen")

        # T in, Density in mol/dm^3, thermal conductivity in W/(m*K)
        in_out = ((100, 25.0, 103.834e-3, 6), (200, 10.0, 36.0099e-3, 7),
                  (300, 5.0, 32.7694e-3, 7))

        molar_mass = 0.02801348  # [kg/mol] also from Span2000

        for T, rho, kappa, places in in_out:
            p = fp.get_pressure(T=T, rho=rho * molar_mass * 1e3)
            res_kappa = fp.get_thermal_conductivity(T=T, p=p)
            self.assertAlmostEqual(res_kappa, kappa, places=places)
Example #9
0
    def test_table(self):
        # Table V from Lemmon2004 has density as inputs, which is not interesting for our purposes, so first the pressure must be obtained

        fp = FluidProperties("nitrogen")

        # T in, Density in mol/dm^3, viscosity out Pa*s
        in_out = ((100, 25.0, 79.7418e-6, 10), (200, 10.0, 21.0810e-6, 10),
                  (300, 5.0, 20.7430e-6, 10))

        molar_mass = 0.02801348  # [kg/mol] also from Span2000

        for T, rho, mu, places in in_out:
            p = fp.get_pressure(T=T, rho=rho * molar_mass * 1e3)
            res_mu = fp.get_viscosity(T=T, p=p)
            self.assertAlmostEqual(res_mu, mu, places=places)
Example #10
0
    def testIntegrationWithKandlikarRelation(self):
        # Same test but only focussing on Nusselt number for Kandlikar relation, as that would prove thar arguments are correctly passed to function
        td = thrusters.thruster_data.td_verification_one # Dummy dictionary with thruster data for verifcation

        Nu_func_gas = thermo.convection.Nu_DB
        Nu_func_liquid = thermo.convection.Nu_Kandlikar_NDB_Re_low_sat_gas_constant_wall_temp_square_water

        T_wall = td['T_wall']
        w_channel = td['w_channel']
        T_inlet = td['T_inlet']
        T_chamber = td['T_chamber']
        p_ref = td['p_inlet']
        m_dot = td['m_dot']
        h_channel = td['h_channel']
        fp = FluidProperties(td['propellant'])

        # Check just the liquid/multi-phase Nusselt number of the Kandlikar relation, to ensure integration is correct
        exp_Nu_liquid_multi = 46.74856022286813
        

        res = zD.two_phase_single_channel(
            T_wall=T_wall,
            w_channel=w_channel,
            Nu_func_gas=Nu_func_gas,
            Nu_func_liquid=Nu_func_liquid,
            T_inlet=T_inlet,
            T_chamber=T_chamber,
            p_ref=p_ref,
            m_dot=m_dot,
            h_channel=h_channel,
            fp=fp,
            print_info=False)

        self.assertAlmostEqual(exp_Nu_liquid_multi, res['Nu_liquid_multi'], delta=0.01*exp_Nu_liquid_multi)
Example #11
0
File: IRT.py Project: j-thd/thesis
def engine_performance_from_F_and_T(F_desired, p_chamber, T_chamber, AR_exit,
                                    p_back, fp: FluidProperties):
    """ Returns Nozzle Inlet State based on IRT

    Args:
        F_desired (N): Desired thrust
        p_chamber (Pa): Chamber thrust/nozzle inlet pressure
        T_chamber (K): Chamber temperature
        AR_exit (-): A_exit / A_throat
        p_back (Pa): Back pressure
        fp (FluidProperties): Used to access fluid properties

    Raises:
        Exception: Raised when no solution is found for given input

    Returns:
        dict{A_throat [m^2], m_dot [kg/s]}: Throat area and mass flow
    """
    # Default range for temperature for root-finding algorithm
    A_low = 1e-22  # [K]
    A_high = 1e-3  # [K]

    R = fp.get_specific_gas_constant()  # [J/(kg*K)]
    gamma = fp.get_specific_heat_ratio(T_chamber,
                                       p_chamber)  # [-] Specific heat ratio
    # If x is zero, then the desired thrust is found. Gamma is changed depending on temperature as well
    x = lambda A_t: F_desired - get_engine_performance(p_chamber=p_chamber, T_chamber=T_chamber, A_throat=A_t, \
                        AR_exit=AR_exit,p_back=p_back, gamma=gamma,R=R)['thrust']

    root_result = optimize.root_scalar(x, bracket=[A_low, A_high], xtol=1e-12)

    if root_result.converged:
        A_throat = root_result.root  # [m^2]
    else:
        raise Exception("No solution found for given temperature")

    # Now the chamber temperature is known, return the unknown parameters

    ep = get_engine_performance(p_chamber=p_chamber, T_chamber=T_chamber, A_throat=A_throat, \
                        AR_exit=AR_exit,p_back=p_back, gamma=fp.get_specific_heat_ratio(T_chamber,p_chamber),R=R)
    # Add throat area to dictionary
    ep['A_throat'] = A_throat  # This is usually an input for get_engine_performance, but now added to make it one complete solution
    #ep['Isp'] = IRT.effective_ISP(thrust=F_desired,m_dot=ep['m_dot']) # [s] Effective specific impulse

    return ep
Example #12
0
    def test_one(self):
        # Simply re-using case above, only heating
        fp = FluidProperties("HEOS::Water")
        T_inlet = 700  # [K]
        T_outlet = 900  # [K]
        # This makes the bulk temperature 800 K
        p = 5e5  # [Pa]

        D_h = 1e-3
        u = 1e-3

        T_bulk = (T_outlet + T_inlet) / 2
        Re = fp.get_Reynolds_from_velocity(T=T_bulk, p=p, L_ref=D_h, u=u)
        Pr = fp.get_Prandtl(T=T_bulk, p=p)
        arguments = {'fp': fp, 'Re': Re, 'Pr': Pr}
        exp_Nu = 0.0018785745665208552
        res_Nu = thermo.convection.Nu_DB(args=arguments)
        self.assertAlmostEqual(exp_Nu, res_Nu, delta=0.00001 * exp_Nu / res_Nu)
Example #13
0
def h_conv_from_Stanton(Stanton, u, T_ref, p_ref, fp: FluidProperties):
    """Return heat transfer coefficient dependent on Stanton number and thermodynamic state\
        Temperature and pressure are passed instead of T and p, as these abstract away constant computations of cp and rho\
            and it is easier to pass around the same state variables time and time again

            WARNING: REFERENCE THERMODYNAMIC STATE (T_ref, p_ref) MUST BE EQUAL TO THOSE WITH WHICH NUSSELT NUMBER WAS DETERMINED

    Args:
        Stanton (-): Stanton number: dimensionless flow characteristic
        u (m/s): flow velocity
        T_ref (K): Temperature
        p_ref (Pa): Pressure
        fp (FluidProperties): object to use to obtain properties of fluid

    Returns:
        h_conv (W/(m^2*K)): convective heat transfer coefficient based on Stanton number, flow velocity and thermodynamic state
    """
    cp = fp.get_cp(T=T_ref, p=p_ref) # [J/kg] Specific heat capacity under constant pressure
    rho = fp.get_density(T=T_ref,p=p_ref) # [kg/m^3] Fluid density

    return Stanton*rho*u*cp # [W/(m^2*K)] h_conv: Convective heat transfer coefficient
Example #14
0
    def setUp(self):
        # Inputs
        fp = FluidProperties('water')
        p_inlet = 2e5  # [Pa] Inlet pressure
        steps = 10  # [-] Number of data point
        m_dot = 1e-4  # [kg/s]

        self.prep = oneD.prepare_homogenous_transition(steps=steps,
                                                       p=p_inlet,
                                                       m_dot=m_dot,
                                                       fp=fp)
        return super().setUp()
Example #15
0
    def test_webbook_data(self):
        # Pick some random points of NIST webbook to calculate Prandlt numbers, instead of re-using tables of different functions
        # Source: https://webbook.nist.gov/cgi/fluid.cgi?T=300&PLow=1&PHigh=10&PInc=1&Applet=on&Digits=5&ID=C7727379&Action=Load&Type=IsoTherm&TUnit=K&PUnit=bar&DUnit=kg%2Fm3&HUnit=kJ%2Fkg&WUnit=m%2Fs&VisUnit=Pa*s&STUnit=N%2Fm&RefState=DEF

        fp = FluidProperties("nitrogen")

        T = 300  # [K]
        p = 2e5  # [Pa]

        exp_Pr = 0.721667851210939
        res_Pr = fp.get_Prandtl(T=T, p=p)
        self.assertAlmostEqual(exp_Pr, res_Pr, places=2)

        p = 10e5
        exp_Pr = 0.7279411479231152
        res_Pr = fp.get_Prandtl(T=T, p=p)
        self.assertAlmostEqual(exp_Pr, res_Pr, places=2)

        # Source for 1000K : https://webbook.nist.gov/cgi/fluid.cgi?Action=Load&ID=C7727379&Type=IsoTherm&Digits=5&PLow=1&PHigh=10&PInc=1&T=1000&RefState=DEF&TUnit=K&PUnit=bar&DUnit=kg%2Fm3&HUnit=kJ%2Fkg&WUnit=m%2Fs&VisUnit=Pa*s&STUnit=N%2Fm
        T = 1000  # [K]
        p = 2e5  # [Pa]

        exp_Pr = 0.7359141666666666
        res_Pr = fp.get_Prandtl(T=T, p=p)
        self.assertAlmostEqual(exp_Pr, res_Pr, places=1)

        T = 1000  # [K]
        p = 10e5  # [Pa]

        exp_Pr = 0.7361587678944341
        res_Pr = fp.get_Prandtl(T=T, p=p)
        self.assertAlmostEqual(exp_Pr, res_Pr, places=1)
Example #16
0
    def test_webbook_data(self):
        # Pick some random points of NIST webbook to calculate Reynolds numbers, instead of re-using tables of different functions
        # Source: https://webbook.nist.gov/cgi/fluid.cgi?T=300&PLow=1&PHigh=10&PInc=1&Applet=on&Digits=5&ID=C7727379&Action=Load&Type=IsoTherm&TUnit=K&PUnit=bar&DUnit=kg%2Fm3&HUnit=kJ%2Fkg&WUnit=m%2Fs&VisUnit=Pa*s&STUnit=N%2Fm&RefState=DEF

        fp = FluidProperties("nitrogen")

        T = 300  # [K]
        p = 1e5  # [Pa]
        u = 1  # [m/s]
        L = 1  # [m]

        exp_Re = 62764.70916913448
        res_Re = fp.get_Reynolds_from_velocity(T=T, p=p, u=u, L_ref=L)
        self.assertAlmostEqual(exp_Re, res_Re, places=-2)

        u = u * 2  # [m/s]
        exp_Re = 2 * 62764.70916913448
        res_Re = fp.get_Reynolds_from_velocity(T=T, p=p, u=u, L_ref=L)
        self.assertAlmostEqual(exp_Re, res_Re, places=-2)

        L = 1 / 3  # [m]
        exp_Re = 2 / 3 * 62764.70916913448
        res_Re = fp.get_Reynolds_from_velocity(T=T, p=p, u=u, L_ref=L)
        self.assertAlmostEqual(exp_Re, res_Re, places=-2)

        T = 1000  # [K]
        p = 10e5  # [Pa]
        u = 1e-3  # [m/s]
        L = 10e-3  # [m]

        exp_Re = 0.806359422656644
        res_Re = fp.get_Reynolds_from_velocity(T=T, p=p, u=u, L_ref=L)
        self.assertAlmostEqual(exp_Re, res_Re, places=2)
Example #17
0
    def setUp(self):
        # Inputs
        fp = FluidProperties('water')
        T_outlet = 450  # [K]
        p_inlet = 2e5  # [Pa] Inlet pressure
        steps = 10  # [-] Number of data point
        m_dot = 1e-3  # [kg/s]

        self.prep = oneD.prepare_single_phase_gas(T_outlet=T_outlet,
                                                  steps=steps,
                                                  p_ref=p_inlet,
                                                  m_dot=m_dot,
                                                  fp=fp)
        return super().setUp()
Example #18
0
def ideal_enthalpy_change(T_inlet, p_inlet, T_outlet, p_outlet, fp: FluidProperties):
    """Returns specific enthalpy change based on simple chamber inlet and outlet conditions.
    This should give the power the micro-heater must transfer in ideal conditions with no heat losses.
    In addition returns a warning if the final state is not gaseous.
    
    Arguments:
        T_inlet {K} -- Inlet temperature
        p_inlet {Pa} -- Inlet pressure
        T_outlet {K} -- Outlet temperature
        p_outlet {Pa} -- Outlet pressure
        fp {object} -- FluidProperties object
    
    Returns:
        delta_h {J/(kg*K)} -- 
    """

    h_inlet = fp.get_enthalpy(T=T_inlet, p=p_inlet)
    h_outlet = fp.get_enthalpy(T=T_outlet, p=p_outlet)

    outlet_phase = fp.get_phase(T=T_outlet,p=p_outlet)
    if not (outlet_phase == 'gas' or outlet_phase == 'supercritical_gas'):
        print("Warning: Phase at chamber exit is not gaseous but {}".format(outlet_phase))
        
    return h_outlet-h_inlet
Example #19
0
def run2():
    #Calcuate heating efficiency of heaters in literature
    m_dot = 0.83e-6 # [kg/s] mass flow
    T_in = 24+273.15 # [K] Inlet temperature
    T_out = 426.65 # [K] Outlet temperature
    p = 5.15e5 # [Pa] Pressure
    P_total = 8.19 # [W] Total electrical power

    fp = FluidProperties("water")

    # Specific enthalpy at inlet and outlet
    h_in = fp.get_enthalpy(T=T_in, p=p) # [J/kg] Inlet
    h_out = fp.get_enthalpy(T=T_out, p=p) # [J/kg] Outlet
    
    P_delta_h = m_dot*(h_out-h_in) # [W] Power raising enthalpy
    efficiency = P_delta_h/P_total # [-]

    print("Exit phase: {}".format(fp.get_phase(T=T_out,p=p)))

    print("P_delta_h: {:1.2f} W".format(P_delta_h))
    print("Micro-heater efficiency: {:1.2f} ".format(efficiency))

    print("T_in = {:3.0f} K \t\t T_out =  {:3.0f} K".format(T_in,T_out))
    print("Mass flow = {:2.2f} mg/s".format(m_dot*1e6))
Example #20
0
    def test_water_input(self):
        # Source: https://webbook.nist.gov/cgi/fluid.cgi?Action=Load&ID=C7732185&Type=IsoBar&Digits=5&P=0.1&THigh=1000&TLow=300&TInc=100&RefState=DEF&TUnit=K&PUnit=MPa&DUnit=kg%2Fm3&HUnit=kJ%2Fkg&WUnit=m%2Fs&VisUnit=Pa*s&STUnit=N%2Fm
        fp = FluidProperties("HEOS::Water")

        T = 500  # [K]
        p = 5e5  # [Pa]
        u = 1e-3  # [m/s]
        St = 1

        exp_h_conv = 4.6448084  # [W/(m^2*K)] Convective heat transfer
        res_h_conv = chamber.h_conv_from_Stanton(Stanton=St,
                                                 T_ref=T,
                                                 p_ref=p,
                                                 u=u,
                                                 fp=fp)
        self.assertAlmostEqual(exp_h_conv,
                               res_h_conv,
                               delta=exp_h_conv / res_h_conv * 0.0001)
Example #21
0
    def test_one(self):
        # Calculate a known case manually, and check for similarity
        # Source: https://webbook.nist.gov/cgi/fluid.cgi?Action=Load&ID=C7732185&Type=IsoBar&Digits=5&P=0.5&THigh=1000&TLow=300&TInc=100&RefState=DEF&TUnit=K&PUnit=MPa&DUnit=kg%2Fm3&HUnit=kJ%2Fkg&WUnit=m%2Fs&VisUnit=Pa*s&STUnit=N%2Fm

        fp = FluidProperties("HEOS::Water")
        T_inlet = 700  # [K]
        T_outlet = 900  # [K]
        # This makes the bulk temperature 800 K
        p = 5e5  # [Pa]

        D_h = 1e-3
        L = 1000e-3

        m_dot = 1e-6  # [kg/s]
        A = 0.0007359976448075365  # [m^2]

        exp_Nu = 0.0018785745665208552
        res_Nu = thermo.convection.Nusselt_Dittus_Boelter(
            T_inlet=T_inlet,
            T_outlet=T_outlet,
            p=p,
            D_hydraulic=D_h,
            L_channel=L,
            m_dot=m_dot,
            A=A,
            fp=fp,
            supressExceptions=True)
        self.assertAlmostEqual(exp_Nu, res_Nu, delta=0.01 * exp_Nu)

        # Same but with cooling assumption

        exp_Nu = 0.001896461381677763
        res_Nu = thermo.convection.Nusselt_Dittus_Boelter(
            T_inlet=T_inlet,
            T_outlet=T_outlet,
            p=p,
            D_hydraulic=D_h,
            L_channel=L,
            m_dot=m_dot,
            A=A,
            fp=fp,
            heating=False,
            supressExceptions=True)
        self.assertAlmostEqual(exp_Nu, res_Nu, delta=0.01 * exp_Nu)
Example #22
0
    def test_one(self):
        #Simply Re-using case above again
        fp = FluidProperties("water")
        T_inlet = 700  # [K]
        T_outlet = 900  # [K]
        # This makes the bulk temperature 800 K
        p = 5e5  # [Pa]

        D_h = 1e-3
        m_dot = 1e-6  # [kg/s]
        A = 0.0007359976448075365  # [m^2]

        Nu_func = Nu_DB
        T_bulk = (T_inlet + T_outlet) / 2

        Pr = 0.9095872167254094
        Re = 0.04578292954139569

        exp_St = 0.0018785745665208552 / (Re * Pr)
        res_St = thermo.convection.Stanton_from_Nusselt_func_and_velocity(
            Nu_func=Nu_func,
            m_dot=m_dot,
            A=A,
            T_ref=T_bulk,
            p_ref=p,
            L_ref=D_h,
            fp=fp)
        self.assertAlmostEqual(exp_St, res_St, delta=exp_St * 0.01)

        def dummy_func(args):
            return 5

        # Another test with a dummy func
        exp_St = 5 / (Re * Pr)
        res_St = thermo.convection.Stanton_from_Nusselt_func_and_velocity(
            Nu_func=dummy_func,
            m_dot=m_dot,
            A=A,
            T_ref=T_bulk,
            p_ref=p,
            L_ref=D_h,
            fp=fp)
        self.assertAlmostEqual(exp_St, res_St, delta=exp_St * 0.01)
Example #23
0
    def setUp(self):
        # Inputs
        fp = FluidProperties('water')
        T_inlet = 300  # [K]
        p_inlet = 2e5  # [Pa] Inlet pressure
        steps = 3  # [-] 3 steps for convenience
        m_dot = 0.1e-3  # [kg/s]
        # Get the prepared thermodynamic values
        self.prep = oneD.prepare_single_phase_liquid(T_inlet=T_inlet,
                                                     steps=steps,
                                                     p_ref=p_inlet,
                                                     m_dot=m_dot,
                                                     fp=fp)
        # set the Nusselt function
        Nu_func_liquid = thermo.convection.Nu_DB  # [-] Nusselt number for liquid phase
        # Set remaining inputs
        T_wall = 500  # [K] Wall temperature\

        #Geometry
        w_h = 100e-6  # [m] Width and height
        A_channel = w_h**2  # [m^2]
        wetted_perimeter = 4 * w_h  # [m]
        D_hydr = 4 * A_channel / wetted_perimeter  # [m]

        self.res = oneD.calc_channel_single_phase(\
            T = self.prep['T'],
            Q_dot= self.prep['Q_dot'],
            rho = self.prep['rho'],
            Pr = self.prep['Pr'],
            kappa = self.prep['kappa'],
            mu = self.prep['mu'],
            p_ref=p_inlet,
            m_dot=m_dot,
            T_wall=T_wall,
            D_hydr=D_hydr,
            wetted_perimeter=wetted_perimeter,
            A_channel=A_channel,
            Nu_func=Nu_func_liquid,
            fp=fp
            )
        return super().setUp()
Example #24
0
def calc_P_delta_h(T_in,T_out,m_dot,p_chamber):
    """Calculate power required to raise temperature of flow with mass flow m_dot
    
    Arguments:
        T_in {K} -- Inlet temperature
        T_out {K} -- Outlet temperature
        m_dot {kg/s} -- Mass flow
        p_chamber {Pa} -- Chamber pressure
    
    Returns:
        {W} - Required power
    """
    # Check if outlet state is gaseous

    fp = FluidProperties("water")

    outlet_phase = fp.get_phase(T=T_out,p=p_chamber)
    if not (outlet_phase == "gas" or outlet_phase == "supercritical_gas"):
        print(fp.get_phase(T=T_out,p=p_chamber))
        raise ValueError("Assumed outlet temperature is not not in gas phase")
    
    Delta_h = fp.get_enthalpy(T=T_out, p=p_chamber) - fp.get_enthalpy(T=T_in, p=p_chamber)

    return m_dot*Delta_h
Example #25
0
def two_phase_single_channel(T_wall,
                             w_channel,
                             Nu_func_gas,
                             Nu_func_liquid,
                             T_inlet,
                             T_chamber,
                             p_ref,
                             m_dot,
                             h_channel,
                             fp: FluidProperties,
                             print_info=True):
    """ Function that calculates the total power consumption of a specific chamber, in order to optimize the chamber

    Args:
        T_wall (K): Wall temperature
        w_channel (m): Channel width
        Nu_func_gas (-): Nusselt function for gas phase
        Nu_func_liquid (-) Nusselt function for liquid phase
        T_inlet (K): Chamber inlet temperature
        T_chamber (K): Chamber outlet temperature (same as T_c in IRT)
        p_ref (Pa): Reference pressure for the Nusselt relation and flow similary parameters (same as inlet pressure as no pressure drop is assumed)
        m_dot (kg/s): Mass flow
        h_channel (m): Channel height
        w_channel_margin (m): The amount of margin around the chamber for structural reasons. Important because it also radiates heat
        fp (-  ): [description]
        print_info(Bool): for debugging purposes
    """

    # Calculate saturation temperature, to determine where transition from gas to liquid occurs
    T_sat = fp.get_saturation_temperature(p=p_ref)  # [K]
    # Sanity check on input
    assert (T_chamber > T_sat)
    assert (T_wall > T_chamber)

    # Calculate the two reference temperatures for the separated phases
    T_bulk_gas = (T_sat + T_chamber) / 2  # [K] Bulk temperature gas phase
    T_bulk_liquid_multi = (
        T_inlet +
        T_sat) / 2  # [K] Bulk temperature of liquid and multi-phase flow
    # Calculate the density at these reference points
    rho_bulk_gas = fp.get_density(T=T_bulk_gas, p=p_ref)  # [kg/m^3]
    rho_bulk_liquid_multi = fp.get_density(T=T_bulk_liquid_multi,
                                           p=p_ref)  # [kg/m^3]

    # Channel geometry
    A_channel = w_channel * h_channel  # [m^2] Area through which the fluid flows
    wetted_perimeter = wetted_perimeter_rectangular(
        w_channel=w_channel, h_channel=h_channel
    )  # [m] Distance of channel cross-section in contact with fluid
    D_hydraulic = hydraulic_diameter_rectangular(
        w_channel=w_channel, h_channel=h_channel)  # [m] Hydraulic diameter

    # Flow similarity parameters (for debugging and Nu calculatoin purposes)
    Re_bulk_gas = fp.get_Reynolds_from_mass_flow(
        m_dot=m_dot, p=p_ref, T=T_bulk_gas, L_ref=D_hydraulic,
        A=A_channel)  # [-] Bulk Reynolds number in the gas phase
    Re_bulk_liquid_multi = fp.get_Reynolds_from_mass_flow(
        m_dot=m_dot,
        p=p_ref,
        T=T_bulk_liquid_multi,
        L_ref=D_hydraulic,
        A=A_channel)  # [-] Bulk Reynolds number in the liquid/multi-phase
    Pr_bulk_gas = fp.get_Prandtl(
        T=T_bulk_gas, p=p_ref)  # [-] Prandtl number in the gas phase
    Pr_bulk_liquid_multi = fp.get_Prandtl(
        T=T_bulk_liquid_multi,
        p=p_ref)  # [-] Prandtl number in liquid/multi-phase
    Bo_sat = fp.get_Bond_number(
        p_sat=p_ref, L_ref=D_hydraulic
    )  # [-] Bond number at saturation pressure (assumed to be p_ref)

    # Calculate Nusselt number in both sections
    args_gas = {
        'Re': Re_bulk_gas,  # Arguments for Nusselt function (gas phase) 
        'Pr': Pr_bulk_gas,
        'Bo': Bo_sat,
    }

    args_liquid_multi = { # Arguments for Nusselt function (liquid/multi phase)
        'Re': Re_bulk_liquid_multi,
        'Pr': Pr_bulk_liquid_multi,
        'Bo': Bo_sat,
        }

    Nu_gas = Nu_func_gas(args=args_gas)
    Nu_liquid_multi = Nu_func_liquid(args=args_liquid_multi)
    # Calculate Stanton number in both sections
    St_gas = Stanton_from_Nusselt_and_velocity(
        Nu=Nu_gas,
        T_ref=T_bulk_gas,
        p_ref=p_ref,
        L_ref=D_hydraulic,
        m_dot=m_dot,
        A=A_channel,
        fp=fp)  # [-] Stanton number in gas phase
    St_liquid_multi = Stanton_from_Nusselt_and_velocity(
        Nu_liquid_multi,
        T_ref=T_bulk_liquid_multi,
        p_ref=p_ref,
        L_ref=D_hydraulic,
        m_dot=m_dot,
        A=A_channel,
        fp=fp)  # [-] Stanton number in liquid phase
    # Calculate velocity for convection parameter (bulk temp used as reference for phase)
    u_bulk_gas = velocity_from_mass_flow(
        A=A_channel, m_dot=m_dot,
        rho=rho_bulk_gas)  # [m/s] Velocity at the gas bulk reference state
    u_bulk_liquid_multi = velocity_from_mass_flow(
        A=A_channel, m_dot=m_dot, rho=rho_bulk_liquid_multi
    )  # [m/s] Velocity at the liquid/multi-phase bulk reference state
    # Convective parameter
    h_conv_gas = h_conv_from_Stanton(
        Stanton=St_gas, u=u_bulk_gas, T_ref=T_bulk_gas, p_ref=p_ref, fp=fp
    )  # [W/(m^2*K)] Convective heat transfer coefficient at bulk gas state
    h_conv_liquid_multi = h_conv_from_Stanton(
        Stanton=St_liquid_multi,
        u=u_bulk_liquid_multi,
        T_ref=T_bulk_liquid_multi,
        p_ref=p_ref,
        fp=fp
    )  # [W/(m^2*K)] Convective heat transfer coefficient at bulk liquid/multi-phase state
    # Required specific enthalpy change for heating the separate sections
    h_outlet = fp.get_enthalpy(
        T=T_chamber, p=p_ref)  # [J/kg] Specific enthalpy at the outlet
    h_sat_gas = fp.get_saturation_enthalpy_gas(
        p=p_ref)  # [J/kg] Specific enthalpy of saturated gas
    h_inlet = fp.get_enthalpy(T=T_inlet, p=p_ref)  # [J/kg]
    # Required specific enthalpy increases
    delta_h_gas = h_outlet - h_sat_gas  # [J/kg] Enthalpy increase needed to go from saturated gas to outlet enthalpy
    delta_h_liquid_multi = h_sat_gas - h_inlet  # [J/k] Enthalpy increase needed to go from inlet enthalpy to saturated gas
    # Required power for those enthalpy changes at the given mass flow
    Q_dot_gas = required_power(m_dot=m_dot, delta_h=delta_h_gas)  # [W]
    Q_dot_liquid_multi = required_power(m_dot=m_dot,
                                        delta_h=delta_h_liquid_multi)  # [W]
    # Required heater area to achieve the required power
    A_heater_gas = required_heater_area(Q_dot=Q_dot_gas,
                                        h_conv=h_conv_gas,
                                        T_wall=T_wall,
                                        T_ref=T_bulk_gas)  # [m^2]
    A_heater_liquid_multi = required_heater_area(
        Q_dot=Q_dot_liquid_multi,
        h_conv=h_conv_liquid_multi,
        T_wall=T_wall,
        T_ref=T_bulk_liquid_multi)  # [m^2]
    # Required length to achieve desired area
    L_channel_gas = A_heater_gas / wetted_perimeter  # [m] Length of channel after gas is saturated
    L_channel_liquid_multi = A_heater_liquid_multi / wetted_perimeter  # [m] Length of channel after heater
    L_channel = L_channel_gas + L_channel_liquid_multi  # [m]
    L_hydrodynamic_entrance = D_hydraulic * Re_bulk_liquid_multi * 0.04  # [m] Hydrodynamic entrance to estimate if the flow is fully developed

    assert (h_outlet > h_sat_gas)
    assert (h_sat_gas > h_inlet)

    if (print_info):
        print("\n--- SPECIFIC ENTHALPY AT DIFFERENT STATIONS ---")
        print("h_outlet: {:4.3f} J/kg".format(h_outlet))
        print("h_sat_gas: {:4.3f} J/kg".format(h_sat_gas))
        print("h_inlet: {:4.3f} J/kg".format(h_inlet))

        print("\n --- REQUIRED POWER ---")
        print("Q_dot_gas: {:2.5f} W".format(Q_dot_gas))
        print("Q_dot_liquid_multi: {:2.5f} W".format(Q_dot_liquid_multi))

        print("\n --- BULK GAS PHASE PARAMETERS --- ")
        print("u: {:3.2f} m/s".format(u_bulk_gas))
        print("Nu: {}".format(Nu_gas))
        print("Re: {}".format(Re_bulk_gas))
        print("Pr: {}".format(Pr_bulk_gas))
        print("St: {}".format(St_gas))
        print("Bo_sat: {}".format(Bo_sat))

        print("\n --- BULK LIQUID/MULTI-PHASE PARAMETERS ---")
        print("u: {:3.4f} m/s".format(u_bulk_liquid_multi))
        print("Nu: {}".format(Nu_liquid_multi))
        print("Re: {}".format(Re_bulk_liquid_multi))
        print("Pr: {}".format(Pr_bulk_liquid_multi))
        print("St: {}".format(St_liquid_multi))

        print("\n --- CHARACTERISTIC GEOMETRIC VALUES --- ")
        print("Hydrodynamic entance length: {:3.3f} micron".format(
            L_hydrodynamic_entrance * 1e6))
        print("Hydraulic diameter: {:3.3f} micron".format(D_hydraulic * 1e6))
        print("L/D: {:4.2f} ".format(L_channel / D_hydraulic))
        print("L/X_T {:4.2f}".format(L_channel / L_hydrodynamic_entrance))

        print("\n --- RESULTING GEOMETRY ---")
        print("Total length: {:3.3f} mm".format(L_channel * 1e3))
        print("Length (liquid/multi): {:3.3f} mm".format(
            L_channel_liquid_multi * 1e3))
        print("Length (gas): {:3.4f} mm".format(L_channel_gas * 1e3))
        print("Relative length (gas) {:3.3f} \%".format(L_channel_gas /
                                                        L_channel * 100))

        ## Return a dictionary with results and interesting intermediate values
    res = {
        "L_channel": L_channel,  # [m] Total length of channel
        "D_hydraulic": D_hydraulic,  # [m] Hydraulic diameter of channel
        "Nu_liquid_multi":
        Nu_liquid_multi,  # [-] Nusselt number of liquid/multi-phase flow
        "Pr_bulk_liquid_multi":
        Pr_bulk_liquid_multi,  # [-] Prandlt number of liquid/multi-phase flow
        "Re_bulk_liquid_multi":
        Re_bulk_liquid_multi,  # [-] Reynolds number of liquid/multi-phase flow
        "St_liquid_multi":
        St_liquid_multi,  # [-] Stanton number of liquid/multi-phase flow
        "h_conv_liquid_multi":
        h_conv_liquid_multi,  # [W/(m^2*K)] Heat transfer coefficient
        "A_heater_liquid_multi":
        A_heater_liquid_multi,  # [m^2] Required heater area for liquid/multi-phase flow
        "L_channel_liquid_multi":
        L_channel_liquid_multi,  # [m] Length of channel to get required heater area
        "u_bulk_liquid_multi":
        u_bulk_liquid_multi,  # [m/s] Bulk flow velocity of liquid/multi-phase flow
        "rho_bulk_liquid_multi":
        rho_bulk_liquid_multi,  # [kg/m^3] Bulk density of liquid/multi-phase flow
        "T_bulk_liquid_multi":
        T_bulk_liquid_multi,  # [K] Bulk temperature of liquid/multi-phase flow
        "delta_h_liquid_multi":
        delta_h_liquid_multi,  # [J/kg] Enthalpy change from inlet to saturated gas
        "Q_dot_liquid_multi":
        Q_dot_liquid_multi,  # [W] Power required for enthalpy change
        ## Same thing but for gas values
        "Nu_gas": Nu_gas,  # [-]
        "Pr_bulk_gas": Pr_bulk_gas,  # [-]
        "Re_bulk_gas": Re_bulk_gas,  # [-]
        "St_gas": St_gas,  # [-]
        "h_conv_gas": h_conv_gas,  # [W/(m^2*K)]
        "A_heater_gas": A_heater_gas,  # [m^2]
        "L_channel_gas": L_channel_gas,  # [m]
        "u_bulk_gas": u_bulk_gas,  # [m/s]
        "rho_bulk_gas": rho_bulk_gas,  # [kg/m^3]
        "T_bulk_gas": T_bulk_gas,  # [K]
        "delta_h_gas": delta_h_gas,  # [J/kg]
        "Q_dot_gas": Q_dot_gas,  # [W]
    }
    return res
Example #26
0
def chamber_performance_from_Nu(Nu_func, T_inlet, T_chamber, T_ref, T_wall,
                                p_ref, m_dot, A_channel, L_ref,
                                fp: FluidProperties):
    """ Function that calculates the power consumption and heating area for a specific chamber

    Args:
        Nu_func (-): Nusselt function, that implement the emperical relation of choice
        T_inlet (K): Chamber inlet temperature
        T_chamber (K): Chamber outlet temperature (same as T_chamber for IRT)
        T_ref (K): Reference temperature for the Nusselt relation and flow similary parameters
        T_wall (K): Wall temperature
        p_ref (Pa): Chamber pressure (no pressure drop assumed)
        m_dot (kg/s): Mass flow
        A_channel (m^2): Cross-sectional area of the chamber, through which the fluid flows
        L_ref (m): Reference length for Nusselt relation and flow similarty parameters
        fp (FluidProperties): Object from which Fluid Properties are determined

    Returns:
        dictionary with heater area, power required to heat up flow and Nusselt number
    """
    ## Make sure all parameters are calculated at the same reference state (including velocity!)
    # Pr and Re parameters needed for most Nusselt relation
    rho_ref = fp.get_density(T=T_ref, p=p_ref)  # [kg/m^3] Reference density
    u_ref = velocity_from_mass_flow(
        A=A_channel, m_dot=m_dot,
        rho=rho_ref)  # [m/s] Speed at reference state
    print("u_ref {} m/s".format(u_ref))
    Re_ref = fp.get_Reynolds_from_mass_flow(
        T=T_ref, p=p_ref, L_ref=L_ref, m_dot=m_dot,
        A=A_channel)  # [-] Reynolds number at reference state
    Pr_ref = fp.get_Prandtl(T=T_ref,
                            p=p_ref)  # [-] Prandtl number at reference state
    # Now the Nusselt can be determined
    Nusselt = Nu_func(args={
        'Re': Re_ref,
        'Pr': Pr_ref
    })  # [-] Nusselt number at given state (used for plotting purposes)
    Stanton = Stanton_from_Nusselt_func_and_velocity(
        Nu_func=Nu_func,
        m_dot=m_dot,
        A=A_channel,
        T_ref=T_ref,
        p_ref=p_ref,
        L_ref=L_ref,
        fp=fp)  # [-] Stanton number at reference state
    h_conv = h_conv_from_Stanton(Stanton=Stanton,
                                 u=u_ref,
                                 T_ref=T_ref,
                                 p_ref=p_ref,
                                 fp=fp)
    # Now determine how much energy must be convected
    delta_h = ideal_enthalpy_change(T_inlet=T_inlet,
                                    p_inlet=p_ref,
                                    T_outlet=T_chamber,
                                    p_outlet=p_ref,
                                    fp=fp)  # [J/kg]
    Q_dot = required_power(
        m_dot=m_dot, delta_h=delta_h)  # [W] Required power to achieve delta_h
    A_heater = required_heater_area(Q_dot=Q_dot,
                                    h_conv=h_conv,
                                    T_wall=T_wall,
                                    T_ref=T_ref)  # [m^2]
    assert (A_heater > 0)
    # Return a dictionary with interesting values
    return {
        'A_heater': A_heater,
        'Q_dot': Q_dot,
        'Nusselt': Nusselt,
        'Re_ref': Re_ref,
        'Pr_ref': Pr_ref
    }
Example #27
0
import math
from thermo.prop import FluidProperties
import thermo.convection
import thermo.two_phase as tp
from thermo.prop import FluidProperties
import models.one_D as oneD

#####################################################################################
###                        1D RECTANGULAR MULTICHANNEL 4mN                         ##
#####################################################################################
settings_1D_rectangular_multichannel = {}
## Fixed design parameters
settings_1D_rectangular_multichannel['FDP'] = {
    'fp': FluidProperties(
        'water'
    ),  # (object) Interface with Coolprop that returns all necessary properties of water
    'p_inlet': 5e5,  # [Pa] Pressure at inlet
    'p_back':
    0,  # [Pa] NOTE: back pressure MUST be vacuum/zero for nozzle adjustment to work correctly
    'T_inlet': 300,  # [K] Heating chamber inlet temperature
    'h_channel': 100e-6,  # [m] Channel depth/height
    'AR_exit': 10,  # [-] Exit area ratio of nozzles
    'inlet_manifold_length_factor':
    2,  # [m] Multiplication factor with inlet manifold width to determine manifold length
    'inlet_manifold_width_factor':
    5.5,  # [-] Multiplication factor (with channel width to determine margin in chamber)
    'l_exit_manifold':
    0,  # [m] Length between the end of multiple channels and start of convergent nozzle
    'convergent_half_angle':
    math.radians(45),  # [rad] Half-angle of the convergent part of the nozzle
Example #28
0
## File to show Nusselt number predicted by Kandlikar

import numpy as np
import matplotlib.pyplot as plt

from thermo.two_phase import Nu_Kandlikar_NBD_dryout, Nu_Kandlikar_NBD_CBD_dryout
from thermo.prop import FluidProperties
from thermo.convection import Nu_laminar_developed_constant_wall_temp_square, Nu_DB
from basic.chamber import Reynolds_from_mass_flow

fp = FluidProperties("water")

Nu_func_le_laminar = Nu_laminar_developed_constant_wall_temp_square
Nu_func_le_turbulent = Nu_DB
Nu_func_tp = Nu_Kandlikar_NBD_CBD_dryout

# Design parameters
p = 5e5  # Pressure through channel [Pa]
m_dot = 200e-6  # [kg/s]
A_channel = 1e-6  # [m^2] Channel cross sections
D_h = 1e-6 * np.array((100, 200, 500))  # [m] Hydraulic diameters

# Mass flux calculated for reference
G = m_dot / A_channel  # [kg/(m^2*s)] Mass flux
print("Mass flux: {:3.1f} kg/(m^2*s)".format(G))

# Saturatoin conditions
rho_l = fp.get_liquid_density_at_psat(
    p_sat=p)  # [kg/m^3] Liquid density at saturation point
rho_g = fp.get_vapour_density_at_psat(
    p_sat=p)  # [kg/m^3] Vapour density at saturation point
Example #29
0
def Rajeev_complete(p_chamber, T_chamber, w_throat, h_throat, throat_roc,
                    AR_exit, p_back, divergence_half_angle,
                    fp: FluidProperties, is_cold_flow):
    """ Function that implements all corrections proposed by Makhan2018

    Args:
        p_chamber (Pa): Chamber pressure
        T_chamber (K): Chamber temperature
        w_throat (m): Throat width
        h_throat (m): Throat heigh (or channel depth)
        throat_roc (m): Throat radius of curvature
        AR_exit (-): Area ratio of nozzle exit area divided by throat area
        p_back (Pa): Back pressure
        divergence_half_angle (rad): Divergence half angle of nozzle 
        fp (FluidProperties): Object to access fluid properties
        is_cold_flow (bool): Reynolds number is adjusted depending on whether the chamber is heated or cooled

    Raises:
        ValueError: Is raised for hot flow, since no verification is done yet on that equation
    """

    # Get the (assumed to be) constant fluid properties
    gamma = fp.get_specific_heat_ratio(T=T_chamber,
                                       p=p_chamber)  # [-] Specific heat ratio
    R = fp.get_specific_gas_constant()  # [J/kg] Specific gas constant
    # Report calculated values for verification and comparison purposes
    print("Gamma: {:1.4f}".format(gamma))
    print("R: {:3.2f} J/kg\n".format(R))

    # Calculate basic peformance parameters
    A_throat = w_throat * h_throat  # [m] Throat area

    ## IDEAL PERFORMANCE
    # First get ideal performance, and check if the nozzle is properly expanded.
    ep = IRT.get_engine_performance(p_chamber=p_chamber,
                                    T_chamber=T_chamber,
                                    A_throat=A_throat,
                                    AR_exit=AR_exit,
                                    p_back=p_back,
                                    gamma=gamma,
                                    R=R)

    # Report ideal performance
    print("Thrust: {:.2f} mN".format(ep['thrust'] * 1e3))
    print("Isp_ideal: {:.1f} s".format(ep['thrust'] / ep['m_dot'] / 9.80655))
    print("Mass flow: {:.3f} mg/s".format(ep['m_dot'] * 1e6))

    m_dot_ideal = ep['m_dot']  # [kg/s] Ideal mass flow
    #F_ideal = ep['thrust'] # [N] Ideal thrust

    ## CALCULATING THE CORRECTION FACTORS

    # Calculate the divergence loss and report it
    CF_divergence_loss = divergence_loss_conical_2D(
        alpha=divergence_half_angle)
    print("\n -- DIVERGENCE LOSS for {:2.2f} deg divergence half-angle".format(
        math.degrees(divergence_half_angle)))
    print(
        "  Divergence loss (2D concical): {:.5f} ".format(CF_divergence_loss))

    # Calculate the viscous loss

    # To determine the Reynolds number at the throat, the hydraulic diameter at the throat and nozzle conditions must be determined
    # Get hydraulic diameter of the nozzle from the wetted perimeter and nozzle area
    wetted_perimeter_throat = 2 * (w_throat + h_throat
                                   )  # [m] Wetted perimeter throat
    Dh_throat = hydraulic_diameter(A=A_throat,
                                   wetted_perimeter=wetted_perimeter_throat
                                   )  # [m] Hydraulic diameter at throat
    p_throat = p_chamber / IRT.pressure_ratio(
        M=1, gamma=gamma)  # [Pa] pressure in throat
    T_throat = T_chamber / IRT.temperature_ratio(
        M=1, gamma=gamma)  # [K] Temperature in throat
    viscosity_throat = fp.get_viscosity(T=T_throat, p=p_throat)
    # Throat reynolds based on ideal mass flow?
    Re_throat = reynolds(m_dot=m_dot_ideal,
                         A=A_throat,
                         D_hydraulic=Dh_throat,
                         viscosity=viscosity_throat)
    if is_cold_flow:
        Re_throat_wall = Reynolds_throat_wall_cold(reynolds_throat=Re_throat)
    else:
        Re_throat_wall = Reynolds_throat_wall_hot(reynolds_throat=Re_throat)
    print("\n-- THROAT CONDITIONS --")
    print("  p = {:2.4f} bar,     T = {:4.2f} K".format(
        p_throat * 1e-5, T_throat))
    print("  mu = {:2.4f} [microPa*s]  Dh = {:3.4f} [microm]".format(
        viscosity_throat * 1e6, Dh_throat * 1e6))
    print(" Reynolds: {:6.6f} ".format(Re_throat))

    CF_viscous_loss = viscous_loss(area_ratio=AR_exit,
                                   reynolds_throat_wall=Re_throat_wall)
    print(" CF_viscous_loss: {:1.5f}".format(CF_viscous_loss))

    # Calculating throat boundary layer loss, which causes a reduction in effective throat area/mass flow
    Cd_throat_boundary_loss = throat_boundary_loss(gamma=gamma,
                                                   reynolds_throat=Re_throat,
                                                   throat_radius=0.5 *
                                                   Dh_throat,
                                                   throat_roc=throat_roc)
    print("\n-- DISCHARGE FACTOR --")
    print("  Throat boundary layer: {:1.4f}".format(Cd_throat_boundary_loss))

    ## APPLYING THE CORRECTION FACTORS
    # Now all these loss factors must be combined into a new "real" thrust
    # The divergence loss only applies to the jet/momentum thrust and not the pressure, so jet thrust is needed
    # This is equal to the exit velocity times corrected mass flow. The returned exit velocity does not include pressure terms!

    # First we must know the corrected mass flow
    m_dot_real = ep['m_dot'] * Cd_throat_boundary_loss  # [kg/s]
    # Secondly, we must know the pressure thrust to add to the jet thrust again
    F_pressure = IRT.pressure_thrust(p_chamber=p_chamber,
                                     p_back=p_back,
                                     A_throat=A_throat,
                                     AR=AR_exit,
                                     gamma=gamma)
    F_divergence = m_dot_real * ep[
        'u_exit'] * CF_divergence_loss + F_pressure  # [N] Thrust decreased by divergence loss, pressure term must be added again, since divergence only applies to jet thrust
    # This jet thrust is then again corrected by viscous losses, which are subtracted from the current CF
    CF_jet_divergence = F_divergence / (
        p_chamber * A_throat
    )  # [-] Thrust coefficient after taking into account discharge factor and divergence loss
    CF_real_final = CF_jet_divergence - CF_viscous_loss  # [-] The final thrust coefficient, also taking into account viscous loss
    F_real = CF_real_final * p_chamber * A_throat  # [N] Real thrust, after taking into account of all the three proposed correction factors

    # Report "real" results
    print("\n === CORRECTED PERFORMANCE PARAMETERS === ")
    print("  Real mass flow: {:3.4f} mg/s".format(m_dot_real * 1e6))
    print("  CF with divergence loss {:1.5f}".format(CF_jet_divergence))
    print("  Real CF: {:1.5f}".format(CF_real_final))
    print("  Real thrust: {:2.4f} mN".format(F_real * 1e3))
    print("  Real Isp: {:3.2f}".format(F_real / m_dot_real / 9.80655))

    return {
        'm_dot_real': m_dot_real,
        'm_dot_ideal': ep['m_dot'],
        'F_real': CF_real_final
    }
Example #30
0
def printBasicStuff():
    fp = FluidProperties("water")
    print("R: {:3.2f} J/(kg*K)".format(fp.get_specific_gas_constant()))