diff --git a/environment.yml b/environment.yml index 6d13f022..a3e3f945 100644 --- a/environment.yml +++ b/environment.yml @@ -18,3 +18,4 @@ dependencies: - pytest - jacobi==0.4.2 #pinned until newer versions functionality confirmed - coverage + - dill diff --git a/pyproject.toml b/pyproject.toml index 17fffbf5..b10bd2b6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,6 +26,7 @@ dependencies = [ "iminuit", "h5py", "jacobi==0.4.2", + "dill", ] [project.optional-dependencies] diff --git a/src/mvesuvio/analysis_reduction.py b/src/mvesuvio/analysis_reduction.py index 71df655a..a0135dcf 100644 --- a/src/mvesuvio/analysis_reduction.py +++ b/src/mvesuvio/analysis_reduction.py @@ -1,6 +1,7 @@ import numpy as np import matplotlib.pyplot as plt import scipy +import dill # Only for converting constraints from string from mantid.kernel import StringListValidator, Direction, IntArrayBoundedValidator, IntArrayProperty,\ IntBoundedValidator, FloatBoundedValidator from mantid.api import FileProperty, FileAction, PythonAlgorithm, MatrixWorkspaceProperty @@ -11,7 +12,7 @@ VesuvioThickness, Integration, Divide, Multiply, DeleteWorkspaces, \ CreateWorkspace, CreateSampleWorkspace -from mvesuvio.util.analysis_helpers import loadConstants, numericalThirdDerivative +from mvesuvio.util.analysis_helpers import deserialize_lambdas, loadConstants, numericalThirdDerivative @@ -37,7 +38,7 @@ def PyInit(self): name="InputProfiles", defaultValue="", direction=Direction.Input), - doc="Table workspace containing starting parameters for profiles" + doc="Table workspace containing starting parameters for profiles." ) self.declareProperty(FileProperty( name='InstrumentParametersFile', @@ -61,17 +62,17 @@ def PyInit(self): name="InvalidDetectors", validator=IntArrayBoundedValidator(lower=3, upper=198), direction=Direction.Input), - doc="List of invalid detectors whithin range 3-198" + doc="List of invalid detectors whithin range 3-198." ) self.declareProperty( name="MultipleScatteringCorrection", defaultValue=False, - doc="Whether to run multiple scattering correction" + doc="Whether to run multiple scattering correction." ) self.declareProperty( name="GammaCorrection", defaultValue=False, - doc="Whether to run gamma correction" + doc="Whether to run gamma correction." ) self.declareProperty( name="SampleVerticalWidth", @@ -99,11 +100,11 @@ def PyInit(self): defaultValue="", doc="Directory where to save analysis results." ) - # self.declareProperty( - # name="Constraints", - # defaultValue=(), - # doc="Constraints to use during fitting profiles." - # ) + self.declareProperty( + name="Constraints", + defaultValue="", + doc="Constraints to use during fitting profiles." + ) self.declareProperty( name="TransmissionGuess", defaultValue=-1.0, @@ -122,12 +123,12 @@ def PyInit(self): self.declareProperty( name="ResultsPath", defaultValue="", - doc="Directory to store results, to be deleted later" + doc="Directory to store results, to be deleted later." ) self.declareProperty( name="FiguresPath", defaultValue="", - doc="Directory to store figures, to be deleted later" + doc="Directory to store figures, to be deleted later." ) # Outputs self.declareProperty(TableWorkspaceProperty( @@ -158,7 +159,7 @@ def _setup(self): self._save_results_path = self.getProperty("ResultsPath").value self._save_figures_path = self.getProperty("FiguresPath").value self._h_ratio = self.getProperty("HRatioToLowestMass").value - self._constraints = () #self.getProperty("Constraints").value + self._constraints = dill.loads(eval(self.getProperty("Constraints").value)) self._profiles_table = self.getProperty("InputProfiles").value diff --git a/src/mvesuvio/analysis_routines.py b/src/mvesuvio/analysis_routines.py index 6110f2e1..4bb74a8b 100644 --- a/src/mvesuvio/analysis_routines.py +++ b/src/mvesuvio/analysis_routines.py @@ -3,10 +3,11 @@ from mantid.simpleapi import CreateEmptyTableWorkspace, mtd, RenameWorkspace from mantid.api import AlgorithmFactory, AlgorithmManager import numpy as np +import dill # To convert constraints to string from mvesuvio.util.analysis_helpers import fix_profile_parameters, \ loadRawAndEmptyWsFromUserPath, cropAndMaskWorkspace, \ - NeutronComptonProfile, calculate_h_ratio + NeutronComptonProfile, calculate_h_ratio, serialize_lambdas from mvesuvio.analysis_reduction import AnalysisRoutine from tests.testhelpers.calibration.algorithms import create_algorithm @@ -56,7 +57,7 @@ def _create_analysis_object_from_current_interface(IC, running_tests=False): "TransmissionGuess": IC.transmission_guess, "MultipleScatteringOrder": int(IC.multiple_scattering_order), "NumberOfEvents": int(IC.number_of_events), - # Constraints"": IC.constraints, + "Constraints": str(dill.dumps(IC.constraints)), "ResultsPath": str(IC.resultsSavePath), "FiguresPath": str(IC.figSavePath), "OutputMeansTable":" Final_Means" diff --git a/tests/unit/analysis/test_analysis_helpers.py b/tests/unit/analysis/test_analysis_helpers.py index 29a1146d..be97818f 100644 --- a/tests/unit/analysis/test_analysis_helpers.py +++ b/tests/unit/analysis/test_analysis_helpers.py @@ -1,5 +1,6 @@ import unittest import numpy as np +import dill import numpy.testing as nptest from mock import MagicMock from mvesuvio.util.analysis_helpers import extractWS, _convert_dict_to_table, \ @@ -109,10 +110,19 @@ def test_fix_profile_parameters_without_H(self): def test_calculate_h_ratio(self): means_table_mock = MagicMock() - means_table_mock.column.side_effect = lambda x: [16, 1, 12] if x is "mass" else [0.1, 0.85, 0.05] + means_table_mock.column.side_effect = lambda x: [16, 1, 12] if x=="mass" else [0.1, 0.85, 0.05] h_ratio = calculate_h_ratio(means_table_mock) self.assertEqual(h_ratio, 0.85 / 0.05) + def test_conversion_of_constraints(self): + constraints = ({'type': 'eq', 'fun': lambda par: par[0] - 2.7527*par[3] },{'type': 'eq', 'fun': lambda par: par[3] - 0.7234*par[6] }) + string_constraints = str(dill.dumps(constraints)) + self.assertIsInstance(string_constraints, str) + converted_constraints = dill.loads(eval(string_constraints)) + self.assertEqual(converted_constraints[0]['fun']([3, 0, 0, 1]), 3-2.7527) + self.assertEqual(converted_constraints[1]['fun']([0, 0, 0, 2, 0, 0, 1]), 2-0.7234) + + if __name__ == "__main__": unittest.main() diff --git a/tests/unit/analysis/test_analysis_reduction.py b/tests/unit/analysis/test_analysis_reduction.py index 378655e3..edb561a3 100644 --- a/tests/unit/analysis/test_analysis_reduction.py +++ b/tests/unit/analysis/test_analysis_reduction.py @@ -4,33 +4,25 @@ from mock import MagicMock from mvesuvio.analysis_reduction import AnalysisRoutine from mantid.simpleapi import CreateWorkspace, DeleteWorkspace +import inspect class TestAnalysisFunctions(unittest.TestCase): def setUp(self): pass - def test_calculate_h_ratio_masses_ordered(self): + def test_constraints_are_passed_correctly(self): alg = AnalysisRoutine() - alg._mean_intensity_ratios = np.array([0.91175, 0.06286, 0.00732, 0.01806]) - alg._masses = np.array([1.0079, 12.0, 16.0, 27.0]) - h_ratio = alg.calculate_h_ratio() - self.assertAlmostEqual(14.504454343, h_ratio) - - def test_calculate_h_ratio_masses_unordered(self): - alg = AnalysisRoutine() - alg._mean_intensity_ratios = np.array([0.00732, 0.06286, 0.01806, 0.91175]) - alg._masses = np.array([16.0, 12.0, 27.0, 1.0079]) - h_ratio = alg.calculate_h_ratio() - self.assertAlmostEqual(14.504454343, h_ratio) - - def test_calculate_h_ratio_hydrogen_missing(self): - alg = AnalysisRoutine() - alg._mean_intensity_ratios = np.array([0.00732, 0.06286, 0.01806]) - alg._masses = np.array([16.0, 12.0, 27.0]) - h_ratio = alg.calculate_h_ratio() - self.assertAlmostEqual(None, h_ratio) - + alg.initialize() + constraints = ( + {'type': 'eq', 'fun': lambda par: par[0] - 2.7527*par[3] }, {'type': 'eq', 'fun': lambda par: par[3] - 0.7234*par[6] }) + for c in constraints: + print(inspect.getsourcelines(c['fun'])[0]) + # alg.setProperty("Constraints", str(constraints)) + # print(str(constraints)) + # print(alg.getPropertyValue("Constraints")) + # alg_constraints = eval(alg.getPropertyValue("Constraints")) + # self.assertEqual(constraints, alg_constraints) if __name__ == "__main__": unittest.main()