def max_deflection(M_1, gamma=1.4): """Returns maximum deflection angle and corresponding wave angle for given Mach number. Parameters ---------- M_1 : float Upstream Mach number. gamma : float, optional Specific heat ratio, default 7 / 5. Returns ------- theta : float Maximum deflection angle. beta : float Corresponding wave angle. """ def eq(beta, M_1, gamma): os = _ShockClass(M_1, beta, gamma) return -os.theta mu = mach_angle(M_1) beta_theta_max = optimize.fminbound(eq, mu, np.pi / 2, args=(M_1, gamma), disp=0) os = _ShockClass(M_1, beta_theta_max, gamma) return os.theta, os.beta
def _from_deflection_angle(M_1, theta, weak, gamma): """Returns oblique shock given upstream Mach number and deflection angle. """ def eq(beta, M_1, theta, gamma): os = _ShockClass(M_1, beta, gamma) return os.theta - theta theta_max, beta_theta_max = max_deflection(M_1) if theta > theta_max: raise ValueError("No attached solution for this deflection angle") else: if weak: mu = mach_angle(M_1) beta = optimize.bisect(eq, mu, beta_theta_max, args=(M_1, theta, gamma)) else: beta = optimize.bisect(eq, beta_theta_max, np.pi / 2, args=(M_1, theta, gamma)) return _ShockClass(M_1, beta, gamma)
def test_mach_angle(): M_list = [1.1, 1.38, 2.05, 3.0, np.inf] mu_list = [65.38, 46.44, 29.20, 19.47, 0.0] expected_mach_angles = [np.radians(val) for val in mu_list] mach_angles = [isentropic.mach_angle(M) for M in M_list] np.testing.assert_array_almost_equal(mach_angles, expected_mach_angles, decimal=3)
def __init__(self, M_1, beta, gamma): mu = mach_angle(M_1) if beta < mu: raise ValueError( "Shock wave angle must be higher than Mach angle {:.2f}°". format(np.degrees(mu))) self.M_1 = M_1 self.M_1n = M_1 * np.sin(beta) if beta != 0.0 else 0.0 self.beta = beta self.gamma = gamma
def __init__(self, M_1, beta, gamma): mu = mach_angle(M_1) if beta < mu: raise ValueError( "Shock wave angle must be higher than Mach angle {:.2f}°" .format(np.degrees(mu))) self.M_1 = M_1 self.M_1n = M_1 * np.sin(beta) if beta != 0.0 else 0.0 self.beta = beta self.gamma = gamma
def theta(self): """Deflection angle of the shock. """ if self.beta == mach_angle(self.M_1) or self.beta == np.pi / 2: theta = 0.0 else: theta = np.arctan( 2 / np.tan(self.beta) * (np.sin(self.beta)**2 - 1 / self.M_1 / self.M_1) / (self.gamma + np.cos(2 * self.beta) + 2 / self.M_1 / self.M_1)) return theta
def theta(self): """Deflection angle of the shock. """ if self.beta == mach_angle(self.M_1) or self.beta == np.pi / 2: theta = 0.0 else: theta = np.arctan( 2 / np.tan(self.beta) * (np.sin(self.beta) ** 2 - 1 / self.M_1 / self.M_1) / (self.gamma + np.cos(2 * self.beta) + 2 / self.M_1 / self.M_1)) return theta
def test_mach_angle(): M_list = [1.1, 1.38, 2.05, 3.0, np.inf] mu_list = [ 65.38, 46.44, 29.20, 19.47, 0.0 ] expected_mach_angles = [np.radians(val) for val in mu_list] mach_angles = [isentropic.mach_angle(M) for M in M_list] np.testing.assert_array_almost_equal(mach_angles, expected_mach_angles, decimal=3)
def _from_deflection_angle(M_1, theta, weak, gamma): """Returns oblique shock given upstream Mach number and deflection angle. """ def eq(beta, M_1, theta, gamma): os = _ShockClass(M_1, beta, gamma) return os.theta - theta theta_max, beta_theta_max = max_deflection(M_1) if theta > theta_max: raise ValueError("No attached solution for this deflection angle") else: if weak: mu = mach_angle(M_1) beta = sp.optimize.bisect( eq, mu, beta_theta_max, args=(M_1, theta, gamma)) else: beta = sp.optimize.bisect( eq, beta_theta_max, np.pi / 2, args=(M_1, theta, gamma)) return _ShockClass(M_1, beta, gamma)
def test_mach_angle_raises_error_when_mach_is_subsonic(): with pytest.raises(ValueError) as excinfo: isentropic.mach_angle(0.8) assert excinfo.exconly().startswith("ValueError: " "Mach number must be supersonic")