Ejemplo n.º 1
0
    def func(Asw_At_ratio):
        """
        Args:
            Asw_At_ratio:   Estimate of the critical area ratio between the Shock Wave area and the throat area.
        
        Return:
            The zero function "estimated ratio Pe/P0" - "Pe/P0".
        """
        # Mach number just upstream of the shock wave
        Mup_sw = m_from_critical_area_ratio(Asw_At_ratio, "super", gamma)

        P1_P01_ratio = pressure_ratio(Mup_sw, gamma)
        # pressure ratio across the shock wave
        P2_P1_ratio = shockwave.pressure_ratio(Mup_sw, gamma)
        # Mach number just downstream of the shock wave
        Mdown_sw = shockwave.mach_downstream(Mup_sw, gamma)
        P02_P2_ratio = 1 / pressure_ratio(Mdown_sw)

        # critical area ratio just downstream of the shock wave
        Asw_A2s_ratio = critical_area_ratio(Mdown_sw, gamma)
        # critical area ratio at the exit (downstream of the shock wave)
        Ae_A2s_ratio = Ae_At_ratio / Asw_At_ratio * Asw_A2s_ratio
        # Mach number at the exit section
        Me = m_from_critical_area_ratio(Ae_A2s_ratio, "sub", gamma)
        Pe_P02_ratio = pressure_ratio(Me, gamma)
        estimated_Pe_P0_ratio = Pe_P02_ratio * P02_P2_ratio * P2_P1_ratio * P1_P01_ratio

        return estimated_Pe_P0_ratio - Pe_P0_ratio
