def test_fatigue_data_finite_infinite_zone(data, finite_zone_expected, infinite_zone_expected): fd = woehler.determine_fractures(data, 1e7).sort_index().fatigue_data pd.testing.assert_frame_equal( sort_fatigue_data(fd.finite_zone)[['load', 'cycles']], sort_fatigue_data(finite_zone_expected)) fd = woehler.determine_fractures(data, 1e7).sort_index().fatigue_data pd.testing.assert_frame_equal( sort_fatigue_data(fd.infinite_zone)[['load', 'cycles']], sort_fatigue_data(infinite_zone_expected))
def test_max_likelihood_parameter_sign(data, no): def _modify_initial_parameters_mock(fd): return fd load_cycle_limit = 1e6 if hasattr(data, "N_threshold"): load_cycle_limit = data.N_threshold fatdat = woehler.determine_fractures(data, load_cycle_limit=load_cycle_limit) ml = woehler.MaxLikeFull(fatigue_data=fatdat.fatigue_data) wl = ml.analyze() print("Data set number {}".format(no)) print("Woehler parameters: {}".format(wl)) def assert_positive_or_nan_but_not_zero(x): if np.isfinite(x): assert x >= 0 assert not np.isclose(x, 0.0) assert_positive_or_nan_but_not_zero(wl['SD_50']) assert_positive_or_nan_but_not_zero(wl['1/TS']) assert_positive_or_nan_but_not_zero(wl['k_1']) assert_positive_or_nan_but_not_zero(wl['ND_50']) assert_positive_or_nan_but_not_zero(wl['1/TN'])
def test_bayesian_TN_trace(pm): fd = woehler.determine_fractures(data, 1e7).fatigue_data bayes = woehler.Bayesian(fd) bayes._common_analysis() bayes._nsamples = 1000 bayes._TN_trace() pm.HalfNormal.assert_called_with('stdev', sigma=1.3) assert pm.Normal.call_count == 2 expected_mu = 5.294264482012933 expected_sigma = 0.2621494419382026 assert pm.Normal.call_args_list[0][0] == ('mu', ) np.testing.assert_almost_equal(pm.Normal.call_args_list[0][1]['mu'], expected_mu, decimal=9) np.testing.assert_almost_equal(pm.Normal.call_args_list[0][1]['sigma'], expected_sigma, decimal=9) assert pm.Normal.call_args_list[1][0] == ('y', ) observed = pm.Normal.call_args_list[1][1][ 'observed'] # Consider switch to kwargs property when py3.7 is dropped np.testing.assert_almost_equal(observed.mean(), expected_mu, decimal=9) np.testing.assert_almost_equal(observed.std(), expected_sigma, decimal=9) pm.sample.assert_called_with(1000, target_accept=0.99, random_seed=None, chains=3, tune=1000)
def test_woehler_fracture_determination_given(): df = pd.DataFrame({'load': [1, 2, 3], 'cycles': [1e6, 1e7, 1e4]}) expected = pd.DataFrame({ 'load': [1, 2, 3], 'cycles': [1e6, 1e7, 1e4], 'fracture': [True, False, True] }) expected_runouts = pd.DataFrame( { 'load': [2], 'cycles': [1e7], 'fracture': [False] }, index=[1]) expected_fractures = pd.DataFrame( { 'load': [1, 3], 'cycles': [1e6, 1e4], 'fracture': [True, True] }, index=[0, 2]) test = woehler.determine_fractures(df, 1e7).sort_index() pd.testing.assert_frame_equal(test, expected) fd = test.fatigue_data pd.testing.assert_frame_equal(fd.fractures, expected_fractures) pd.testing.assert_frame_equal(fd.runouts, expected_runouts)
def test_fatigue_data_simple_properties(): fd = woehler.determine_fractures(data, 1e7).sort_index().fatigue_data pd.testing.assert_series_equal(fd.load.sort_values(), load_sorted) pd.testing.assert_series_equal(fd.cycles.sort_values(), cycles_sorted) assert fd.num_runouts == 18 assert fd.num_fractures == 22
def test_bayesian_mock(_slope_trace, _TN_trace, _SD_TS_trace): expected = pd.Series({ 'SD_50': 100., '1/TS': 1.12, 'k_1': 7.0, 'ND_50': 1e6, '1/TN': 5.3 }).sort_index() expected_slope_trace = { 'x': np.array([0.0, -8.0, -6.0]), 'Intercept': np.array([0.0, 19., 21.]) } expected_SD_TS_trace = { 'SD_50': np.array([0.0, 150., 50]), 'TS_50': np.array([0.0, 1.22, 1.02]) } _slope_trace.__call__( ).get_values.side_effect = lambda key: expected_slope_trace[key] _TN_trace.__call__().get_values.return_value = np.array([0.0, 5.4, 5.2]) _SD_TS_trace.__call__( ).get_values.side_effect = lambda key: expected_SD_TS_trace[key] fd = woehler.determine_fractures(data, 1e7).fatigue_data wc = woehler.Bayesian(fd).analyze(nsamples=10).sort_index() pd.testing.assert_series_equal(wc, expected) np.testing.assert_allclose(wc.to_numpy(), expected.to_numpy())
def test_woehler_elementary_only_one_load_level(): data = pd.DataFrame(np.array([[350.0, 1e7], [350.0, 1e6]]), columns=['load', 'cycles']) fd = woehler.determine_fractures(data, 1e7).fatigue_data with pytest.raises( ValueError, match=r"Need at least two load levels to do a Wöhler analysis."): woehler.Elementary(fd).analyze().sort_index()
def test_woehler_probit_one_runout_load_level(): fd = woehler.determine_fractures(data_one_runout_load_level, 1e7).fatigue_data expected = woehler.Elementary(fd).analyze() with pytest.warns( UserWarning, match= r"Probit needs at least two runout load levels. Falling back to Elementary." ): wc = woehler.Probit(fd).analyze() pd.testing.assert_series_equal(wc, expected)
def test_woehler_fracture_determination_infered(): df = pd.DataFrame({'load': [1, 2, 3], 'cycles': [1e6, 1e7, 1e4]}) expected = pd.DataFrame({ 'load': [1, 2, 3], 'cycles': [1e6, 1e7, 1e4], 'fracture': [True, False, True] }) test = woehler.determine_fractures(df).sort_index() pd.testing.assert_frame_equal(test, expected)
def test_woehler_elementary_no_runouts(): expected = pd.Series({ 'SD_50': 0.0, 'k_1': 7.0, '1/TN': 5.3, '1/TS': 1.27 }).sort_index() fd = woehler.determine_fractures(data_no_runouts, 1e7).fatigue_data wc = woehler.Elementary(fd).analyze().sort_index().drop('ND_50') pd.testing.assert_index_equal(wc.index, expected.index) np.testing.assert_allclose(wc.to_numpy(), expected.to_numpy(), rtol=1e-1)
def test_woehler_probit(): expected = pd.Series({ 'SD_50': 335, '1/TS': 1.19, 'k_1': 6.94, 'ND_50': 463000., '1/TN': 5.26 }).sort_index() fd = woehler.determine_fractures(data, 1e7).fatigue_data wc = woehler.Probit(fd).analyze().sort_index() pd.testing.assert_index_equal(wc.index, expected.index) np.testing.assert_allclose(wc.to_numpy(), expected.to_numpy(), rtol=1e-1)
def test_woehler_elementary_initialize_with_determined_fractures(): expected = pd.Series({ 'SD_50': 362.5, 'k_1': 7.0, 'ND_50': 3e5, '1/TN': 5.3, '1/TS': 1.27 }).sort_index() fd = woehler.determine_fractures(data, 1e7) wc = woehler.Elementary(fd).analyze().sort_index() pd.testing.assert_index_equal(wc.index, expected.index) np.testing.assert_allclose(wc.to_numpy(), expected.to_numpy(), rtol=1e-1)
def test_woehler_max_likelihood_inf_limit_no_runouts(): expected = pd.Series({ 'SD_50': 0., '1/TS': 1.19, 'k_1': 6.94, 'ND_50': 4.4e30, '1/TN': 5.26 }).sort_index() fd = woehler.determine_fractures(data_no_runouts, 1e7).fatigue_data wc = woehler.MaxLikeInf(fd).analyze().sort_index() pd.testing.assert_index_equal(wc.index, expected.index) np.testing.assert_allclose(wc.to_numpy(), expected.to_numpy(), rtol=1e-1)
def test_bayesian_full(): expected = pd.Series({ 'SD_50': 340., '1/TS': 1.12, 'k_1': 7.0, 'ND_50': 400000., '1/TN': 5.3 }).sort_index() fd = woehler.determine_fractures(data, 1e7).fatigue_data wc = woehler.Bayesian(fd).analyze(random_seed=4223, progressbar=False).sort_index() pd.testing.assert_index_equal(wc.index, expected.index) np.testing.assert_allclose(wc.to_numpy(), expected.to_numpy(), rtol=1e-1)
def test_woehler_probit_no_runouts(): expected = pd.Series({ 'SD_50': 0., '1/TS': 1.27, 'k_1': 6.94, 'ND_50': 4.4e30, '1/TN': 5.26 }).sort_index() fd = woehler.determine_fractures(data_no_runouts, 1e7).fatigue_data pb = woehler.Probit(fd) with pytest.warns(UserWarning): wc = pb.analyze().sort_index() pd.testing.assert_index_equal(wc.index, expected.index) np.testing.assert_allclose(wc.to_numpy(), expected.to_numpy(), rtol=1e-1)
def test_woehler_probit_data01(): expected = pd.Series({ 'SD_50': 490, '1/TS': 1.1, 'k_1': 8.0, 'ND_50': 530e3, '1/TN': 3.0 }).sort_index() fd = woehler.determine_fractures(data_01, 1e7).fatigue_data pb = woehler.Probit(fd) wc = pb.analyze().sort_index() bic = pb.bayesian_information_criterion() pd.testing.assert_index_equal(wc.index, expected.index) np.testing.assert_allclose(wc.to_numpy(), expected.to_numpy(), rtol=1e-1)
def test_max_likelihood_full_method_with_all_fixed_params(): """ Test of woehler curve parameters evaluation with the maximum likelihood method """ fp = { 'k_1': 15.7, '1/TN': 1.2, 'SD_50': 280, '1/TS': 1.2, 'ND_50': 10000000 } fd = woehler.determine_fractures(data, 1e7).fatigue_data with pytest.raises( AttributeError, match=r'You need to leave at least one parameter empty!'): (woehler.MaxLikeFull(fd).analyze(fixed_parameters=fp))
def test_max_likelihood_one_mixed_horizon(): expected = pd.Series({ 'SD_50': 489.3, '1/TS': 1.147, 'k_1': 7.99, 'ND_50': 541e3, '1/TN': 2.51 }).sort_index() fd = woehler.determine_fractures(data_01, 1e7).fatigue_data ml = woehler.MaxLikeFull(fatigue_data=fd) with pytest.warns(UserWarning, match=r"^.*less than two mixed load levels.*"): wc = ml.analyze().sort_index() bic = ml.bayesian_information_criterion() pd.testing.assert_index_equal(wc.index, expected.index) np.testing.assert_allclose(wc.to_numpy(), expected.to_numpy(), rtol=1e-1)
def test_max_likelihood_full_with_fixed_params(): expected = pd.Series({ 'SD_50': 335, '1/TS': 1.19, 'k_1': 8.0, 'ND_50': 520000., '1/TN': 6.0 }).sort_index() fd = woehler.determine_fractures(data, 1e7).fatigue_data wc = (woehler.MaxLikeFull(fd).analyze(fixed_parameters={ '1/TN': 6.0, 'k_1': 8.0 }).sort_index()) pd.testing.assert_index_equal(wc.index, expected.index) np.testing.assert_allclose(wc.to_numpy(), expected.to_numpy(), rtol=1e-1) assert wc['1/TN'] == 6.0 assert wc['k_1'] == 8.0
def test_woehler_max_likelihood_full_without_fixed_params(): expected = pd.Series({ 'SD_50': 335, '1/TS': 1.19, 'k_1': 6.94, 'ND_50': 463000., '1/TN': 4.7 }).sort_index() bic = 45.35256860035525 fd = woehler.determine_fractures(data, 1e7).fatigue_data we = woehler.MaxLikeFull(fd) wc = we.analyze().sort_index() pd.testing.assert_index_equal(wc.index, expected.index) np.testing.assert_allclose(wc.to_numpy(), expected.to_numpy(), rtol=1e-1) np.testing.assert_almost_equal(we.bayesian_information_criterion(), bic, decimal=2)
def test_bayesian_slope_trace(pm): fd = woehler.determine_fractures(data, 1e7).fatigue_data bayes = woehler.Bayesian(fd) bayes._nsamples = 1000 bayes._slope_trace() formula, data_dict = pm.glm.GLM.from_formula.call_args[0] assert formula == 'y ~ x' pd.testing.assert_series_equal(data_dict['x'], np.log10(fd.fractures.load)) np.testing.assert_array_equal(data_dict['y'], np.log10(fd.fractures.cycles.to_numpy())) family = pm.glm.GLM.from_formula.call_args[1][ 'family'] # Consider switch to kwargs property when py3.7 is dropped assert family is pm.glm.families.StudentT() pm.sample.assert_called_with(1000, target_accept=0.99, random_seed=None, chains=2, tune=1000)
def test_woehler_max_likelihood_full_without_fixed_params_no_runouts(): expected = pd.Series({ 'SD_50': 0, '1/TS': 1., 'k_1': 6.94, 'ND_50': 4.4e30, '1/TN': 5.7 }).sort_index() bic = np.inf fd = woehler.determine_fractures(data_no_runouts, 1e7).fatigue_data we = woehler.MaxLikeFull(fd) with pytest.warns(UserWarning, match=r"^.*no runouts are present.*"): wc = we.analyze().sort_index() pd.testing.assert_index_equal(wc.index, expected.index) np.testing.assert_allclose(wc.to_numpy(), expected.to_numpy(), rtol=1e-1) np.testing.assert_almost_equal(we.bayesian_information_criterion(), bic, decimal=2)
def test_bayesian_SD_TS_trace_mock(pm, tt): def check_likelihood(l, var): assert var == tt.as_tensor_variable.return_value assert isinstance(l.likelihood, woehler.analyzers.likelihood.Likelihood) np.testing.assert_array_equal(l.likelihood._fd, fd) return 'foovar' fd = woehler.determine_fractures(data, 1e7).fatigue_data inf_load_mean = fd.infinite_zone.load.mean() inf_load_std = fd.infinite_zone.load.std() with mock.patch.object(woehler.Bayesian._LogLike, '__call__', autospec=True) as loglike_call: loglike_call.side_effect = check_likelihood bayes = woehler.Bayesian(fd) bayes._nsamples = 1000 bayes._SD_TS_trace() pm.Normal.assert_called_once_with('SD_50', mu=inf_load_mean, sigma=inf_load_std * 5) pm.Lognormal.assert_called_once_with('TS_50', mu=np.log10(1.1), sigma=np.log10(0.5)) tt.as_tensor_variable.assert_called_once_with( [pm.Normal.return_value, pm.Lognormal.return_value]) pm.Potential.assert_called_once_with('likelihood', 'foovar') pm.sample.assert_called_with(1000, cores=1, chains=3, random_seed=None, discard_tuned_samples=True, tune=1000)
def test_woehler_endur_zones(data, fatigue_limit_expected): fd = woehler.determine_fractures(data, 1e7).fatigue_data assert fd.fatigue_limit == fatigue_limit_expected
def test_max_likelihood_min_three_fractures_on_two_load_levels(invalid_data): fd = woehler.determine_fractures(invalid_data, 1e7).fatigue_data ml = woehler.MaxLikeFull(fatigue_data=fd) with pytest.raises(ValueError, match=r"^.*[N|n]eed at least.*"): ml.analyze()
def test_woehler_endur_zones_conservative(data, fatigue_limit_expected): fd = woehler.determine_fractures(data, 1e7).fatigue_data print(fd.fatigue_limit) fd = fd.conservative_fatigue_limit() print(fd.fatigue_limit) assert fd.fatigue_limit == fatigue_limit_expected
def test_woehler_endure_zones_no_runouts(): df = data[data.cycles < 1e7] fd = woehler.determine_fractures(df, 1e7).fatigue_data assert fd.fatigue_limit == 0.0
def test_bic_without_analysis(): fd = woehler.determine_fractures(data, 1e7).fatigue_data we = woehler.MaxLikeFull(fd) with pytest.raises(ValueError, match="^.*BIC.*"): we.bayesian_information_criterion()