Example #1
0
    def M(self,
          p_p0=None,
          rho_rho0=None,
          T_T0=None,
          A_Astar=None,
          *args,
          **kwargs):
        """
        Computes Mach number when one of the arguments are specified

        """
        g = self.gamma
        if p_p0 is not None:
            M = np.sqrt(2. * ((1. / np.power(p_p0,
                                             (g - 1.) / g)) - 1.) / (g - 1.))
        elif rho_rho0 is not None:
            M = np.sqrt(2. * ((1. / np.power(rho_rho0,
                                             (g - 1.))) - 1.) / (g - 1.))
        elif T_T0 is not None:
            M = np.sqrt(2. * ((1. / T_T0) - 1.) / (g - 1.))
        elif A_Astar is not None:
            Msub, Msup = mach_from_area_ratio(A_Astar)
            M = np.array([Msub, Msup])
        elif 'M' in kwargs.keys():
            return kwargs['M']
        else:
            logger.error('Insufficient data to calculate Mach number')

        return M
def test_mach_from_area_ratio_supersonic():
    fl = isentropic.IsentropicFlow(1.4)
    A_Astar_list = [1.0, 1.043, 1.328, 1.902, 4.441]
    expected_ratios = [1.0, 1.24, 1.69, 2.14, 3.05]
    mach_from_area_ratios = [
        isentropic.mach_from_area_ratio(A_Astar, fl)[1]  # Supersonic
        for A_Astar in A_Astar_list
    ]

    np.testing.assert_array_almost_equal(mach_from_area_ratios,
                                         expected_ratios,
                                         decimal=2)
def test_mach_from_area_ratio_subsonic():
    fl = isentropic.IsentropicFlow(1.4)
    A_Astar_list = [
        np.inf,
        2.4027,
        1.7780,
        1.0382,
        1.0,
    ]
    expected_ratios = [0.0, 0.25, 0.35, 0.8, 1.0]
    mach_from_area_ratios = [
        isentropic.mach_from_area_ratio(A_Astar, fl)[0]  # Subsonic
        for A_Astar in A_Astar_list
    ]
    np.testing.assert_array_almost_equal(mach_from_area_ratios,
                                         expected_ratios,
                                         decimal=3)
Example #4
0
    def M(self, p_p0=None, rho_rho0=None,
          T_T0=None, A_Astar=None, *args, **kwargs):
        """
        Computes Mach number when one of the arguments are specified

        """
        g = self.gamma
        if p_p0 is not None:
            M = np.sqrt(2. * ((1./np.power(p_p0, (g-1.)/g)) - 1.) / (g-1.))
        elif rho_rho0 is not None:
            M = np.sqrt(2. * ((1./np.power(rho_rho0, (g-1.))) - 1.) / (g-1.))
        elif T_T0 is not None:
            M = np.sqrt(2. * ((1./T_T0)-1.)/(g-1.))
        elif A_Astar is not None:
            Msub, Msup = mach_from_area_ratio(A_Astar)
            M = np.array([Msub, Msup])
        elif 'M' in kwargs.keys():
            return kwargs['M']
        else:
            logger.error('Insufficient data to calculate Mach number')

        return M
Example #5
0
def test_mach_from_area_ratio_subsonic():
    fl = isentropic.IsentropicFlow(1.4)
    A_Astar_list = [
        np.inf,
        2.4027,
        1.7780,
        1.0382,
        1.0,
    ]
    expected_ratios = [
        0.0,
        0.25,
        0.35,
        0.8,
        1.0
    ]
    mach_from_area_ratios = [
        isentropic.mach_from_area_ratio(A_Astar, fl)[0]  # Subsonic
        for A_Astar in A_Astar_list]
    np.testing.assert_array_almost_equal(
        mach_from_area_ratios, expected_ratios, decimal=3
    )
Example #6
0
def test_mach_from_area_ratio_supersonic():
    fl = isentropic.IsentropicFlow(1.4)
    A_Astar_list = [
        1.0,
        1.043,
        1.328,
        1.902,
        4.441
    ]
    expected_ratios = [
        1.0,
        1.24,
        1.69,
        2.14,
        3.05
    ]
    mach_from_area_ratios = [
        isentropic.mach_from_area_ratio(A_Astar, fl)[1]  # Supersonic
        for A_Astar in A_Astar_list]

    np.testing.assert_array_almost_equal(
        mach_from_area_ratios, expected_ratios, decimal=2
    )