Ejemplo n.º 2
0
def min_length_supersonic_nozzle_moc(ht, n, Me=None, A_ratio=None, gamma=1.4):
    """
    Compute the contour of the minimum length supersonic nozzle in a planar
    case with the Method of characteristics.

    The method of characteristics provides a technique for properly designing the
    contour of a supersonic nozzle for shockfree, isentropic flow, taking into account the
    multidimensional flow inside the duct.

    Assumptions:
    - Planar case
    - Sharp corner at the throat,
    - M = 1 and theta = 0 at the throat.

    Parameters
    ----------
        ht : float
            Throat height. Must be > 0.
        n : int
            Number of characteristic lines.
        Me : float
            Mach number at the exit section. Default to None. Must be > 1.
            If set to None, A_ratio must be provided. If both are set, 
            Me will be used.
        A_ratio : float
            Ratio between the exit area and the throat area. Since this 
            nozzle is planar, it is equivalent to Re/Rt. It must be > 1.
            Default to None. If set to None, Me must be provided. 
            If both are set, Me will be used.
        gamma : float
            Specific heats ratio. Default to 1.4. Must be > 1.
    
    Returns
    -------
        wall : array_like [2 x n+1]
            Coordinates of points on the nozzle's wall
        characteristics : list
            List of dictionaries. Each dictionary contains the keys "x", "y"
            for the coordinates of the points of each characteristic. Here, with
            characteristic, I mean the points of the right and left running
            characteristic.
        left_runn_chars : list
            List of dictionaries. Each dictionary contains the keys "Km", "Kp",
            "theta", "nu", "M", "mu", "x", "y". Each dictionary represents the
            points lying on the same left-running characteristic.
        theta_w_max : float
            Maximum wall inclination at the sharp corner.
    """
    assert ht > 0, "The throat height must be a number > 0."
    # TODO: is n > 2 correct?
    assert n > 2, "The number of characteristic lines must be an integer > 2."
    assert gamma > 1, "Specific heats ratio must be > 1."

    if Me:
        assert Me > 1, "Exit Mach number must be > 1."
    elif A_ratio:
        assert A_ratio > 1, "Area ratio must be > 1."
        Me = m_from_critical_area_ratio(A_ratio, "super", gamma)
    else:
        raise ValueError("Either Me or A_ratio must be provided.")

    # Prandtl-Meyer function for the designed exit Mach number
    vme = prandtl_meyer_angle(Me, gamma)

    # max angle of the wall downstream of the throat (equation 11.33)
    theta_w_max = vme / 2

    # read carefoully this:
    # http://www.ltas-aea.ulg.ac.be/cms/uploads/Aerothermodynamics05.pdf
    # especially slide 32
    # TODO: is theta_1 small enough for very high n?
    theta_1 = 5e-02
    # theta_1 = theta_w_max - np.floor(theta_w_max)

    delta_theta = (theta_w_max - theta_1) / (n - 1)

    ###
    ### Generate the grid
    ###

    # collection of left running characteristics.
    # each left running characteristic is composed by a certain number of
    # points, resulting from the intersection of this left running characteristic
    # with right running characteristics...
    left_runn_chars = []

    for i in range(n):
        # number of points on the current left-running characteristic
        npt = n + 1 - i
        # init
        left_runn_chars.append({
            "Km": np.zeros(npt),  # right running characteristic K-
            "Kp": np.zeros(npt),  # left running characteristic K+
            "theta": np.zeros(npt),  # deflection angle
            "nu": np.zeros(npt),  # Prandtl-Meyer angle
            "M": np.zeros(npt),  # Mach number
            "mu": np.zeros(npt),  # Mach angle
            "x": np.zeros(npt),  # x coordinate
            "y": np.zeros(npt),  # y coordinate
        })

        for j in range(npt - 1):
            # note that after the first line, theta_1 = 0
            left_runn_chars[i]["theta"][j] = theta_1 + delta_theta * j

            if i == 0:
                left_runn_chars[i]["nu"][j] = left_runn_chars[i]["theta"][j]
                left_runn_chars[i]["Km"][j] = left_runn_chars[i]["theta"][
                    j] + left_runn_chars[i]["nu"][j]
                left_runn_chars[i]["Kp"][j] = left_runn_chars[i]["theta"][
                    j] - left_runn_chars[i]["nu"][j]
            else:
                left_runn_chars[i]["Km"][j] = left_runn_chars[i - 1]["Km"][j +
                                                                           1]
                left_runn_chars[i]["nu"][j] = left_runn_chars[i]["Km"][
                    j] - left_runn_chars[i]["theta"][j]

            left_runn_chars[i]["Kp"][j] = left_runn_chars[i]["theta"][
                j] - left_runn_chars[i]["nu"][j]
            left_runn_chars[i]["M"][j] = m_from_prandtl_meyer_angle(
                left_runn_chars[i]["nu"][j], gamma)
            left_runn_chars[i]["mu"][j] = mach_angle(
                left_runn_chars[i]["M"][j])

        left_runn_chars[i]["theta"][j + 1] = left_runn_chars[i]["theta"][j]
        left_runn_chars[i]["nu"][j + 1] = left_runn_chars[i]["nu"][j]
        left_runn_chars[i]["Km"][j + 1] = left_runn_chars[i]["Km"][j]
        left_runn_chars[i]["Kp"][j + 1] = left_runn_chars[i]["Kp"][j]
        left_runn_chars[i]["M"][j + 1] = left_runn_chars[i]["M"][j]
        left_runn_chars[i]["mu"][j + 1] = left_runn_chars[i]["mu"][j]

        # after first line, we do not need this value anymore
        theta_1 = 0

    ###
    ### Compute nodes coordinates
    ###

    # For readibility purposes, define tangent for angles in degrees
    def tand(angle):
        return np.tan(np.deg2rad(angle))

    for i, l in enumerate(left_runn_chars):
        # number of points in the left running characteristic
        _n = len(l["theta"])
        x = np.zeros(_n)
        y = np.zeros(_n)

        for j in range(_n):
            # the first characteristic is a special case, because at its left
            # there is only the point (0, 1)
            if i == 0:
                # point in the simmetry line
                if j == 0:
                    x[j] = -1 / tand(l["theta"][j] - l["mu"][j])
                    y[j] = 0

                # point at the wall
                elif j == _n - 1:
                    num = y[j - 1] - 1 - x[j - 1] * tand(
                        0.5 * (l["theta"][j - 1] + l["mu"][j - 1] +
                               l["theta"][j] + l["mu"][j]))
                    den = tand(0.5 * (theta_w_max + l["theta"][j])) - tand(
                        0.5 * (l["theta"][j - 1] + l["mu"][j - 1] +
                               l["theta"][j] + l["mu"][j]))
                    x[j] = num / den
                    y[j] = 1 + x[j] * tand(0.5 * (theta_w_max + l["theta"][j]))

                # points in the flow region
                else:
                    num = (
                        1 - y[j - 1] +
                        x[j - 1] * tand(0.5 *
                                        (l["theta"][j - 1] + l["mu"][j - 1] +
                                         l["theta"][j] + l["mu"][j])))
                    den = tand(
                        0.5 *
                        (l["theta"][j - 1] + l["mu"][j - 1] + l["theta"][j] +
                         l["mu"][j])) - tand(l["theta"][j] - l["mu"][j])
                    x[j] = num / den
                    y[j] = tand(l["theta"][j] - l["mu"][j]) * x[j] + 1

            # all other left characteristics
            else:
                # previous left running characteristic line
                lprev = left_runn_chars[i - 1]
                # values of the point in the previous left running characteristic line
                x_prev = lprev["x"][j + 1]
                y_prev = lprev["y"][j + 1]
                theta_prev = lprev["theta"][j + 1]
                mu_prev = lprev["mu"][j + 1]

                # points in the simmetry line
                if j == 0:
                    x[j] = x_prev - y_prev / (tand(
                        0.5 *
                        (l["theta"][j] + theta_prev - l["mu"][j] - mu_prev)))
                    y[j] = 0

                # point at the wall
                elif j == _n - 1:
                    num = x_prev * tand(0.5 * (theta_prev + l["theta"][j])) \
                        - y_prev + l["y"][j-1] - l["x"][j-1] * tand(0.5 * (l["theta"][j] + l["theta"][j-1] + l["mu"][j] + l["mu"][j-1]))

                    den = tand(0.5 * (l["theta"][j] + theta_prev)) \
                        - tand(0.5 * (l["theta"][j-1] + l["theta"][j] + l["mu"][j-1] + l["mu"][j]))

                    x[j] = num / den
                    y[j] = y_prev + (l["x"][j] - x_prev) * tand(
                        0.5 * (theta_prev + l["theta"][j]))

                # points in the flow region
                else:
                    s1 = tand(0.5 * (l["theta"][j] + l["theta"][j - 1] +
                                     l["mu"][j] + l["mu"][j - 1]))
                    s2 = tand(
                        0.5 *
                        (l["theta"][j] + theta_prev - l["mu"][j] - mu_prev))
                    x[j] = (y_prev - l["y"][j - 1] + s1 * l["x"][j - 1] -
                            s2 * x_prev) / (s1 - s2)
                    y[j] = l["y"][j - 1] + (l["x"][j] - l["x"][j - 1]) * s1

            # add the computed coordinates points to the left running characteristic
            left_runn_chars[i]["x"] = x
            left_runn_chars[i]["y"] = y

    for l in left_runn_chars:
        l["x"] *= ht
        l["y"] *= ht

    # each symmetry line point has a left and right-running characteristic.
    # I pack them togheter for visualization purposes.
    characteristics = []
    # extract the wall coordinates
    wall = np.zeros((n + 1, 2))
    # first coordinate is the sharp corner
    wall[0, :] = [0, 1 * ht]

    for i, l in enumerate(left_runn_chars):
        # each characteristic starts from the sharp corner
        x = np.zeros(len(l["x"]) + i + 1)
        y = np.zeros(len(l["x"]) + i + 1)
        x[0] = 0
        y[0] = 1 * ht

        # add the points of the current right-running characteristic. These points
        # are included in the previous left-running characteristics.
        for j in range(i):
            x[j + 1] = left_runn_chars[j]["x"][i - j]
            y[j + 1] = left_runn_chars[j]["y"][i - j]

        # add the point of the current left-running characteristic
        if i == 0: j = -1
        x[j + 2:] = left_runn_chars[i]["x"]
        y[j + 2:] = left_runn_chars[i]["y"]

        characteristics.append({"x": x, "y": y})

        wall[i + 1, :] = [l["x"][-1], l["y"][-1]]

    return wall, characteristics, left_runn_chars, theta_w_max
