diff --git a/src/pyrecest/calibration/bias.py b/src/pyrecest/calibration/bias.py index 754650b69c..1ecaa4d50d 100644 --- a/src/pyrecest/calibration/bias.py +++ b/src/pyrecest/calibration/bias.py @@ -64,18 +64,28 @@ class SensorBiasCorrectionModel: def __post_init__(self) -> None: target_dim = _as_positive_int(self.target_dim, "target_dim") feature_dim = _as_nonnegative_int(self.feature_dim, "feature_dim") - intercept = _as_numeric_array(self.intercept, "intercept").reshape(target_dim) - coefficients = _as_numeric_array(self.coefficients, "coefficients").reshape( - feature_dim, target_dim + intercept = ( + _as_numeric_array(self.intercept, "intercept") + .reshape(target_dim) + .copy() ) - feature_mean = _as_numeric_array(self.feature_mean, "feature_mean").reshape( - feature_dim + coefficients = ( + _as_numeric_array(self.coefficients, "coefficients") + .reshape(feature_dim, target_dim) + .copy() + ) + feature_mean = ( + _as_numeric_array(self.feature_mean, "feature_mean") + .reshape(feature_dim) + .copy() ) feature_scale = _as_numeric_array(self.feature_scale, "feature_scale").reshape( feature_dim ) - residual_std = _as_numeric_array(self.residual_std, "residual_std").reshape( - target_dim + residual_std = ( + _as_numeric_array(self.residual_std, "residual_std") + .reshape(target_dim) + .copy() ) _require_finite_array(intercept, "intercept") _require_finite_array(coefficients, "coefficients") diff --git a/tests/calibration/test_bias_parameter_ownership.py b/tests/calibration/test_bias_parameter_ownership.py new file mode 100644 index 0000000000..b25b56f1e4 --- /dev/null +++ b/tests/calibration/test_bias_parameter_ownership.py @@ -0,0 +1,37 @@ +import numpy as np + +from pyrecest.calibration.bias import SensorBiasCorrectionModel + + +def test_bias_model_copies_mutable_parameter_arrays(): + intercept = np.array([1.0]) + coefficients = np.array([[2.0]]) + feature_mean = np.array([3.0]) + feature_scale = np.array([4.0]) + residual_std = np.array([5.0]) + model = SensorBiasCorrectionModel( + target_dim=1, + feature_dim=1, + intercept=intercept, + coefficients=coefficients, + feature_mean=feature_mean, + feature_scale=feature_scale, + residual_std=residual_std, + training_count=1, + ridge_alpha=0.0, + ) + features = np.array([[7.0]]) + expected_prediction = model.predict(features).copy() + + intercept[:] = 10.0 + coefficients[:] = 20.0 + feature_mean[:] = 30.0 + feature_scale[:] = 40.0 + residual_std[:] = 50.0 + + np.testing.assert_allclose(model.intercept, [1.0]) + np.testing.assert_allclose(model.coefficients, [[2.0]]) + np.testing.assert_allclose(model.feature_mean, [3.0]) + np.testing.assert_allclose(model.feature_scale, [4.0]) + np.testing.assert_allclose(model.residual_std, [5.0]) + np.testing.assert_allclose(model.predict(features), expected_prediction)