Example #7
0
    def solve_flow(self, fl, p_0, T_0, p_B):
        """Solves the flow through the nozzle.

        For the time being, it assumes isentropic flow and uses a quasi one
        dimensional model.

        Parameters
        ----------
        fl : IsentropicFlow
            Isentropic flow through the nozzle.
        p_0 : float
            Stagnation pressure at the reservoir.
        T_0 : float
            Stagnation temperature at the reservoir.
        p_B : float
            Back pressure at the exit section.

        Returns
        -------
        M : array
            Mach distribution along the nozzle.
        p : array
            Pressure distribution along the nozzle.

        Raises
        ------
        ValueError
            If the back pressure is higher than the reservoir pressure.

        Notes
        -----
        First of all, the function computes the isentropic conditions to
        discriminate if we have fully subsonic flow, chocked flow with shock
        inside nozzle or chocked fully supersonic flow.

        """
        p_ratio = p_B / p_0
        if p_ratio > 1.0:
            raise ValueError(
                "Back pressure must be lower than reservoir pressure")

        # Exit and minimum area
        A_e = self.A[-1]
        A_min = np.min(self.A)
        i_min = np.argmin(self.A)

        # 1. Compute isentropic conditions at the exit
        # Points 1 (subsonic) and 2 (supersonic)
        M_e_1, M_e_2 = isentropic.mach_from_area_ratio(fl, A_e / A_min)

        pe_p0_1 = fl.p_p0(M_e_1)
        pe_p0_2 = fl.p_p0(M_e_2)

        # 2. Normal shock at the exit of the nozzle
        ns_e = shocks.NormalShock(M_e_2)
        pe_p0_3 = pe_p0_2 * ns_e.p2_p1

        # 3. Discriminate case
        M = np.empty_like(self.x)
        p = np.empty_like(self.x)

        if pe_p0_1 <= p_ratio <= 1.0:
            print("Fully subsonic flow")
            # 1. Compute M_e (inverse fl.p_p0(M))
            # 2. Compute area ratio from M_e (fl.A_Ac(M_e))
            # 3. The area ratio in each point is A_Ac = A * Ae_Ac / Ae
            #    so I can compute the Mach number distribution
        elif pe_p0_3 <= p_ratio < pe_p0_1:
            print("Shock inside the nozzle")
            # First I have to compute shock location and properties
        elif p_ratio < pe_p0_3:
            print("Fully isentropic subsonic-supersonic flow")
            # I already have Ac = A_min, so I can directly compute the Mach
            # number distribution
            Ac = A_min
            for i in range(i_min + 1):
                M[i] = isentropic.mach_from_area_ratio(fl, self.A[i] / Ac)[0]
            for i in range(i_min, len(M)):
                M[i] = isentropic.mach_from_area_ratio(fl, self.A[i] / Ac)[1]
            # Stagnation pressure does not change, as the flow is fully
            # isentropic
            p = p_0 * fl.p_p0(M)

        return M, p
def test_mach_from_area_ratio_raises_error_when_ratio_is_subsonic():
    with pytest.raises(ValueError):
        isentropic.mach_from_area_ratio(0.9)
Example #9
0
def test_mach_from_area_ratio_raises_error_when_ratio_is_subsonic():
    with pytest.raises(ValueError):
        isentropic.mach_from_area_ratio(0.9)
Example #10
0
    def solve_flow(self, fl, p_0, T_0, p_B):
        """Solves the flow through the nozzle.

        For the time being, it assumes isentropic flow and uses a quasi one
        dimensional model.

        Parameters
        ----------
        fl : IsentropicFlow
            Isentropic flow through the nozzle.
        p_0 : float
            Stagnation pressure at the reservoir.
        T_0 : float
            Stagnation temperature at the reservoir.
        p_B : float
            Back pressure at the exit section.

        Returns
        -------
        M : array
            Mach distribution along the nozzle.
        p : array
            Pressure distribution along the nozzle.

        Raises
        ------
        ValueError
            If the back pressure is higher than the reservoir pressure.

        Notes
        -----
        First of all, the function computes the isentropic conditions to
        discriminate if we have fully subsonic flow, chocked flow with shock
        inside nozzle or chocked fully supersonic flow.

        """
        p_ratio = p_B / p_0
        if p_ratio > 1.0:
            raise ValueError(
                "Back pressure must be lower than reservoir pressure")

        # Exit and minimum area
        A_e = self.A[-1]
        A_min = np.min(self.A)
        i_min = np.argmin(self.A)

        # 1. Compute isentropic conditions at the exit
        # Points 1 (subsonic) and 2 (supersonic)
        M_e_1, M_e_2 = isentropic.mach_from_area_ratio(fl, A_e / A_min)

        pe_p0_1 = fl.p_p0(M_e_1)
        pe_p0_2 = fl.p_p0(M_e_2)

        # 2. Normal shock at the exit of the nozzle
        ns_e = shocks.NormalShock(M_e_2)
        pe_p0_3 = pe_p0_2 * ns_e.p2_p1

        # 3. Discriminate case
        M = np.empty_like(self.x)
        p = np.empty_like(self.x)

        if pe_p0_1 <= p_ratio <= 1.0:
            print("Fully subsonic flow")
            # 1. Compute M_e (inverse fl.p_p0(M))
            # 2. Compute area ratio from M_e (fl.A_Ac(M_e))
            # 3. The area ratio in each point is A_Ac = A * Ae_Ac / Ae
            #    so I can compute the Mach number distribution
        elif pe_p0_3 <= p_ratio < pe_p0_1:
            print("Shock inside the nozzle")
            # First I have to compute shock location and properties
        elif p_ratio < pe_p0_3:
            print("Fully isentropic subsonic-supersonic flow")
            # I already have Ac = A_min, so I can directly compute the Mach
            # number distribution
            Ac = A_min
            for i in range(i_min + 1):
                M[i] = isentropic.mach_from_area_ratio(fl, self.A[i] / Ac)[0]
            for i in range(i_min, len(M)):
                M[i] = isentropic.mach_from_area_ratio(fl, self.A[i] / Ac)[1]
            # Stagnation pressure does not change, as the flow is fully
            # isentropic
            p = p_0 * fl.p_p0(M)

        return M, p