Ejemplo n.º 3
0
    def compute(self, Pe_P0_ratio):
        """ 
        Compute the flow quantities along the nozzle geometry.

        Parameters
        ----------
            Pe_P0_ratio : float
                Back to Stagnation pressure ratio. The pressure at the
                exit plane coincide with the back pressure.
        
        Returns
        -------
            L : np.ndarray
                Lengths along the stream flow.
            area_ratios : np.ndarray
                Area ratios along the stream flow.
            M : np.ndarray
                Mach numbers.
            P_ratios : np.ndarray
                Pressure ratios.
            rho_ratios : np.ndarray
                Density ratios.
            T_ratios : np.ndarray
                Temperature ratios.
            flow_condition : string
                The flow condition given the input pressure ratio.
            Asw_At_ratio : float
                Area ratio of the shock wave location if present, otherwise
                return None.
        """
        self._flow_condition = self.flow_condition(Pe_P0_ratio)

        Ae = self._geometry.outlet_area
        At = self._geometry.critical_area
        Lc = self._geometry.length_convergent
        # copy the arrays: we do not want to modify the original geometry in case of
        # shock wave at the exit plane
        area_ratios = np.copy(self._geometry.area_ratio_array)
        L = np.copy(self._geometry.length_array) + Lc

        M = np.zeros_like(area_ratios)
        P_ratios = np.zeros_like(area_ratios)
        rho_ratios = np.zeros_like(area_ratios)
        T_ratios = np.zeros_like(area_ratios)
        flow_condition = self.flow_condition(Pe_P0_ratio)
        Asw_At_ratio = None

        if Pe_P0_ratio > 1:
            raise ValueError(
                "The back to reservoir pressure ratio must be Pe/P0 <= 1.")

        elif Pe_P0_ratio == 1:  # no flow
            P_ratios += 1
            T_ratios += 1
            rho_ratios += 1

        elif Pe_P0_ratio >= self._r1:  # fully subsonic flow
            M = m_from_critical_area_ratio(area_ratios, "sub", self._gas.gamma)
            P_ratios = pressure_ratio(M, self._gas.gamma)
            rho_ratios = density_ratio(M, self._gas.gamma)
            T_ratios = temperature_ratio(M, self._gas.gamma)

        elif Pe_P0_ratio < self._r2:  # fully supersonic flow in the divergent
            M[L < Lc] = m_from_critical_area_ratio(area_ratios[L < Lc], "sub",
                                                   self._gas.gamma)
            M[L == Lc] = 1
            M[L > Lc] = m_from_critical_area_ratio(area_ratios[L > Lc],
                                                   "super", self._gas.gamma)
            P_ratios = pressure_ratio(M, self._gas.gamma)
            rho_ratios = density_ratio(M, self._gas.gamma)
            T_ratios = temperature_ratio(M, self._gas.gamma)

        elif Pe_P0_ratio == self._r2:  # shock wave at the exit plane
            Ae_At_ratio = Ae / At
            Asw_At_ratio = Ae_At_ratio
            # Supersonic Mach number at the exit section just upstream of the shock wave
            Meup_sw = m_from_critical_area_ratio(Ae_At_ratio, "super",
                                                 self._gas.gamma)
            # Subsonic Mach number at the exit section just downstream of the shock wave
            Medw_sw = shockwave.mach_downstream(Meup_sw, self._gas.gamma)
            # downstream of the shock wave there is a new isentropic critical area ratio
            Ae_A2s_ratio = critical_area_ratio(Medw_sw, self._gas.gamma)
            # total pressure ratio across the shock wave
            P02_P0_ratio = shockwave.total_pressure_ratio(Meup_sw)

            M[L < Lc] = m_from_critical_area_ratio(area_ratios[L < Lc], "sub",
                                                   self._gas.gamma)
            M[L == Lc] = 1
            M[L > Lc] = m_from_critical_area_ratio(area_ratios[L > Lc],
                                                   "super", self._gas.gamma)

            # append the last subsonic point at the exit
            M = np.append(
                M,
                m_from_critical_area_ratio(Ae_A2s_ratio, "sub",
                                           self._gas.gamma))
            P_ratios = pressure_ratio(M, self._gas.gamma)
            # For idx_after_sw (downstream of the shock wave), I've been returned P/P02.
            # Need to compute the ratio P/P0.
            P_ratios[-1] *= P02_P0_ratio

            rho_ratios = density_ratio(M, self._gas.gamma)
            # P02 = rho02 * R * T02
            # P01 = rho01 * R * T01
            # Taking the ratios, and knowing that T01 = T02 across the shock wave, leads to:
            # P02 / P01 = rho02 / rho01
            # Need to compute the ratio rho/rho0 after the shock wave
            rho_ratios[-1] *= P02_P0_ratio

            T_ratios = temperature_ratio(M, self._gas.gamma)
            L = np.append(L, L[-1])
            area_ratios = np.append(area_ratios, Ae_At_ratio)
        else:  # shock into the divergent
            Ae_At_ratio = Ae / At
            # area ratio of the shock wave
            Asw_At_ratio = find_shockwave_area_ratio(Ae_At_ratio, Pe_P0_ratio,
                                                     self._gas.R,
                                                     self._gas.gamma)
            # Mach number at the exit section given the exit pressure ratio Pe_P0_ratio
            Me = m_from_critical_area_ratio_and_pressure_ratio(
                Ae_At_ratio, Pe_P0_ratio, self._gas.gamma)
            # downstream of the shock wave there is a new isentropic critical area ratio
            Ae_A2s_ratio = critical_area_ratio(Me, self._gas.gamma)
            # critical area downstream of the shock wave
            A2s = Ae / Ae_A2s_ratio
            # Mach number just upstream of the shock wave
            Mup_sw = m_from_critical_area_ratio(Asw_At_ratio, "super",
                                                self._gas.gamma)
            # total pressure ratio across the shock wave
            P02_P0_ratio = shockwave.total_pressure_ratio(Mup_sw)

            # find indeces before and after the shock wave in the divergent
            idx_before_sw = np.bitwise_and(L > Lc, area_ratios <= Asw_At_ratio)
            idx_after_sw = np.bitwise_and(L > Lc, area_ratios > Asw_At_ratio)

            # adjust the area ratios to use the new A2s downstream of the shock wave
            area_ratios[idx_after_sw] = area_ratios[idx_after_sw] * At / A2s

            # mach number in the convergent
            M[L < Lc] = m_from_critical_area_ratio(area_ratios[L < Lc], "sub",
                                                   self._gas.gamma)
            M[L == Lc] = 1
            # supersonic mach number
            M[idx_before_sw] = m_from_critical_area_ratio(
                area_ratios[idx_before_sw], "super", self._gas.gamma)
            # subsonic mach number
            M[idx_after_sw] = m_from_critical_area_ratio(
                area_ratios[idx_after_sw], "sub", self._gas.gamma)

            P_ratios = pressure_ratio(M, self._gas.gamma)
            # For idx_after_sw (downstream of the shock wave), I've been returned P/P02.
            # Need to compute the ratio P/P0.
            P_ratios[idx_after_sw] *= P02_P0_ratio

            rho_ratios = density_ratio(M, self._gas.gamma)
            # P02 = rho02 * R * T02
            # P01 = rho01 * R * T01
            # Taking the ratios, and knowing that T01 = T02 across the shock wave, leads to:
            # P02 / P01 = rho02 / rho01
            # Need to compute the ratio rho/rho0 after the shock wave
            rho_ratios[idx_after_sw] *= P02_P0_ratio

            T_ratios = temperature_ratio(M, self._gas.gamma)
        L -= Lc
        return L, area_ratios, M, P_ratios, rho_ratios, T_ratios, flow_condition, Asw_At_ratio
