def test_hollweg1999_vals(self, kwargs, expected, desired_beta): """ Test calculated values based on Figure 2 of Hollweg1999 (DOI: https://doi.org/10.1029/1998JA900132) using eqn 3 of Bellan 2012 (DOI: https://doi.org/10.1029/2012JA017856). The WebPlotDigitizer software was used to determine the test parameters for k, B, and expected omega from Figure 2 of Hollweg1999. - GitHub: https://github.com/ankitrohatgi/WebPlotDigitizer - Web Version: https://automeris.io/WebPlotDigitizer/ """ # k values need to be single valued for this test to function correctly cs = speeds.cs_(kwargs["T_e"], kwargs["T_i"], kwargs["ion"]).value va = speeds.va_(kwargs["B"], kwargs["n_i"], ion=kwargs["ion"]).value beta = (cs / va)**2 if not np.isclose(beta, desired_beta, atol=2e-4): pytest.fail( f"The Holweg 1999 paper requires a 'beta' value of {desired_beta:0.5f} " f"and the test parameters yielded {beta:.6f}.") kz = (np.cos(kwargs["theta"]) * kwargs["k"]).value w_alfven = (hollweg(**kwargs)["alfven_mode"]).value big_omega = np.abs(w_alfven / (kz * va)) assert np.allclose(big_omega, expected, atol=1e-2)
def test_on_bellan2012_vals(self, kwargs, expected): """ Test calculated values based on Figure 1 of Bellan 2012 (DOI: https://agupubs.onlinelibrary.wiley.com/doi/10.1029/2012JA017856). """ # theta and k values need to be single valued for this test to function # correctly cs = cs_(kwargs["T_e"], kwargs["T_i"], kwargs["ion"]) va = va_(kwargs["B"], kwargs["n_i"], ion=kwargs["ion"]) wci = wc_(kwargs["B"], kwargs["ion"]) beta = (cs / va).value**2 if not np.isclose(beta, 0.4, atol=1e-4): pytest.fail( f"The Bellan 2012 paper requires a 'beta' value of 0.4 and the test " f"parameters yielded {beta:.6f}.") Lambda = (kwargs["k"] * va / wci).value**2 if not np.isclose(Lambda, 0.4, atol=1e-4): pytest.fail( f"The Bellan 2012 paper requires a 'Lambda' value of 0.4 and the test " f"parameters yielded {Lambda:.6f}.") ws = two_fluid(**kwargs) for mode, val in ws.items(): norm = (np.absolute(val) / (kwargs["k"] * va)).value**2 assert np.isclose(norm, expected[mode])
class TestAlfvenSpeed: """Test `~plasmapy.formulary.speeds.Alfven_speed`.""" @pytest.mark.parametrize( "args, kwargs, _error", [ # scenarios that raise RelativityError ((10 * u.T, 1.0e-10 * u.kg * u.m ** -3), {}, RelativityError), ((np.inf * u.T, 1 * u.m ** -3), {"ion": "p"}, RelativityError), ((-np.inf * u.T, 1 * u.m ** -3), {"ion": "p"}, RelativityError), # # scenarios that raise InvalidParticleError ((1 * u.T, 5e19 * u.m ** -3), {"ion": "spacecats"}, InvalidParticleError), # # scenarios that raise TypeError (("not a Bfield", 1.0e-10 * u.kg * u.m ** -3), {}, TypeError), ((10 * u.T, "not a density"), {}, TypeError), ((10 * u.T, 5), {"ion": "p"}, TypeError), ((1 * u.T, 1.0e18 * u.m ** -3), {"ion": ["He"]}, TypeError), ((1 * u.T, 1.0e18 * u.m ** -3), {"ion": "He", "z_mean": "nope"}, TypeError), # # scenarios that raise UnitTypeError ((1 * u.T, 1.0e18 * u.cm), {"ion": "He"}, u.UnitTypeError), ((1 * u.T, 5 * u.m ** -2), {"ion": "p"}, u.UnitTypeError), ((1 * u.cm, 1.0e18 * u.m ** -3), {"ion": "He"}, u.UnitTypeError), ((5 * u.A, 5e19 * u.m ** -3), {"ion": "p"}, u.UnitTypeError), # # scenarios that raise ValueError ((1 * u.T, -1.0e18 * u.m ** -3), {"ion": "He"}, ValueError), ( (np.array([5, 6, 7]) * u.T, np.array([5, 6]) * u.m ** -3), {"ion": "p"}, ValueError, ), ( (np.array([0.001, 0.002]) * u.T, np.array([-5e19, 6e19]) * u.m ** -3), {"ion": "p"}, ValueError, ), ], ) def test_raises(self, args, kwargs, _error): """Test scenarios that raise exceptions or warnings.""" with pytest.raises(_error): Alfven_speed(*args, **kwargs) @pytest.mark.parametrize( "args, kwargs, expected, isclose_kw, _warning", [ # scenarios that issue RelativityWarning ( (5 * u.T, 5e19 * u.m ** -3), {"ion": "H"}, 15413707.39, {}, RelativityWarning, ), ( (5 * u.T, 5e19 * u.m ** -3), {"ion": "H+"}, 15413707.39, {"rtol": 3.0e-4}, RelativityWarning, ), ( (5 * u.T, 5e19 * u.m ** -3), {"ion": "p"}, 15413707.39, {"rtol": 4.0e-4}, RelativityWarning, ), # # scenarios that issue UnitsWarning ((0.5, 1.0e18 * u.m ** -3), {"ion": "He"}, 5470657.93, {}, u.UnitsWarning), ], ) def test_warns(self, args, kwargs, expected, isclose_kw, _warning): """Test scenarios that issue warnings""" with pytest.warns(_warning): val = Alfven_speed(*args, **kwargs) assert isinstance(val, u.Quantity) assert val.unit == u.m / u.s assert np.isclose(val.value, expected, **isclose_kw) @pytest.mark.parametrize( "args, kwargs, expected, isclose_kw", [ ( (1 * u.T, 1e-8 * u.kg * u.m ** -3), {"ion": "p"}, 8920620.58 * u.m / u.s, {"rtol": 1e-6}, ), ( (1 * u.T, 1e-8 * u.kg * u.m ** -3), {}, 8920620.58 * u.m / u.s, {"rtol": 1e-6}, ), ( (0.05 * u.T, 1e18 * u.m ** -3), {"ion": "He"}, Alfven_speed(0.05 * u.T, 6.64738793e-09 * u.kg * u.m ** -3), {}, ), ( (0.05 * u.T, 1e18 * u.m ** -3), {"ion": "He+"}, Alfven_speed(0.05 * u.T, 1e18 * u.m ** -3, ion="He"), {"rtol": 7e-5}, ), ( (0.05 * u.T, 1e18 * u.m ** -3), {"ion": "He", "z_mean": 2}, Alfven_speed(0.05 * u.T, 1e18 * u.m ** -3, ion="He +2"), {"rtol": 1.4e-4}, ), ( (0.05 * u.T, 1e18 * u.m ** -3), {"ion": Particle("He+")}, Alfven_speed(0.05 * u.T, 1e18 * u.m ** -3, ion="He+"), {}, ), ( ([0.001, 0.002] * u.T, 5e-10 * u.kg * u.m ** -3), {}, [ va_(0.001 * u.T, 5e-10 * u.kg * u.m ** -3).value, va_(0.002 * u.T, 5e-10 * u.kg * u.m ** -3).value, ] * (u.m / u.s), {}, ), ( ([0.001, 0.002] * u.T, [5e-10, 2e-10] * u.kg * u.m ** -3), {}, [ va_(0.001 * u.T, 5e-10 * u.kg * u.m ** -3).value, va_(0.002 * u.T, 2e-10 * u.kg * u.m ** -3).value, ] * (u.m / u.s), {}, ), ( (0.001 * u.T, [1.0e18, 2e18] * u.m ** -3), {"ion": "p"}, [ va_(0.001 * u.T, 1e18 * u.m ** -3, ion="p").value, va_(0.001 * u.T, 2e18 * u.m ** -3, ion="p").value, ] * (u.m / u.s), {}, ), ], ) def test_values(self, args, kwargs, expected, isclose_kw): """Test expected values.""" assert np.allclose(Alfven_speed(*args, **kwargs), expected, **isclose_kw) @pytest.mark.parametrize( "args, kwargs, nan_mask", [ ((np.nan * u.T, 1 * u.kg * u.m ** -3), {}, []), ((0.001 * u.T, np.nan * u.kg * u.m ** -3), {}, []), (([np.nan, 0.001] * u.T, 1 * u.kg * u.m ** -3), {}, [True, False]), ( (0.001 * u.T, [np.nan, 1.0, np.nan] * u.kg * u.m ** -3), {}, [True, False, True], ), (([np.nan, 0.001] * u.T, [1, np.nan] * u.kg * u.m ** -3), {}, [True, True]), ( (0.001 * u.T, [np.nan, 1e18, np.nan] * u.m ** -3), {"ion": "Ar+"}, [True, False, True], ), ], ) def test_nan_values(self, args, kwargs, nan_mask): """Input scenarios that lead to `numpy.nan` values being returned.""" val = Alfven_speed(*args, **kwargs) if np.isscalar(val.value): assert np.isnan(val) else: nan_arr = np.isnan(val) assert np.all(nan_arr[nan_mask]) assert np.all(np.logical_not(nan_arr[np.logical_not(nan_mask)])) def test_handle_nparrays(self): """Test for ability to handle numpy array quantities""" assert_can_handle_nparray(Alfven_speed)