From f859bab2b45f915d66eda333a58735e7b8fb7274 Mon Sep 17 00:00:00 2001 From: MothNik Date: Tue, 21 May 2024 13:29:42 +0200 Subject: [PATCH] test/feat/refactor: added central finite differences test; made finite difference fixture smarter --- tests/fixtures.py | 4 +- .../reference_central_differences.csv | 22 ++++++ .../test_for_utils/test_finite_differences.py | 74 ++++++++++++++++--- 3 files changed, 88 insertions(+), 12 deletions(-) create mode 100644 tests/resources/finite_differences/reference_central_differences.csv diff --git a/tests/fixtures.py b/tests/fixtures.py index 0ee4646..8007ba4 100644 --- a/tests/fixtures.py +++ b/tests/fixtures.py @@ -133,10 +133,10 @@ def noise_level_whittaker_auto_lambda() -> np.ndarray: @pytest.fixture -def reference_forward_finite_differences() -> List[RefDifferenceKernel]: +def reference_finite_differences(kind: str) -> List[RefDifferenceKernel]: fpath = os.path.join( path_to_resources, - "./finite_differences/reference_forward_differences.csv", + f"./finite_differences/reference_{kind}_differences.csv", ) fin_diff_table = np.genfromtxt( fpath, diff --git a/tests/resources/finite_differences/reference_central_differences.csv b/tests/resources/finite_differences/reference_central_differences.csv new file mode 100644 index 0000000..ca0e00a --- /dev/null +++ b/tests/resources/finite_differences/reference_central_differences.csv @@ -0,0 +1,22 @@ +From https://en.wikipedia.org/wiki/Finite_difference_coefficient#Central_finite_difference,,,,,,,,,,,, +Difference Order,Accuracy,,,,,,,,,,, +1,2,-0.5,0,0.5,,,,,,,, +1,4,0.0833333333333333,-0.666666666666667,0,0.666666666666667,-0.0833333333333333,,,,,, +1,6,-0.0166666666666667,0.15,-0.75,0,0.75,-0.15,0.0166666666666667,,,, +1,8,0.00357142857142857,-0.0380952380952381,0.2,-0.8,0,0.8,-0.2,0.0380952380952381,-0.00357142857142857,, +2,2,1,-2,1,,,,,,,, +2,4,-0.0833333333333333,1.33333333333333,-2.5,1.33333333333333,-0.0833333333333333,,,,,, +2,6,0.0111111111111111,-0.15,1.5,-2.72222222222222,1.5,-0.15,0.0111111111111111,,,, +2,8,-0.00178571428571429,0.0253968253968254,-0.2,1.6,-2.84722222222222,1.6,-0.2,0.0253968253968254,-0.00178571428571429,, +3,2,-0.5,1,0,-1,0.5,,,,,, +3,4,0.125,-1,1.625,0,-1.625,1,-0.125,,,, +3,6,-0.0291666666666667,0.3,-1.40833333333333,2.03333333333333,0,-2.03333333333333,1.40833333333333,-0.3,0.0291666666666667,, +4,2,1,-4,6,-4,1,,,,,, +4,4,-0.166666666666667,2,-6.5,9.33333333333333,-6.5,2,-0.166666666666667,,,, +4,6,0.0291666666666667,-0.4,2.81666666666667,-8.13333333333333,11.375,-8.13333333333333,2.81666666666667,-0.4,0.0291666666666667,, +5,2,-0.5,2,-2.5,0,2.5,-2,0.5,,,, +5,4,0.166666666666667,-1.5,4.33333333333333,-4.83333333333333,0,4.83333333333333,-4.33333333333333,1.5,-0.166666666666667,, +5,6,-0.0451388888888889,0.527777777777778,-2.71875,6.5,-6.72916666666667,0,6.72916666666667,-6.5,2.71875,-0.527777777777778,0.0451388888888889 +6,2,1,-6,15,-20,15,-6,1,,,, +6,4,-0.25,3,-13,29,-37.5,29,-13,3,-0.25,, +6,6,0.0541666666666667,-0.791666666666667,5.4375,-19.5,40.375,-51.15,40.375,-19.5,5.4375,-0.791666666666667,0.0541666666666667 diff --git a/tests/test_for_utils/test_finite_differences.py b/tests/test_for_utils/test_finite_differences.py index c3428b5..040a39d 100644 --- a/tests/test_for_utils/test_finite_differences.py +++ b/tests/test_for_utils/test_finite_differences.py @@ -12,13 +12,14 @@ import pytest from chemotools.utils._finite_differences import ( + calc_central_diff_kernel, calc_forward_diff_kernel, estimate_noise_stddev, gen_squ_fw_fin_diff_mat_cho_banded, ) from tests.fixtures import noise_level_estimation_refs # noqa: F401 from tests.fixtures import noise_level_estimation_signal # noqa: F401 -from tests.fixtures import reference_forward_finite_differences # noqa: F401 +from tests.fixtures import reference_finite_differences # noqa: F401 from tests.test_for_utils.utils_funcs import ( conv_upper_cho_banded_storage_to_sparse, multiply_vect_with_squ_fw_fin_diff_orig_first, @@ -32,20 +33,61 @@ ### Test Suite ### +# parametrizes the fixture ``reference_finite_differences`` +@pytest.mark.parametrize("kind", ["forward"]) def test_forward_diff_kernel( - reference_forward_finite_differences: List[RefDifferenceKernel], # noqa: F811 + reference_finite_differences: List[RefDifferenceKernel], # noqa: F811 ) -> None: + """ + Tests the calculation of the forward finite difference kernel. + + """ + # each kernel is calculated and compared to the reference - for ref_diff_kernel in reference_forward_finite_differences: + for ref_diff_kernel in reference_finite_differences: kernel = calc_forward_diff_kernel(differences=ref_diff_kernel.differences) + # first, the size of the kernel is checked ... + assert kernel.size == ref_diff_kernel.size, ( + f"Difference order {ref_diff_kernel.differences} with accuracy 1 - " + f"Expected kernel size {ref_diff_kernel.size} but got {kernel.size}" + ) + # ... followed by the comparison of the kernel itself + assert np.allclose(kernel, ref_diff_kernel.kernel, atol=1e-8), ( + f"Difference order {ref_diff_kernel.differences} with accuracy 1 - " + f"Expected kernel {ref_diff_kernel.kernel.tolist()} but got " + f"{kernel.tolist()}" + ) + + +# parametrizes the fixture ``reference_finite_differences`` +@pytest.mark.parametrize("kind", ["central"]) +def test_central_diff_kernel( + reference_finite_differences: List[RefDifferenceKernel], # noqa: F811 +) -> None: + """ + Tests the calculation of the central finite difference kernel. + + """ + + # each kernel is calculated and compared to the reference + for ref_diff_kernel in reference_finite_differences: + kernel = calc_central_diff_kernel( + differences=ref_diff_kernel.differences, + accuracy=ref_diff_kernel.accuracy, + ) + + # first, the size of the kernel is checked ... assert kernel.size == ref_diff_kernel.size, ( - f"Difference order {ref_diff_kernel.differences} with accuracy 1 expected " - f"kernel size {ref_diff_kernel.size} but got {kernel.size}" + f"Difference order {ref_diff_kernel.differences} with accuracy " + f"{ref_diff_kernel.accuracy} - Expected kernel size {ref_diff_kernel.size} " + f"but got {kernel.size}" ) + # ... followed by the comparison of the kernel itself assert np.allclose(kernel, ref_diff_kernel.kernel, atol=1e-8), ( - f"Difference order {ref_diff_kernel.differences} with accuracy 1 expected " - f"kernel {ref_diff_kernel.kernel.tolist()} but got {kernel.tolist()}" + f"Difference order {ref_diff_kernel.differences} with accuracy " + f"{ref_diff_kernel.accuracy} - Expected kernel " + f"{ref_diff_kernel.kernel.tolist()} but got {kernel.tolist()}" ) @@ -322,7 +364,7 @@ def test_estimate_noise_stddev_invalid_input( differences=differences, diff_accuracy=accuracy, window_size=window_size, - power=power, # type: ignore + power=power, # type: ignore stddev_min=stddev_min, ) @@ -353,7 +395,12 @@ def test_noise_level_estimation( # way because both results were computed in the same way with the only # difference being that Chemotools uses Python and the reference uses # LibreOffice Calc - assert np.allclose(noise_level, ref.noise_level, rtol=1e-12) + assert np.allclose(noise_level, ref.noise_level, rtol=1e-12), ( + f"Original noise level differs from reference noise for differences " + f"{ref.differences} with accuracy {ref.accuracy} and window size " + f"{ref.window_size} given a minimum standard deviation of " + f"{ref.min_noise_level}." + ) # then, all the available powers to which the noise level can be raised are # compared to the reference @@ -368,6 +415,13 @@ def test_noise_level_estimation( ) # again, the comparison is quite strict - assert np.allclose(raised_noise_level, raised_noise_level_ref, atol=1e-12) + assert np.allclose( + raised_noise_level, raised_noise_level_ref, atol=1e-12 + ), ( + f"Raised noise level differs from reference noise for differences " + f"{ref.differences} with accuracy {ref.accuracy} and window size " + f"{ref.window_size} given a minimum standard deviation of " + f"{ref.min_noise_level} and a power of {power}." + ) return