Ejemplo n.º 4
0
    def __init__(self, gas, geometry, input_state, Pb_P0_ratio=None):
        """
        Parameters
        ----------
            gas : Ideal_Gas
                Gas used in the nozzle.
            geometry : Nozzle_Geometry
                Nozzle geometry (lengths, areas, ...)
            input_state : Flow_State
                Represents the stagnation flow state.
            Pb_P0_ratio : float
                Back to Stagnation pressure ratio. Default to None.
        """
        self._gas = gas
        self._geometry = geometry
        self._input_state = input_state

        R = gas.R
        gamma = gas.gamma
        T0 = input_state.total_temperature
        P0 = input_state.total_pressure
        rho0 = gas.solve(p=P0, t=T0)

        Ae_As_ratio = geometry.outlet_area / geometry.critical_area

        self._critical_temperature = temperature_ratio(1, gamma) * T0
        self._critical_pressure = pressure_ratio(1, gamma) * P0
        self._critical_density = density_ratio(1, gamma) * rho0
        self._critical_velocity = sound_speed(self._critical_temperature, R,
                                              gamma)

        M2_sub = m_from_critical_area_ratio(Ae_As_ratio, "sub", gamma)
        M2_sup = m_from_critical_area_ratio(Ae_As_ratio, "super", gamma)

        # exit pressure ratio corresponding to fully subsonic flow in the divergent (when M=1 in A*)
        r1 = pressure_ratio(M2_sub, gamma)
        # exit pressure ratio corresponding to fully supersonic flow in the divergent
        # and Pe = Pb (pressure at back). Design condition.
        r3 = pressure_ratio(M2_sup, gamma)

        # isentropic pressure at the exit section of the divergent
        p_exit = r3 * P0

        # pressure downstream of the normal shock wave at the exit section of the divergent
        p2 = shockwave.pressure_ratio(M2_sup, gamma) * p_exit
        # exit pressure ratio corresponding to a normal shock wave at the exit section of the divergent
        r2 = p2 / P0

        self._r1 = r1
        self._r2 = r2
        self._r3 = r3

        self._flow_condition = self.flow_condition(Pb_P0_ratio)
        self._output_state = None

        if Pb_P0_ratio:
            # compute output state
            _, _, M, pr, rhor, tr, _, _ = self.compute(Pb_P0_ratio)

            self._output_state = Flow_State(m=M[-1],
                                            p=pr[-1] * P0,
                                            rho=rhor[-1] * rho0,
                                            t=tr[-1] * T0,
                                            p0=Pb_P0_ratio * P0,
                                            t0=T0)
