diff --git a/napytau/core/chi.py b/napytau/core/chi.py index 22e1a70..26f70cc 100644 --- a/napytau/core/chi.py +++ b/napytau/core/chi.py @@ -1,5 +1,5 @@ -from napytau.core.polynomials import polynomial_sum_at_measuring_distances -from napytau.core.polynomials import differentiated_polynomial_sum_at_measuring_distances # noqa E501 +from napytau.core.polynomials import evaluate_polynomial_at_measuring_distances +from napytau.core.polynomials import evaluate_differentiated_polynomial_at_measuring_distances # noqa E501 from numpy import ndarray from numpy import sum from numpy import mean @@ -9,7 +9,6 @@ from typing import Tuple -# chi^2 function for fixed t_hyp def chi_squared_fixed_t( doppler_shifted_intensities: ndarray, unshifted_intensities: ndarray, @@ -47,19 +46,18 @@ def chi_squared_fixed_t( # Compute the difference between Doppler-shifted intensities and polynomial model shifted_intensity_difference: ndarray = ( - doppler_shifted_intensities - - polynomial_sum_at_measuring_distances(distances, coefficients) + doppler_shifted_intensities + - evaluate_polynomial_at_measuring_distances(distances, coefficients) ) / delta_doppler_shifted_intensities # Compute the difference between unshifted intensities and # scaled derivative of the polynomial model unshifted_intensity_difference: ndarray = ( unshifted_intensities - - ( - t_hyp - * differentiated_polynomial_sum_at_measuring_distances(distances, + - (t_hyp + * evaluate_differentiated_polynomial_at_measuring_distances(distances, coefficients) - ) + ) ) / delta_unshifted_intensities # combine the weighted sum of squared differences @@ -179,10 +177,8 @@ def optimize_t_hyp( # Initial guess for t_hyp. Startíng with the mean reduces likelihood of # biasing the optimization process toward one boundary. x0=mean(t_hyp_range), - bounds=[(t_hyp_range[0], t_hyp_range[1])], # Boundaries for optimization + bounds=[(t_hyp_range[0], t_hyp_range[1])], ) # Return optimized t_hyp value - optimized_t_hyp: float = result.x - - return optimized_t_hyp + return float(result.x) diff --git a/napytau/core/core.py b/napytau/core/core.py index 16a9221..7748d83 100644 --- a/napytau/core/core.py +++ b/napytau/core/core.py @@ -1,7 +1,7 @@ import numpy as np -from napytau.core.tau import optimize_t_hyp -from napytau.core.tau import optimize_coefficients -from napytau.core.tau import calculate_tau_i +from napytau.core.chi import optimize_t_hyp +from napytau.core.chi import optimize_coefficients +from napytau.core.tau import calculate_tau_i_values from napytau.core.delta_tau import calculate_error_propagation_terms from napytau.core.tau_final import calculate_tau_final from typing import Tuple, Optional @@ -46,15 +46,15 @@ def calculate_lifetime(doppler_shifted_intensities: np.ndarray, )[0] # We now calculate the lifetimes tau_i for all measured distances - tau_i_values: np.ndarray = calculate_tau_i(doppler_shifted_intensities, - unshifted_intensities, - delta_doppler_shifted_intensities, - delta_unshifted_intensities, - initial_coefficients, - distances, - t_hyp_range, - weight_factor, - custom_t_hyp_estimate) + tau_i_values: np.ndarray = calculate_tau_i_values(doppler_shifted_intensities, + unshifted_intensities, + delta_doppler_shifted_intensities, + delta_unshifted_intensities, + initial_coefficients, + distances, + t_hyp_range, + weight_factor, + custom_t_hyp_estimate) # And we calculate the respective errors for the lifetimes delta_tau_i_values: np.ndarray = calculate_error_propagation_terms( diff --git a/napytau/core/delta_tau.py b/napytau/core/delta_tau.py index dd54998..3cfc05b 100644 --- a/napytau/core/delta_tau.py +++ b/napytau/core/delta_tau.py @@ -1,5 +1,5 @@ -from napytau.core.polynomials import differentiated_polynomial_sum_at_measuring_distances # noqa E501 -from napytau.core.polynomials import polynomial_sum_at_measuring_distances +from napytau.core.polynomials import evaluate_differentiated_polynomial_at_measuring_distances # noqa E501 +from napytau.core.polynomials import evaluate_polynomial_at_measuring_distances from numpy import array from numpy import ndarray from numpy import zeros @@ -20,7 +20,7 @@ def calculate_jacobian_matrix(distances: ndarray, coefficients: ndarray) -> ndar Returns: ndarray: - The computed Jacobian matrix with shape (len(times), len(coefficients)). + The computed Jacobian matrix with shape (len(distances), len(coefficients)). """ # initializes the jacobian matrix @@ -33,16 +33,18 @@ def calculate_jacobian_matrix(distances: ndarray, coefficients: ndarray) -> ndar perturbed_coefficients: ndarray = array(coefficients, dtype=float) perturbed_coefficients[i] += epsilon # slightly disturb the current coefficient - # Compute the disturbed and original polynomial values at the given times - perturbed_function: ndarray = polynomial_sum_at_measuring_distances( + # Compute the disturbed and original polynomial values at the given distances + perturbed_function: ndarray = evaluate_polynomial_at_measuring_distances( distances, perturbed_coefficients ) - original_function: ndarray = polynomial_sum_at_measuring_distances( + original_function: ndarray = evaluate_polynomial_at_measuring_distances( distances, coefficients ) # Calculate the partial derivative coefficients and store it in the # Jacobian matrix + # jacobian_matrix[:, i] selects the entire column i of the jacobian matrix + # The colon (:) indicates all rows and i specifies the column jacobian_matrix[:, i] = (perturbed_function - original_function) / epsilon return jacobian_matrix @@ -63,16 +65,13 @@ def calculate_covariance_matrix( ndarray: The computed covariance matrix for the polynomial coefficients. """ - # Compute the Jacobian matrix for the polynomial jacobian_matrix: ndarray = calculate_jacobian_matrix(distances, coefficients) # Construct the weight matrix from the inverse squared errors weight_matrix: ndarray = diag(1 / power(delta_shifted_intensities, 2)) - # Compute the fit matrix fit_matrix: ndarray = jacobian_matrix.T @ weight_matrix @ jacobian_matrix - # Invert the fit matrix to get the covariance matrix covariance_matrix: ndarray = linalg.inv(fit_matrix) return covariance_matrix @@ -98,19 +97,18 @@ def calculate_error_propagation_terms( taufactor (float): Scaling factor related to the Doppler-shift model. Returns: - ndarray: The combined error propagation terms for each time point. + ndarray: The combined error propagation terms for each distance point. """ - calculated_differentiated_polynomial_sum_at_measuring_times = ( - differentiated_polynomial_sum_at_measuring_distances( # noqa E501 + calculated_differentiated_polynomial_sum_at_measuring_distances = ( + evaluate_differentiated_polynomial_at_measuring_distances( # noqa E501 distances, coefficients, ) ) - # First summand: Contribution from unshifted intensity errors - first_summand: ndarray = power(delta_unshifted_intensities, 2) / power( - calculated_differentiated_polynomial_sum_at_measuring_times, + gaussian_error_from_unshifted_intensity: ndarray = power(delta_unshifted_intensities, 2) / power( + calculated_differentiated_polynomial_sum_at_measuring_distances, 2, ) @@ -128,21 +126,19 @@ def calculate_error_propagation_terms( + power(distances, k) * power(distances, l) * covariance_matrix[k, l] ) - # Second summand: Contribution from polynomial uncertainties - second_summand: ndarray = ( + gaussian_error_from_polynomial_uncertainties: ndarray = ( power(unshifted_intensities, 2) / power( - calculated_differentiated_polynomial_sum_at_measuring_times, + calculated_differentiated_polynomial_sum_at_measuring_distances, 4, ) ) * power(delta_p_j_i_squared, 2) - # Third summand: Mixed covariance contribution - third_summand: ndarray = ( + error_from_covariance: ndarray = ( unshifted_intensities * taufactor * delta_p_j_i_squared - ) / power(calculated_differentiated_polynomial_sum_at_measuring_times, 3) + ) / power(calculated_differentiated_polynomial_sum_at_measuring_distances, 3) + test = gaussian_error_from_unshifted_intensity + gaussian_error_from_polynomial_uncertainties + res = test + error_from_covariance # Return the sum of all three contributions - result: ndarray = first_summand + second_summand + third_summand - - return result + return res diff --git a/napytau/core/logic_mockup.py b/napytau/core/logic_mockup.py deleted file mode 100644 index 4c32253..0000000 --- a/napytau/core/logic_mockup.py +++ /dev/null @@ -1,5 +0,0 @@ -def logic(value: int) -> int: - if value > 10: - return value**2 - else: - return value**3 diff --git a/napytau/core/polynomials.py b/napytau/core/polynomials.py index 9f84728..62a8fd7 100644 --- a/napytau/core/polynomials.py +++ b/napytau/core/polynomials.py @@ -1,12 +1,10 @@ from numpy import ndarray -from numpy import array from numpy import power -from numpy import zeros from numpy import zeros_like -def polynomial_sum_at_measuring_distances(distances: ndarray, - coefficients: ndarray) -> ndarray: +def evaluate_polynomial_at_measuring_distances(distances: ndarray, + coefficients: ndarray) -> ndarray: """ Computes the sum of a polynomial evaluated at given distance points. @@ -21,18 +19,18 @@ def polynomial_sum_at_measuring_distances(distances: ndarray, ndarray: Array of polynomial values evaluated at the given distance points. """ - # If no coefficients are provided, return a ndarray of zeros if len(coefficients) == 0: - return zeros(array(len(distances)), dtype=float) + return zeros_like(distances) # Evaluate the polynomial sum at the given time points - result: ndarray = zeros_like(distances) - for i, c in enumerate(coefficients): - result += c * power(distances, i) - return result + sum_at_measuring_distances: ndarray = zeros_like(distances) + for exponent, coefficient in enumerate(coefficients): + sum_at_measuring_distances += coefficient * power(distances, exponent) + return sum_at_measuring_distances -def differentiated_polynomial_sum_at_measuring_distances( + +def evaluate_differentiated_polynomial_at_measuring_distances( distances: ndarray, coefficients: ndarray ) -> ndarray: """ @@ -50,8 +48,9 @@ def differentiated_polynomial_sum_at_measuring_distances( ndarray: Array of the derivative values of the polynomial at the given distance points. """ - result: ndarray = zeros_like(distances) - for i, c in enumerate(coefficients): - if i > 0: - result += i * c * power(distances, (i - 1)) - return result + sum_of_derivative_at_measuring_distances: ndarray = zeros_like(distances) + for exponent, coefficient in enumerate(coefficients): + if exponent > 0: + sum_of_derivative_at_measuring_distances += exponent * coefficient * power(distances, (exponent - 1)) + + return sum_of_derivative_at_measuring_distances diff --git a/napytau/core/tau.py b/napytau/core/tau.py index 0bac65c..6488780 100644 --- a/napytau/core/tau.py +++ b/napytau/core/tau.py @@ -1,11 +1,11 @@ from napytau.core.chi import optimize_t_hyp from napytau.core.chi import optimize_coefficients -from napytau.core.polynomials import differentiated_polynomial_sum_at_measuring_distances # noqa E501 +from napytau.core.polynomials import evaluate_differentiated_polynomial_at_measuring_distances # noqa E501 from numpy import ndarray from typing import Tuple, Optional -def calculate_tau_i( +def calculate_tau_i_values( doppler_shifted_intensities: ndarray, unshifted_intensities: ndarray, delta_doppler_shifted_intensities: ndarray, @@ -70,11 +70,11 @@ def calculate_tau_i( )[0] # calculate decay times using the optimized coefficients - tau_i: ndarray = ( + tau_i_values: ndarray = ( unshifted_intensities - / differentiated_polynomial_sum_at_measuring_distances( + / evaluate_differentiated_polynomial_at_measuring_distances( distances, optimized_coefficients ) ) - return tau_i + return tau_i_values diff --git a/tests/core/chi_test.py b/tests/core/chi_test.py index 57a7f6b..e0286a7 100644 --- a/tests/core/chi_test.py +++ b/tests/core/chi_test.py @@ -5,6 +5,7 @@ from numpy import testing from numpy import mean from scipy.optimize import OptimizeResult +from typing import Tuple def set_up_mocks() -> (MagicMock, MagicMock, MagicMock): @@ -24,19 +25,19 @@ def set_up_mocks() -> (MagicMock, MagicMock, MagicMock): class ChiUnitTest(unittest.TestCase): - def test_ChiCalculationForValidData(self): + def test_CanCalculateChiForValidData(self): + """Can calculate chi for valid data""" polynomials_mock, numpy_module_mock, scipy_optimize_module_mock = set_up_mocks() # Mocked return values of called functions - polynomials_mock.polynomial_sum_at_measuring_distances.return_value = array( - [5, 15, 57] - ) - polynomials_mock.differentiated_polynomial_sum_at_measuring_distances.return_value = array( - [4, 20, 72] - ) + polynomials_mock.evaluate_polynomial_at_measuring_distances\ + .return_value = array([5, 15, 57]) + polynomials_mock.evaluate_differentiated_polynomial_at_measuring_distances\ + .return_value = array([4, 20, 72]) - numpy_module_mock.sum.return_value = - numpy_module_mock.power.side_effect = [] + numpy_module_mock.sum.return_value = 628.3486168 + numpy_module_mock.power.side_effect = [array([4, 18.77777778, 182.25]), + array([0.64, 34.02777778, 388.65306122])] with patch.dict( "sys.modules", @@ -75,57 +76,102 @@ def test_ChiCalculationForValidData(self): ) self.assertEqual( - len(polynomials_mock.polynomial_sum_at_measuring_distances.mock_calls), 1 + len(polynomials_mock.evaluate_polynomial_at_measuring_distances.mock_calls), 1 ) testing.assert_array_equal( - polynomials_mock.polynomial_sum_at_measuring_distances.mock_calls[0].args[ - 0 - ], + polynomials_mock.evaluate_polynomial_at_measuring_distances + .mock_calls[0].args[0], (array([0, 1, 2])), ) testing.assert_array_equal( - polynomials_mock.polynomial_sum_at_measuring_distances.mock_calls[0].args[ - 1 - ], + polynomials_mock.evaluate_polynomial_at_measuring_distances + .mock_calls[0].args[1], (array([5, 4, 3, 2, 1])), ) self.assertEqual( len( - polynomials_mock.differentiated_polynomial_sum_at_measuring_distances.mock_calls + polynomials_mock.evaluate_differentiated_polynomial_at_measuring_distances.mock_calls ), 1, ) testing.assert_array_equal( - polynomials_mock.differentiated_polynomial_sum_at_measuring_distances.mock_calls[ - 0 - ].args[0], + polynomials_mock.evaluate_differentiated_polynomial_at_measuring_distances + .mock_calls[0].args[0], (array([0, 1, 2])), ) testing.assert_array_equal( - polynomials_mock.differentiated_polynomial_sum_at_measuring_distances.mock_calls[ - 0 - ].args[1], + polynomials_mock.evaluate_differentiated_polynomial_at_measuring_distances + .mock_calls[0].args[1], (array([5, 4, 3, 2, 1])), ) - def test_ChiCalculationForEmptyDataArrays(self): + self.assertEqual( + len( + numpy_module_mock.sum.mock_calls + ), + 1, + ) + + testing.assert_array_almost_equal( + numpy_module_mock.sum + .mock_calls[0].args[0], + (array([4.64, 52.80555556, 570.90306122])), + ) + + self.assertEqual( + len( + numpy_module_mock.power.mock_calls + ), + 2, + ) + + testing.assert_array_almost_equal( + numpy_module_mock.power + .mock_calls[0].args[0], + (array([-2, -4.33333333, -13.5])), + ) + + testing.assert_array_equal( + numpy_module_mock.power + .mock_calls[0].args[1], + 2, + ) + + testing.assert_array_almost_equal( + numpy_module_mock.power + .mock_calls[1].args[0], + (array([-0.8, -5.83333333, -19.71428571])), + ) + + testing.assert_array_equal( + numpy_module_mock.power + .mock_calls[1].args[1], + 2, + ) + + def test_CanHandleEmptyDataArraysForChiCalculation(self): + """Can handle empty data arrays for chi calculation""" polynomials_mock, numpy_module_mock, scipy_optimize_module_mock = set_up_mocks() # Mocked return values of called functions - polynomials_mock.polynomial_sum_at_measuring_distances.return_value = array([]) - polynomials_mock.differentiated_polynomial_sum_at_measuring_distances.return_value = array( - [] - ) + polynomials_mock.evaluate_polynomial_at_measuring_distances\ + .return_value = array([]) + polynomials_mock.evaluate_differentiated_polynomial_at_measuring_distances\ + .return_value = array([]) + + numpy_module_mock.sum.return_value = 0 + numpy_module_mock.power.side_effect = [array([]),array([])] with patch.dict( "sys.modules", { "napytau.core.polynomials": polynomials_mock, + "numpy": numpy_module_mock, }, ): from napytau.core.chi import chi_squared_fixed_t @@ -158,18 +204,18 @@ def test_ChiCalculationForEmptyDataArrays(self): ) self.assertEqual( - len(polynomials_mock.polynomial_sum_at_measuring_distances.mock_calls), 1 + len(polynomials_mock.evaluate_polynomial_at_measuring_distances.mock_calls), 1 ) testing.assert_array_equal( - polynomials_mock.polynomial_sum_at_measuring_distances.mock_calls[0].args[ + polynomials_mock.evaluate_polynomial_at_measuring_distances.mock_calls[0].args[ 0 ], (array([])), ) testing.assert_array_equal( - polynomials_mock.polynomial_sum_at_measuring_distances.mock_calls[0].args[ + polynomials_mock.evaluate_polynomial_at_measuring_distances.mock_calls[0].args[ 1 ], (array([])), @@ -177,38 +223,86 @@ def test_ChiCalculationForEmptyDataArrays(self): self.assertEqual( len( - polynomials_mock.differentiated_polynomial_sum_at_measuring_distances.mock_calls + polynomials_mock.evaluate_differentiated_polynomial_at_measuring_distances.mock_calls ), 1, ) testing.assert_array_equal( - polynomials_mock.differentiated_polynomial_sum_at_measuring_distances.mock_calls[ + polynomials_mock.evaluate_differentiated_polynomial_at_measuring_distances.mock_calls[ 0 ].args[0], (array([])), ) testing.assert_array_equal( - polynomials_mock.differentiated_polynomial_sum_at_measuring_distances.mock_calls[ + polynomials_mock.evaluate_differentiated_polynomial_at_measuring_distances.mock_calls[ 0 ].args[1], (array([])), ) - def test_ChiCalculationForSingleDatapoint(self): + self.assertEqual( + len( + numpy_module_mock.sum.mock_calls + ), + 1, + ) + + testing.assert_array_equal( + numpy_module_mock.sum + .mock_calls[0].args[0], + array([]), + ) + + self.assertEqual( + len( + numpy_module_mock.power.mock_calls + ), + 2, + ) + + testing.assert_array_equal( + numpy_module_mock.power + .mock_calls[0].args[0], + (array([])), + ) + + testing.assert_array_equal( + numpy_module_mock.power + .mock_calls[0].args[1], + 2, + ) + + testing.assert_array_equal( + numpy_module_mock.power + .mock_calls[1].args[0], + (array([])), + ) + + testing.assert_array_equal( + numpy_module_mock.power + .mock_calls[1].args[1], + 2, + ) + + def test_CanCalculateChiForSingleDatapoint(self): + """Can calculate chi for single datapoint""" polynomials_mock, numpy_module_mock, scipy_optimize_module_mock = set_up_mocks() # Mocked return values of called functions - polynomials_mock.polynomial_sum_at_measuring_distances.return_value = array([57]) - polynomials_mock.differentiated_polynomial_sum_at_measuring_distances.return_value = array( - [72] - ) + polynomials_mock.evaluate_polynomial_at_measuring_distances.return_value = array([57]) + polynomials_mock.evaluate_differentiated_polynomial_at_measuring_distances\ + .return_value = array([72]) + + numpy_module_mock.sum.return_value = 1608.69444444 + numpy_module_mock.power.side_effect = [array([348.44444444]), array([1260.25])] with patch.dict( "sys.modules", { "napytau.core.polynomials": polynomials_mock, + "numpy": numpy_module_mock, }, ): from napytau.core.chi import chi_squared_fixed_t @@ -224,7 +318,7 @@ def test_ChiCalculationForSingleDatapoint(self): weight_factor: float = 1.0 # Expected result - expected_result: float = 1608.694444444444 + expected_result: float = 1608.69444444 self.assertAlmostEqual( chi_squared_fixed_t( @@ -241,18 +335,18 @@ def test_ChiCalculationForSingleDatapoint(self): ) self.assertEqual( - len(polynomials_mock.polynomial_sum_at_measuring_distances.mock_calls), 1 + len(polynomials_mock.evaluate_polynomial_at_measuring_distances.mock_calls), 1 ) testing.assert_array_equal( - polynomials_mock.polynomial_sum_at_measuring_distances.mock_calls[0].args[ + polynomials_mock.evaluate_polynomial_at_measuring_distances.mock_calls[0].args[ 0 ], (array([2])), ) testing.assert_array_equal( - polynomials_mock.polynomial_sum_at_measuring_distances.mock_calls[0].args[ + polynomials_mock.evaluate_polynomial_at_measuring_distances.mock_calls[0].args[ 1 ], (array([5, 4, 3, 2, 1])), @@ -260,38 +354,88 @@ def test_ChiCalculationForSingleDatapoint(self): self.assertEqual( len( - polynomials_mock.differentiated_polynomial_sum_at_measuring_distances.mock_calls + polynomials_mock.evaluate_differentiated_polynomial_at_measuring_distances.mock_calls ), 1, ) testing.assert_array_equal( - polynomials_mock.differentiated_polynomial_sum_at_measuring_distances.mock_calls[ + polynomials_mock.evaluate_differentiated_polynomial_at_measuring_distances.mock_calls[ 0 ].args[0], (array([2])), ) testing.assert_array_equal( - polynomials_mock.differentiated_polynomial_sum_at_measuring_distances.mock_calls[ + polynomials_mock.evaluate_differentiated_polynomial_at_measuring_distances.mock_calls[ 0 ].args[1], (array([5, 4, 3, 2, 1])), ) - def test_ChiCalculationForDenominatorZero(self): + self.assertEqual( + len( + numpy_module_mock.sum.mock_calls + ), + 1, + ) + + testing.assert_array_almost_equal( + numpy_module_mock.sum + .mock_calls[0].args[0], + (array([1608.69444444])), + ) + + self.assertEqual( + len( + numpy_module_mock.power.mock_calls + ), + 2, + ) + + testing.assert_array_almost_equal( + numpy_module_mock.power + .mock_calls[0].args[0], + (array([-18.66666667])), + ) + + testing.assert_array_equal( + numpy_module_mock.power + .mock_calls[0].args[1], + 2, + ) + + testing.assert_array_almost_equal( + numpy_module_mock.power + .mock_calls[1].args[0], + (array([-35.5])), + ) + + testing.assert_array_equal( + numpy_module_mock.power + .mock_calls[1].args[1], + 2, + ) + + def test_CanCalculateChiIfDenominatorIsZero(self): + """Can calculate chi if denominator is zero.""" polynomials_mock, numpy_module_mock, scipy_optimize_module_mock = set_up_mocks() # Mocked return values of called functions - polynomials_mock.polynomial_sum_at_measuring_distances.return_value = array([5, 15]) - polynomials_mock.differentiated_polynomial_sum_at_measuring_distances.return_value = array( - [4, 20] - ) + polynomials_mock.evaluate_polynomial_at_measuring_distances\ + .return_value = array([5, 15]) + polynomials_mock.evaluate_differentiated_polynomial_at_measuring_distances\ + .return_value = array([4, 20]) + + numpy_module_mock.sum.return_value = float("inf") + numpy_module_mock.power.side_effect = [array([float("inf"), 169]), + array([float("inf"), 1296])] with patch.dict( "sys.modules", { "napytau.core.polynomials": polynomials_mock, + "numpy": numpy_module_mock, }, ): from napytau.core.chi import chi_squared_fixed_t @@ -324,59 +468,103 @@ def test_ChiCalculationForDenominatorZero(self): ) self.assertEqual( - len(polynomials_mock.polynomial_sum_at_measuring_distances.mock_calls), 1 + len(polynomials_mock.evaluate_polynomial_at_measuring_distances.mock_calls), 1 ) testing.assert_array_equal( - polynomials_mock.polynomial_sum_at_measuring_distances.mock_calls[0].args[ - 0 - ], + polynomials_mock.evaluate_polynomial_at_measuring_distances + .mock_calls[0].args[0], (array([0, 1])), ) testing.assert_array_equal( - polynomials_mock.polynomial_sum_at_measuring_distances.mock_calls[0].args[ - 1 - ], + polynomials_mock.evaluate_polynomial_at_measuring_distances + .mock_calls[0].args[1], (array([5, 4, 3, 2, 1])), ) self.assertEqual( len( - polynomials_mock.differentiated_polynomial_sum_at_measuring_distances.mock_calls + polynomials_mock.evaluate_differentiated_polynomial_at_measuring_distances.mock_calls ), 1, ) testing.assert_array_equal( - polynomials_mock.differentiated_polynomial_sum_at_measuring_distances.mock_calls[ - 0 - ].args[0], + polynomials_mock.evaluate_differentiated_polynomial_at_measuring_distances + .mock_calls[0].args[0], (array([0, 1])), ) testing.assert_array_equal( - polynomials_mock.differentiated_polynomial_sum_at_measuring_distances.mock_calls[ - 0 - ].args[1], - (array([5, 4, 3, 2, 1])), + polynomials_mock.evaluate_differentiated_polynomial_at_measuring_distances + .mock_calls[0].args[1], + (array([5, 4, 3, 2, 1])) + ) + + self.assertEqual( + len( + numpy_module_mock.sum.mock_calls + ), + 1, + ) + + testing.assert_array_equal( + numpy_module_mock.sum + .mock_calls[0].args[0], + (array([float("inf"), 1465])), + ) + + self.assertEqual( + len( + numpy_module_mock.power.mock_calls + ), + 2, + ) + + testing.assert_array_equal( + numpy_module_mock.power + .mock_calls[0].args[0], + (array([-float("inf"), -13])), + ) + + testing.assert_array_equal( + numpy_module_mock.power + .mock_calls[0].args[1], + 2, + ) + + testing.assert_array_equal( + numpy_module_mock.power + .mock_calls[1].args[0], + (array([-float("inf"), -36])), ) - def test_ChiCalculationForNegativeValues(self): + testing.assert_array_equal( + numpy_module_mock.power + .mock_calls[1].args[1], + 2, + ) + + def test_CanCalculateChiForNegativeValues(self): + """Can calculate chi for negative values""" polynomials_mock, numpy_module_mock, scipy_optimize_module_mock = set_up_mocks() # Mocked return values of called functions - polynomials_mock.polynomial_sum_at_measuring_distances.return_value = array( - [-5, -5] - ) - polynomials_mock.differentiated_polynomial_sum_at_measuring_distances.return_value = array( - [-4, -4] - ) + polynomials_mock.evaluate_polynomial_at_measuring_distances\ + .return_value = array([-5, -5]) + polynomials_mock.evaluate_differentiated_polynomial_at_measuring_distances\ + .return_value = array([-4, -4]) + + numpy_module_mock.sum.return_value = 22.02777778 + numpy_module_mock.power.side_effect = [array([16, 2.25]), + array([2.77777778, 1])] with patch.dict( "sys.modules", { "napytau.core.polynomials": polynomials_mock, + "numpy": numpy_module_mock, }, ): from napytau.core.chi import chi_squared_fixed_t @@ -409,59 +597,103 @@ def test_ChiCalculationForNegativeValues(self): ) self.assertEqual( - len(polynomials_mock.polynomial_sum_at_measuring_distances.mock_calls), 1 + len(polynomials_mock.evaluate_polynomial_at_measuring_distances.mock_calls), 1 ) testing.assert_array_equal( - polynomials_mock.polynomial_sum_at_measuring_distances.mock_calls[0].args[ - 0 - ], + polynomials_mock.evaluate_polynomial_at_measuring_distances + .mock_calls[0].args[0], (array([0, 1])), ) testing.assert_array_equal( - polynomials_mock.polynomial_sum_at_measuring_distances.mock_calls[0].args[ - 1 - ], + polynomials_mock.evaluate_polynomial_at_measuring_distances + .mock_calls[0].args[1], (array([-5, -4, 3, 2, -1])), ) self.assertEqual( len( - polynomials_mock.differentiated_polynomial_sum_at_measuring_distances.mock_calls + polynomials_mock.evaluate_differentiated_polynomial_at_measuring_distances.mock_calls ), 1, ) testing.assert_array_equal( - polynomials_mock.differentiated_polynomial_sum_at_measuring_distances.mock_calls[ - 0 - ].args[0], + polynomials_mock.evaluate_differentiated_polynomial_at_measuring_distances + .mock_calls[0].args[0], (array([0, 1])), ) testing.assert_array_equal( - polynomials_mock.differentiated_polynomial_sum_at_measuring_distances.mock_calls[ - 0 - ].args[1], + polynomials_mock.evaluate_differentiated_polynomial_at_measuring_distances + .mock_calls[0].args[1], (array([-5, -4, 3, 2, -1])), ) - def test_ChiCalculationForWeightFactorZero(self): + self.assertEqual( + len( + numpy_module_mock.sum.mock_calls + ), + 1, + ) + + testing.assert_array_almost_equal( + numpy_module_mock.sum + .mock_calls[0].args[0], + (array([18.77777778, 3.25])), + ) + + self.assertEqual( + len( + numpy_module_mock.power.mock_calls + ), + 2, + ) + + testing.assert_array_almost_equal( + numpy_module_mock.power + .mock_calls[0].args[0], + (array([4, 1.5])), + ) + + testing.assert_array_equal( + numpy_module_mock.power + .mock_calls[0].args[1], + 2, + ) + + testing.assert_array_almost_equal( + numpy_module_mock.power + .mock_calls[1].args[0], + (array([1.66666667, 1])), + ) + + testing.assert_array_equal( + numpy_module_mock.power + .mock_calls[1].args[1], + 2, + ) + + def test_CanCalculateChiForWeightFactorZero(self): + """Can calculate chi for weight factor zero""" polynomials_mock, numpy_module_mock, scipy_optimize_module_mock = set_up_mocks() # Mocked return values of called functions - polynomials_mock.polynomial_sum_at_measuring_distances.return_value = array( - [5, 15, 57] - ) - polynomials_mock.differentiated_polynomial_sum_at_measuring_distances.return_value = array( - [4, 20, 72] - ) + polynomials_mock.evaluate_polynomial_at_measuring_distances\ + .return_value = array([5, 15, 57]) + polynomials_mock.evaluate_differentiated_polynomial_at_measuring_distances\ + .return_value = array([4, 20, 72]) + + numpy_module_mock.sum.return_value = 205.02777778 + numpy_module_mock.power.side_effect = [array([4, 18.77777778, 182.25]), + array([0.64, 34.02777778, 388.65306122])] with patch.dict( "sys.modules", { "napytau.core.polynomials": polynomials_mock, + "numpy": numpy_module_mock, }, ): from napytau.core.chi import chi_squared_fixed_t @@ -477,7 +709,7 @@ def test_ChiCalculationForWeightFactorZero(self): weight_factor: float = 0.0 # Expected result - expected_result: float = 205.0277778 + expected_result: float = 205.02777778 self.assertAlmostEqual( chi_squared_fixed_t( @@ -494,18 +726,18 @@ def test_ChiCalculationForWeightFactorZero(self): ) self.assertEqual( - len(polynomials_mock.polynomial_sum_at_measuring_distances.mock_calls), 1 + len(polynomials_mock.evaluate_polynomial_at_measuring_distances.mock_calls), 1 ) testing.assert_array_equal( - polynomials_mock.polynomial_sum_at_measuring_distances.mock_calls[0].args[ + polynomials_mock.evaluate_polynomial_at_measuring_distances.mock_calls[0].args[ 0 ], (array([0, 1, 2])), ) testing.assert_array_equal( - polynomials_mock.polynomial_sum_at_measuring_distances.mock_calls[0].args[ + polynomials_mock.evaluate_polynomial_at_measuring_distances.mock_calls[0].args[ 1 ], (array([5, 4, 3, 2, 1])), @@ -513,26 +745,71 @@ def test_ChiCalculationForWeightFactorZero(self): self.assertEqual( len( - polynomials_mock.differentiated_polynomial_sum_at_measuring_distances.mock_calls + polynomials_mock.evaluate_differentiated_polynomial_at_measuring_distances.mock_calls ), 1, ) testing.assert_array_equal( - polynomials_mock.differentiated_polynomial_sum_at_measuring_distances.mock_calls[ + polynomials_mock.evaluate_differentiated_polynomial_at_measuring_distances.mock_calls[ 0 ].args[0], (array([0, 1, 2])), ) testing.assert_array_equal( - polynomials_mock.differentiated_polynomial_sum_at_measuring_distances.mock_calls[ + polynomials_mock.evaluate_differentiated_polynomial_at_measuring_distances.mock_calls[ 0 ].args[1], (array([5, 4, 3, 2, 1])), ) - def test_coefficientOptimization(self): + self.assertEqual( + len( + numpy_module_mock.sum.mock_calls + ), + 1, + ) + + testing.assert_array_equal( + numpy_module_mock.sum + .mock_calls[0].args[0], + (array([4, 18.77777778, 182.25])), + ) + + self.assertEqual( + len( + numpy_module_mock.power.mock_calls + ), + 2, + ) + + testing.assert_array_almost_equal( + numpy_module_mock.power + .mock_calls[0].args[0], + (array([-2, -4.33333333, -13.5])), + ) + + testing.assert_array_equal( + numpy_module_mock.power + .mock_calls[0].args[1], + 2, + ) + + testing.assert_array_almost_equal( + numpy_module_mock.power + .mock_calls[1].args[0], + (array([-0.8, -5.83333333, -19.71428571])), + ) + + testing.assert_array_equal( + numpy_module_mock.power + .mock_calls[1].args[1], + 2, + ) + + def test_CanOptimizePolynomialCoefficients(self): + """Can optimize polynomial coefficients""" polynomials_mock, numpy_module_mock, scipy_optimize_module_mock = set_up_mocks() # Mocked return value of called function @@ -578,7 +855,6 @@ def test_coefficientOptimization(self): self.assertEqual(actual_chi, expected_chi) testing.assert_array_equal(actual_coefficients, expected_coefficients) - self.assertEqual(len(scipy_optimize_module_mock.minimize.mock_calls), 1) self.assertEqual(len(scipy_optimize_module_mock.minimize.mock_calls), 1) testing.assert_array_equal( @@ -591,16 +867,20 @@ def test_coefficientOptimization(self): "L-BFGS-B", ) - def test_tHypOptimization(self): + def test_CanOptimizeTHypValue(self): + """Can optimize t_hyp value""" polynomials_mock, numpy_module_mock, scipy_optimize_module_mock = set_up_mocks() - # Mocked return value of called function + # Mocked return values of called functions scipy_optimize_module_mock.minimize.return_value = OptimizeResult(x=2.0) + numpy_module_mock.mean.return_value = 0 + with patch.dict( "sys.modules", { "scipy.optimize": scipy_optimize_module_mock, + "numpy": numpy_module_mock, }, ): from napytau.core.chi import optimize_t_hyp @@ -612,7 +892,7 @@ def test_tHypOptimization(self): delta_unshifted_intensities: ndarray = array([1, 1]) initial_coefficients: ndarray = array([1, 1, 1]) distances: ndarray = array([0, 1]) - t_hyp_range: (float, float) = (-5, 5) + t_hyp_range: Tuple[float, float] = (-5, 5) weight_factor: float = 1.0 # Expected result @@ -647,3 +927,9 @@ def test_tHypOptimization(self): scipy_optimize_module_mock.minimize.mock_calls[0].kwargs["bounds"], [(t_hyp_range[0], t_hyp_range[1])], ) + + self.assertEqual(len(numpy_module_mock.mean.mock_calls), 1) + + self.assertEqual( + numpy_module_mock.mean.mock_calls[0].args[0], (-5, 5) + ) diff --git a/tests/core/core_test.py b/tests/core/core_test.py new file mode 100644 index 0000000..70d0c87 --- /dev/null +++ b/tests/core/core_test.py @@ -0,0 +1,210 @@ +import unittest +from unittest.mock import MagicMock, patch +import numpy as np +from typing import Tuple, Optional + + +def set_up_mocks() -> (MagicMock, MagicMock, MagicMock, MagicMock): + chi_mock = MagicMock() + chi_mock.optimize_t_hyp = MagicMock() + chi_mock.optimize_coefficients = MagicMock() + + tau_mock = MagicMock() + tau_mock.calculate_tau_i_values = MagicMock() + + delta_tau_mock = MagicMock() + delta_tau_mock.calculate_error_propagation_terms = MagicMock() + + tau_final_mock = MagicMock() + tau_final_mock.calculate_tau_final = MagicMock() + + return chi_mock, tau_mock, delta_tau_mock, tau_final_mock + + +class CoreUnitTest(unittest.TestCase): + def test_CanCalculateLifetime(self): + """Can calculate lifetime""" + chi_mock, tau_mock, delta_tau_mock, tau_final_mock = set_up_mocks() + + # Mocked return values of called functions + chi_mock.optimize_t_hyp.return_value = 2.0 + chi_mock.optimize_coefficients.return_value = (np.array([2, 3, 1]), 2.0) + + tau_mock.calculate_tau_i_values.return_value = np.array([3, 1.66666667]) + + delta_tau_mock.calculate_error_propagation_terms.return_value = np.array([0.6, 0.2]) + + tau_final_mock.calculate_tau_final.return_value = (1.8, 0.18973666) + + with patch.dict( + "sys.modules", + { + "napytau.core.chi": chi_mock, + "napytau.core.tau": tau_mock, + "napytau.core.delta_tau": delta_tau_mock, + "napytau.core.tau_final": tau_final_mock, + }, + ): + from napytau.core.core import calculate_lifetime + + # Mocked input data + doppler_shifted_intensities: np.ndarray = np.array([2, 6]) + unshifted_intensities: np.ndarray = np.array([6, 10]) + delta_doppler_shifted_intensities: np.ndarray = np.array([1, 1]) + delta_unshifted_intensities: np.ndarray = np.array([1, 1]) + initial_coefficients: np.ndarray = np.array([1, 1, 1]) + distances: np.ndarray = np.array([0, 1]) + t_hyp_range: Tuple[float, float] = (-5, 5) + weight_factor: float = 1.0 + custom_t_hyp_estimate: Optional[float] = None + + actual_result: Tuple[float, float] = calculate_lifetime( + doppler_shifted_intensities, + unshifted_intensities, + delta_doppler_shifted_intensities, + delta_unshifted_intensities, + initial_coefficients, + distances, + t_hyp_range, + weight_factor, + custom_t_hyp_estimate) + + self.assertAlmostEqual(actual_result[0],1.8) + + self.assertAlmostEqual(actual_result[1],0.18973666) + + self.assertEqual(len(chi_mock.optimize_t_hyp.mock_calls), 1) + + np.testing.assert_array_equal(chi_mock.optimize_t_hyp.mock_calls[0].args[0], + np.array([2, 6])) + + np.testing.assert_array_equal(chi_mock.optimize_t_hyp.mock_calls[0].args[1], + np.array([6, 10])) + + np.testing.assert_array_equal(chi_mock.optimize_t_hyp.mock_calls[0].args[2], + np.array([1, 1])) + + np.testing.assert_array_equal(chi_mock.optimize_t_hyp.mock_calls[0].args[3], + np.array([1, 1])) + + np.testing.assert_array_equal(chi_mock.optimize_t_hyp.mock_calls[0].args[4], + np.array([1, 1, 1])) + + np.testing.assert_array_equal(chi_mock.optimize_t_hyp.mock_calls[0].args[5], + np.array([0, 1])) + + self.assertEqual(chi_mock.optimize_t_hyp.mock_calls[0].args[6], + (-5, 5)) + + self.assertEqual(chi_mock.optimize_t_hyp.mock_calls[0].args[7], + 1.0) + + self.assertEqual(len(chi_mock.optimize_coefficients.mock_calls), 1) + + np.testing.assert_array_equal( + chi_mock.optimize_coefficients.mock_calls[0].args[0], + np.array([2, 6]) + ) + + np.testing.assert_array_equal( + chi_mock.optimize_coefficients.mock_calls[0].args[1], + np.array([6, 10]) + ) + + np.testing.assert_array_equal( + chi_mock.optimize_coefficients.mock_calls[0].args[2], + np.array([1, 1]) + ) + + np.testing.assert_array_equal( + chi_mock.optimize_coefficients.mock_calls[0].args[3], + np.array([1, 1]) + ) + + np.testing.assert_array_equal( + chi_mock.optimize_coefficients.mock_calls[0].args[4], + np.array([1, 1, 1]) + ) + + np.testing.assert_array_equal( + chi_mock.optimize_coefficients.mock_calls[0].args[5], + np.array([0, 1]) + ) + + self.assertEqual( + chi_mock.optimize_coefficients.mock_calls[0].args[6], + 2.0 + ) + + self.assertEqual( + chi_mock.optimize_coefficients.mock_calls[0].args[7], + 1.0 + ) + + self.assertEqual(len(tau_mock.calculate_tau_i_values.mock_calls), 1) + + np.testing.assert_array_equal(tau_mock.calculate_tau_i_values.mock_calls[0].args[0], + np.array([2, 6])) + + np.testing.assert_array_equal(tau_mock.calculate_tau_i_values.mock_calls[0].args[1], + np.array([6, 10])) + + np.testing.assert_array_equal(tau_mock.calculate_tau_i_values.mock_calls[0].args[2], + np.array([1, 1])) + + np.testing.assert_array_equal(tau_mock.calculate_tau_i_values.mock_calls[0].args[3], + np.array([1, 1])) + + np.testing.assert_array_equal(tau_mock.calculate_tau_i_values.mock_calls[0].args[4], + np.array([1, 1, 1])) + + np.testing.assert_array_equal(tau_mock.calculate_tau_i_values.mock_calls[0].args[5], + np.array([0, 1])) + + self.assertEqual(tau_mock.calculate_tau_i_values.mock_calls[0].args[6], + (-5, 5)) + + self.assertEqual(tau_mock.calculate_tau_i_values.mock_calls[0].args[7], + 1.0) + + self.assertEqual(tau_mock.calculate_tau_i_values.mock_calls[0].args[8], + None) + + self.assertEqual(len(delta_tau_mock.calculate_error_propagation_terms.mock_calls), 1) + + np.testing.assert_array_equal( + delta_tau_mock.calculate_error_propagation_terms.mock_calls[0].args[0], + np.array([6, 10])) + + np.testing.assert_array_equal( + delta_tau_mock.calculate_error_propagation_terms.mock_calls[0].args[1], + np.array([1, 1])) + + np.testing.assert_array_equal( + delta_tau_mock.calculate_error_propagation_terms.mock_calls[0].args[2], + np.array([1, 1])) + + np.testing.assert_array_equal( + delta_tau_mock.calculate_error_propagation_terms.mock_calls[0].args[3], + np.array([0, 1])) + + np.testing.assert_array_equal( + delta_tau_mock.calculate_error_propagation_terms.mock_calls[0].args[4], + np.array([2, 3, 1])) + + self.assertEqual( + delta_tau_mock.calculate_error_propagation_terms.mock_calls[0].args[5], + 2.0 + ) + + self.assertEqual(len(tau_final_mock.calculate_tau_final.mock_calls), 1) + + np.testing.assert_array_equal( + tau_final_mock.calculate_tau_final.mock_calls[0].args[0], + np.array([3, 1.66666667]) + ) + + np.testing.assert_array_equal( + tau_final_mock.calculate_tau_final.mock_calls[0].args[1], + np.array([0.6, 0.2]) + ) diff --git a/tests/core/delta_tau_test.py b/tests/core/delta_tau_test.py index 62a0a97..4ba62b4 100644 --- a/tests/core/delta_tau_test.py +++ b/tests/core/delta_tau_test.py @@ -27,11 +27,11 @@ def set_up_mocks() -> (MagicMock, MagicMock, MagicMock, MagicMock): class DeltaChiUnitTests(unittest.TestCase): @staticmethod def test_canCalculateJacobianMatrixOutOfTimesAndCoefficients(): - """ " Can calculate Jacobian matrix out of distances and coefficients.""" + """Can calculate Jacobian matrix out of distances and coefficients.""" polynomial_module_mock, zeros_mock, numpy_module_mock = set_up_mocks() zeros_mock.return_value = np.array([[0, 0], [0, 0], [0, 0]]) - polynomial_module_mock.polynomial_sum_at_measuring_distances.side_effect = [ + polynomial_module_mock.evaluate_polynomial_at_measuring_distances.side_effect = [ 6, 3, 2, @@ -61,7 +61,7 @@ def test_canCalculateCovarianceMatrixOutOfJacobianMatrixAndWeightMatrix(self): polynomial_module_mock, zeros_mock, numpy_module_mock = set_up_mocks() zeros_mock.return_value = np.array([[0, 0], [0, 0], [0, 0]]) - polynomial_module_mock.polynomial_sum_at_measuring_distances.side_effect = [ + polynomial_module_mock.evaluate_polynomial_at_measuring_distances.side_effect = [ 6, 3, 2, @@ -99,54 +99,54 @@ def test_canCalculateCovarianceMatrixOutOfJacobianMatrixAndWeightMatrix(self): self.assertEqual( len( - polynomial_module_mock.polynomial_sum_at_measuring_distances.mock_calls + polynomial_module_mock.evaluate_polynomial_at_measuring_distances.mock_calls ), 4, ) np.testing.assert_array_equal( - polynomial_module_mock.polynomial_sum_at_measuring_distances.mock_calls[ + polynomial_module_mock.evaluate_polynomial_at_measuring_distances.mock_calls[ 0 ].args[0], np.array([0, 1, 2]), ) np.testing.assert_array_equal( - polynomial_module_mock.polynomial_sum_at_measuring_distances.mock_calls[ + polynomial_module_mock.evaluate_polynomial_at_measuring_distances.mock_calls[ 0 ].args[1], np.array([5 + 1e-8, 4]), ) np.testing.assert_array_equal( - polynomial_module_mock.polynomial_sum_at_measuring_distances.mock_calls[ + polynomial_module_mock.evaluate_polynomial_at_measuring_distances.mock_calls[ 1 ].args[0], np.array([0, 1, 2]), ) np.testing.assert_array_equal( - polynomial_module_mock.polynomial_sum_at_measuring_distances.mock_calls[ + polynomial_module_mock.evaluate_polynomial_at_measuring_distances.mock_calls[ 1 ].args[1], np.array([5, 4]), ) np.testing.assert_array_equal( - polynomial_module_mock.polynomial_sum_at_measuring_distances.mock_calls[ + polynomial_module_mock.evaluate_polynomial_at_measuring_distances.mock_calls[ 2 ].args[0], np.array([0, 1, 2]), ) np.testing.assert_array_equal( - polynomial_module_mock.polynomial_sum_at_measuring_distances.mock_calls[ + polynomial_module_mock.evaluate_polynomial_at_measuring_distances.mock_calls[ 2 ].args[1], np.array([5, 4 + 1e-8]), ) np.testing.assert_array_equal( - polynomial_module_mock.polynomial_sum_at_measuring_distances.mock_calls[ + polynomial_module_mock.evaluate_polynomial_at_measuring_distances.mock_calls[ 3 ].args[0], np.array([0, 1, 2]), ) np.testing.assert_array_equal( - polynomial_module_mock.polynomial_sum_at_measuring_distances.mock_calls[ + polynomial_module_mock.evaluate_polynomial_at_measuring_distances.mock_calls[ 3 ].args[1], np.array([5, 4]), @@ -172,7 +172,7 @@ def testCanCalculateErrorPropagation(self): np.array([0, 0, 0]), np.array([[0, 0], [0, 0], [0, 0]]), ] - polynomial_module_mock.polynomial_sum_at_measuring_distances.side_effect = [ + polynomial_module_mock.evaluate_polynomial_at_measuring_distances.side_effect = [ 6, 3, 2, @@ -204,7 +204,7 @@ def testCanCalculateErrorPropagation(self): np.array([64, 64, 64]), ] - polynomial_module_mock.differentiated_polynomial_sum_at_measuring_distances.return_value = np.array( + polynomial_module_mock.evaluate_differentiated_polynomial_at_measuring_distances.return_value = np.array( [4, 4, 4] ) @@ -238,13 +238,13 @@ def testCanCalculateErrorPropagation(self): ) np.testing.assert_array_equal( - polynomial_module_mock.differentiated_polynomial_sum_at_measuring_distances.mock_calls[ + polynomial_module_mock.evaluate_differentiated_polynomial_at_measuring_distances.mock_calls[ 0 ].args[0], np.array([0, 1, 2]), ) np.testing.assert_array_equal( - polynomial_module_mock.differentiated_polynomial_sum_at_measuring_distances.mock_calls[ + polynomial_module_mock.evaluate_differentiated_polynomial_at_measuring_distances.mock_calls[ 0 ].args[1], np.array([5, 4]), diff --git a/tests/core/polynomials_test.py b/tests/core/polynomials_test.py index 74bd5be..f330b51 100644 --- a/tests/core/polynomials_test.py +++ b/tests/core/polynomials_test.py @@ -1,129 +1,289 @@ import unittest -from napytau.core.polynomials import polynomial_sum_at_measuring_distances -from napytau.core.polynomials import differentiated_polynomial_sum_at_measuring_distances +from unittest.mock import MagicMock, patch + +from napytau.core.polynomials import evaluate_differentiated_polynomial_at_measuring_distances from numpy import ndarray from numpy import array from numpy import testing +def set_up_mocks() -> MagicMock: + numpy_module_mock = MagicMock() + numpy_module_mock.power = MagicMock() + numpy_module_mock.zeros_like = MagicMock() + + return numpy_module_mock + + class PolynomialsUnitTest(unittest.TestCase): @staticmethod - def test_CalculationForValidPolynomial(): - # Test for a simple quadratic polynomial: 2 + 3x + 4x^2 - distances: ndarray = array([1, 2, 3]) - coefficients: ndarray = array([2, 3, 4]) - # At x = 1: 2 + 3(1) + 4(1^2) = 9 - # At x = 2: 2 + 3(2) + 4(2^2) = 2 + 6 + 16 = 24 - # At x = 3: 2 + 3(3) + 4(3^2) = 2 + 9 + 36 = 47 - expected_result: ndarray = array([9, 24, 47]) - testing.assert_array_equal( - polynomial_sum_at_measuring_distances(distances, coefficients), expected_result - ) + def test_CanEvaluateAValidPolynomialAtMeasuringDistances(): + """Can evaluate a valid polynomial at measuring distances.""" + numpy_module_mock = set_up_mocks() + + # Mocked return values of called functions + numpy_module_mock.power.side_effect = [array([1, 1, 1]), array([1, 2, 3]), array([1, 4, 9])] + numpy_module_mock.zeros_like.return_value = array([0, 0, 0]) + + with patch.dict( + "sys.modules", + { + "numpy": numpy_module_mock, + }, + ): + from napytau.core.polynomials import evaluate_polynomial_at_measuring_distances + + # Test for a simple quadratic polynomial: 2 + 3x + 4x^2 + distances: ndarray = array([1, 2, 3]) + coefficients: ndarray = array([2, 3, 4]) + # At x = 1: 2 + 3(1) + 4(1^2) = 9 + # At x = 2: 2 + 3(2) + 4(2^2) = 2 + 6 + 16 = 24 + # At x = 3: 2 + 3(3) + 4(3^2) = 2 + 9 + 36 = 47 + expected_result: ndarray = array([9, 24, 47]) + testing.assert_array_equal( + evaluate_polynomial_at_measuring_distances(distances, coefficients), expected_result + ) @staticmethod - def test_CalculationForEmptyDistanceInput(): - distances: ndarray = array([]) - coefficients: ndarray = array([2, 3, 4]) - # With an empty input array, the result should also be an empty array - expected_result: ndarray = array([]) - testing.assert_array_equal( - polynomial_sum_at_measuring_distances(distances, coefficients), expected_result - ) + def test_CanEvaluateAPolynomialAtMeasuringDistancesForEmptyDistanceInput(): + """Can evaluate a polynomial at measuring distances for empty distances.""" + numpy_module_mock = set_up_mocks() + + # Mocked return values of called functions + numpy_module_mock.power.side_effect = [array([]), array([]), + array([])] + numpy_module_mock.zeros_like.return_value = array([]) + + with patch.dict( + "sys.modules", + { + "numpy": numpy_module_mock, + }, + ): + from napytau.core.polynomials import evaluate_polynomial_at_measuring_distances + + distances: ndarray = array([]) + coefficients: ndarray = array([2, 3, 4]) + # With an empty input array, the result should also be an empty array + expected_result: ndarray = array([]) + testing.assert_array_equal( + evaluate_polynomial_at_measuring_distances(distances, coefficients), expected_result + ) @staticmethod - def test_CalculationForSingleDistanceMeasurement(): - distances: ndarray = array([2]) - coefficients: ndarray = array([1, 2]) - # Polynomial: f(x) = 1 + 2x - # At x = 2: 1 + 2(2) = 5 - expected_result: ndarray = array([5]) - testing.assert_array_equal( - polynomial_sum_at_measuring_distances(distances, coefficients), expected_result - ) + def test_CanEvaluateAPolynomialAtMeasuringDistancesForSingleDistanceMeasurement(): + """Can evaluate a polynomial at measuring distances for single distance.""" + numpy_module_mock = set_up_mocks() + + # Mocked return values of called functions + numpy_module_mock.power.side_effect = [array([1]), array([2]), + array([4])] + numpy_module_mock.zeros_like.return_value = array([0]) + + with patch.dict( + "sys.modules", + { + "numpy": numpy_module_mock, + }, + ): + from napytau.core.polynomials import evaluate_polynomial_at_measuring_distances + + distances: ndarray = array([2]) + coefficients: ndarray = array([1, 2]) + # Polynomial: f(x) = 1 + 2x + # At x = 2: 1 + 2(2) = 5 + expected_result: ndarray = array([5]) + testing.assert_array_equal( + evaluate_polynomial_at_measuring_distances(distances, coefficients), expected_result + ) @staticmethod - def test_CalculationForSingleValuePolynomial(): - distances: ndarray = array([1, 2, 3]) - coefficients: ndarray = array([5]) - # Constant polynomial: f(x) = 5 - # All values should be 5 - expected_result: ndarray = array([5, 5, 5]) - testing.assert_array_equal( - polynomial_sum_at_measuring_distances(distances, coefficients), expected_result - ) + def test_CanEvaluateASingleValuePolynomialAtMeasuringDistances(): + """Can evaluate a single value polynomial at measuring distances.""" + numpy_module_mock = set_up_mocks() + + # Mocked return values of called functions + numpy_module_mock.power.side_effect = [array([1, 1, 1]), array([1, 2, 3]), + array([1, 4, 9])] + numpy_module_mock.zeros_like.return_value = array([0, 0, 0]) + + with patch.dict( + "sys.modules", + { + "numpy": numpy_module_mock, + }, + ): + from napytau.core.polynomials import evaluate_polynomial_at_measuring_distances + + distances: ndarray = array([1, 2, 3]) + coefficients: ndarray = array([5]) + # Constant polynomial: f(x) = 5 + # All values should be 5 + expected_result: ndarray = array([5, 5, 5]) + testing.assert_array_equal( + evaluate_polynomial_at_measuring_distances(distances, coefficients), expected_result + ) @staticmethod - def test_CalculationForEmptyPolynomial(): - distances: ndarray = array([1, 2]) - coefficients: ndarray = array([]) - # With an empty coefficients array, the result should be an array of zeros - # with the same length as 'distances' - expected_result: ndarray = array([0, 0], float) - testing.assert_array_equal( - polynomial_sum_at_measuring_distances(distances, coefficients), expected_result - ) + def test_CanEvaluateAnEmptyPolynomialAtMeasuringDistances(): + """Can evaluate an empty polynomial at measuring distances.""" + numpy_module_mock = set_up_mocks() + + # Mocked return values of called functions + numpy_module_mock.zeros_like.return_value = array([0, 0]) + + with patch.dict( + "sys.modules", + { + "numpy": numpy_module_mock, + }, + ): + from napytau.core.polynomials import evaluate_polynomial_at_measuring_distances + + distances: ndarray = array([1, 2]) + coefficients: ndarray = array([]) + # With an empty coefficients array, the result should be an array of zeros + # with the same length as 'distances' + expected_result: ndarray = array([0, 0], float) + testing.assert_array_equal( + evaluate_polynomial_at_measuring_distances(distances, coefficients), expected_result + ) @staticmethod - def test_DifferentiatedCalculationForValidPolynomial(): - # Test for a simple quadratic polynomial: 2 + 3x + 4x^2 - distances: ndarray = array([1, 2, 3]) - coefficients: ndarray = array([2, 3, 4]) - # The differentiated polynomial should be: 3 + 8x - # At x = 1: 3 + 8(1) = 3 + 8 = 11 - # At x = 2: 3 + 8(2) = 3 + 16 = 19 - # At x = 3: 3 + 8(3) = 3 + 24 = 27 - expected_result: ndarray = array([11, 19, 27]) - testing.assert_array_equal( - differentiated_polynomial_sum_at_measuring_distances(distances, coefficients), - expected_result, - ) + def test_CanEvaluateAValidDifferentiatedPolynomialAtMeasuringDistances(): + """Can evaluate a valid differentiated polynomial at measuring distances.""" + numpy_module_mock = set_up_mocks() + + # Mocked return values of called functions + numpy_module_mock.power.side_effect = [array([1, 1, 1]), array([1, 2, 3])] + numpy_module_mock.zeros_like.return_value = array([0, 0, 0]) + + with patch.dict( + "sys.modules", + { + "numpy": numpy_module_mock, + }, + ): + from napytau.core.polynomials import evaluate_differentiated_polynomial_at_measuring_distances + + # Test for a simple quadratic polynomial: 2 + 3x + 4x^2 + distances: ndarray = array([1, 2, 3]) + coefficients: ndarray = array([2, 3, 4]) + # The differentiated polynomial should be: 3 + 8x + # At x = 1: 3 + 8(1) = 3 + 8 = 11 + # At x = 2: 3 + 8(2) = 3 + 16 = 19 + # At x = 3: 3 + 8(3) = 3 + 24 = 27 + expected_result: ndarray = array([11, 19, 27]) + testing.assert_array_equal( + evaluate_differentiated_polynomial_at_measuring_distances(distances, coefficients), + expected_result, + ) @staticmethod - def test_DifferentiatedCalculationForEmptyDistanceInput(): - distances: ndarray = array([]) - coefficients: ndarray = array([2, 3, 4]) - # With an empty input array, the result should also be an empty array - expected_result: ndarray = array([]) - testing.assert_array_equal( - differentiated_polynomial_sum_at_measuring_distances(distances, coefficients), - expected_result, - ) + def test_CanEvaluateADifferentiatedPolynomialAtMeasuringDistancesForEmptyDistanceInput(): + """Can evaluate a differentiated polynomial at measuring distances for empty distances.""" + numpy_module_mock = set_up_mocks() + + # Mocked return values of called functions + numpy_module_mock.power.side_effect = [array([]), array([])] + numpy_module_mock.zeros_like.return_value = array([]) + + with patch.dict( + "sys.modules", + { + "numpy": numpy_module_mock, + }, + ): + from napytau.core.polynomials import evaluate_differentiated_polynomial_at_measuring_distances + + distances: ndarray = array([]) + coefficients: ndarray = array([2, 3, 4]) + # With an empty input array, the result should also be an empty array + expected_result: ndarray = array([]) + testing.assert_array_equal( + evaluate_differentiated_polynomial_at_measuring_distances(distances, coefficients), + expected_result, + ) @staticmethod - def test_DifferentiatedCalculationForSingleDistanceMeasurement(): - distances: ndarray = array([2]) - coefficients: ndarray = array([1, 2]) - # The differentiated polynomial should be: 2 - # At x = 2: 2 - expected_result: ndarray = array([2]) - testing.assert_array_equal( - differentiated_polynomial_sum_at_measuring_distances(distances, coefficients), - expected_result, - ) + def test_CanEvaluateADifferentiatedPolynomialAtMeasuringDistancesForSingleDistanceMeasurement(): + """Can evaluate a differentiated polynomial at measuring distances for single distance measurement.""" + numpy_module_mock = set_up_mocks() + + # Mocked return values of called functions + numpy_module_mock.power.side_effect = [array([1]), array([2])] + numpy_module_mock.zeros_like.return_value = array([0]) + + with patch.dict( + "sys.modules", + { + "numpy": numpy_module_mock, + }, + ): + from napytau.core.polynomials import evaluate_differentiated_polynomial_at_measuring_distances + + distances: ndarray = array([2]) + coefficients: ndarray = array([1, 2]) + # The differentiated polynomial should be: 2 + # At x = 2: 2 + expected_result: ndarray = array([2]) + testing.assert_array_equal( + evaluate_differentiated_polynomial_at_measuring_distances(distances, coefficients), + expected_result, + ) @staticmethod - def test_DifferentiatedCalculationForSingleValuePolynomial(): - distances: ndarray = array([1, 2, 3]) - coefficients: ndarray = array([5]) - # The differentiated polynomial should be: 0 - # All values should therefore be 0 - expected_result: ndarray = array([0, 0, 0]) - testing.assert_array_equal( - differentiated_polynomial_sum_at_measuring_distances(distances, coefficients), - expected_result, - ) + def test_CanEvaluateADifferentiatedSingleValuePolynomialAtMeasuringDistances(): + """Can evaluate a differentiated single value polynomial at measuring distances.""" + numpy_module_mock = set_up_mocks() + + # Mocked return values of called functions + numpy_module_mock.power.side_effect = [array([1, 1, 1]), array([1, 2, 3])] + numpy_module_mock.zeros_like.return_value = array([0, 0, 0]) + + with patch.dict( + "sys.modules", + { + "numpy": numpy_module_mock, + }, + ): + from napytau.core.polynomials import evaluate_differentiated_polynomial_at_measuring_distances + + distances: ndarray = array([1, 2, 3]) + coefficients: ndarray = array([5]) + # The differentiated polynomial should be: 0 + # All values should therefore be 0 + expected_result: ndarray = array([0, 0, 0]) + testing.assert_array_equal( + evaluate_differentiated_polynomial_at_measuring_distances(distances, coefficients), + expected_result, + ) @staticmethod - def test_DifferentiatedCalculationForEmptyPolynomial(): - distances: ndarray = array([1, 2]) - coefficients: ndarray = array([]) - # With an empty coefficients array, the result should be an array of zeros - # with the same length as 'distances' - expected_result: ndarray = array([0, 0]) - testing.assert_array_equal( - differentiated_polynomial_sum_at_measuring_distances(distances, coefficients), - expected_result, - ) + def test_CanEvaluateADifferentiatedEmptyPolynomialAtMeasuringDistances(): + """Can evaluate a differentiated empty polynomial at measuring distances.""" + numpy_module_mock = set_up_mocks() + + # Mocked return values of called functions + numpy_module_mock.zeros_like.return_value = array([0, 0]) + + with patch.dict( + "sys.modules", + { + "numpy": numpy_module_mock, + }, + ): + from napytau.core.polynomials import evaluate_differentiated_polynomial_at_measuring_distances + + distances: ndarray = array([1, 2]) + coefficients: ndarray = array([]) + # With an empty coefficients array, the result should be an array of zeros + # with the same length as 'distances' + expected_result: ndarray = array([0, 0]) + testing.assert_array_equal( + evaluate_differentiated_polynomial_at_measuring_distances(distances, coefficients), + expected_result, + ) if __name__ == "__main__": diff --git a/tests/core/tau_final_test.py b/tests/core/tau_final_test.py index 5b73c31..ecb454b 100644 --- a/tests/core/tau_final_test.py +++ b/tests/core/tau_final_test.py @@ -12,7 +12,7 @@ def set_up_mocks() -> MagicMock: return numpy_module_mock -class CoreUnitTest(unittest.TestCase): +class TauFinalUnitTest(unittest.TestCase): def test_calculateTauFinalForValidData(self): """Calculates the weighted mean and the uncertainty of tau correctly""" numpy_module_mock = set_up_mocks() diff --git a/tests/core/tau_test.py b/tests/core/tau_test.py index 0a14716..b9482b5 100644 --- a/tests/core/tau_test.py +++ b/tests/core/tau_test.py @@ -18,7 +18,8 @@ def set_up_mocks() -> (MagicMock, MagicMock): class TauUnitTest(unittest.TestCase): - def test_tauCalculation(self): + def test_CanCalculateTau(self): + """Can calculate tau""" chi_mock, polynomials_mock = set_up_mocks() # Mocked return values of called functions @@ -27,7 +28,7 @@ def test_tauCalculation(self): 0, ) chi_mock.optimize_t_hyp.return_value: float = 2.0 - polynomials_mock.differentiated_polynomial_sum_at_measuring_distances.return_value: ndarray = array( + polynomials_mock.evaluate_differentiated_polynomial_at_measuring_distances.return_value: ndarray = array( [2, 6] ) @@ -38,7 +39,7 @@ def test_tauCalculation(self): "napytau.core.chi": chi_mock, }, ): - from napytau.core.tau import calculate_tau_i + from napytau.core.tau import calculate_tau_i_values # Mocked input data doppler_shifted_intensities: ndarray = array([2, 6]) @@ -54,7 +55,7 @@ def test_tauCalculation(self): expected_tau: ndarray = array([3, 1.6666667]) testing.assert_array_almost_equal( - calculate_tau_i( + calculate_tau_i_values( doppler_shifted_intensities, unshifted_intensities, delta_doppler_shifted_intensities, @@ -63,6 +64,7 @@ def test_tauCalculation(self): distances, t_hyp_range, weight_factor, + None, ), expected_tau, ) @@ -149,20 +151,20 @@ def test_tauCalculation(self): self.assertEqual( len( - polynomials_mock.differentiated_polynomial_sum_at_measuring_distances.mock_calls + polynomials_mock.evaluate_differentiated_polynomial_at_measuring_distances.mock_calls ), 1, ) testing.assert_array_equal( - polynomials_mock.differentiated_polynomial_sum_at_measuring_distances.mock_calls[ + polynomials_mock.evaluate_differentiated_polynomial_at_measuring_distances.mock_calls[ 0 ].args[0], (array([0, 1])), ) testing.assert_array_equal( - polynomials_mock.differentiated_polynomial_sum_at_measuring_distances.mock_calls[ + polynomials_mock.evaluate_differentiated_polynomial_at_measuring_distances.mock_calls[ 0 ].args[1], (array([2, 3, 1])),