Ejemplo n.º 5
0
def isentropic_solver(param_name, param_value, gamma=1.4):
    """
    Compute all isentropic ratios and Mach number given an input parameter.

    Parameters
    ----------
        param_name : string
            Name of the parameter given in input. Can be either one of:
            'm': Mach number
            'pressure': Pressure Ratio P/P0
            'density': Density Ratio rho/rho0
            'temperature': Temperature Ratio T/T0
            'crit_area_sub': Critical Area Ratio A/A* for subsonic case.
            'crit_area_super': Critical Area Ratio A/A* for supersonic case.
            'mach_angle': Mach Angle in degrees.
            'prandtl_meyer': Prandtl-Meyer Angle in degrees.
        param_value : float/list/array_like
            Actual value of the parameter. If float, list, tuple is given as
            input, a conversion will be attempted.
        gamma : float
            Specific heats ratio. Default to 1.4. Must be > 1.
    
    Returns
    -------
        M : array_like
            Mach number
        pr : array_like
            Pressure Ratio P/P0
        dr : array_like
            Density Ratio rho/rho0
        tr : array_like
            Temperature Ratio T/T0
        prs : array_like
            Critical Pressure Ratio P/P*
        drs : array_like
            Critical Density Ratio rho/rho*
        trs : array_like
            Critical Temperature Ratio T/T*
        urs : array_like
            Critical Velocity Ratio U/U*
        ar : array_like
            Critical Area Ratio A/A*
        ma : array_like
            Mach Angle
        pm : array_like
            Prandtl-Meyer Angle
    """

    assert isinstance(gamma, (
        int,
        float)) and gamma > 1, "The specific heats ratio must be a number > 1."

    assert isinstance(param_name, str), "param_name must be a string"
    param_name = param_name.lower()
    assert param_name in [
        'm', 'pressure', 'density', 'temperature', 'crit_area_sub',
        'crit_area_super', 'mach_angle', 'prandtl_meyer'
    ]

    # compute the Mach number
    param_value = convert_to_ndarray(param_value)

    M = None
    if param_name == "m":
        M = param_value
        assert np.all(M >= 0), "Mach number must be >= 0."
    elif param_name == "crit_area_sub":
        M = ise.m_from_critical_area_ratio(param_value, "sub", gamma)
    elif param_name == "crit_area_super":
        M = ise.m_from_critical_area_ratio(param_value, "super", gamma)

    func_dict = {
        'pressure': ise.m_from_pressure_ratio,
        'density': ise.m_from_density_ratio,
        'temperature': ise.m_from_temperature_ratio,
        'mach_angle': ise.m_from_mach_angle,
        'prandtl_meyer': ise.m_from_prandtl_meyer_angle,
    }
    if param_name in func_dict.keys():
        M = func_dict[param_name].__no_check(param_value, gamma)

    # compute the different ratios
    pr, dr, tr, prs, drs, trs, urs, ar, ma, pm = ise.get_ratios_from_mach.__no_check(
        M, gamma)

    return M, pr, dr, tr, prs, drs, trs, urs, ar, ma, pm