From 2e8d9966234025505e1a24d484a6e348b3c6c570 Mon Sep 17 00:00:00 2001
From: Conor Finn <conor.finn@stfc.ac.uk>
Date: Mon, 23 Sep 2019 10:11:23 +0100
Subject: [PATCH] RE #26846 Engineering model and tests created

---
 .../Properties/Mantid.properties.template     |   2 +-
 .../PythonInterface/mantid/kernel/_aliases.py |   2 +-
 scripts/CMakeLists.txt                        |   1 +
 scripts/Engineering/gui/CMakeLists.txt        |  11 ++
 scripts/Engineering/gui/__init__.py           |   0
 .../gui/engineering_diffraction/__init__.py   |   0
 .../engineering_diffraction/tabs/__init__.py  |   0
 .../tabs/calibration/__init__.py              |   0
 .../tabs/calibration/model.py                 | 135 ++++++++++++++++++
 .../tabs/calibration/test/__init__.py         |   0
 .../tabs/calibration/test/test_model.py       |  60 ++++++++
 scripts/Engineering_Diffraction.py            |   0
 12 files changed, 209 insertions(+), 2 deletions(-)
 create mode 100644 scripts/Engineering/gui/CMakeLists.txt
 create mode 100644 scripts/Engineering/gui/__init__.py
 create mode 100644 scripts/Engineering/gui/engineering_diffraction/__init__.py
 create mode 100644 scripts/Engineering/gui/engineering_diffraction/tabs/__init__.py
 create mode 100644 scripts/Engineering/gui/engineering_diffraction/tabs/calibration/__init__.py
 create mode 100644 scripts/Engineering/gui/engineering_diffraction/tabs/calibration/model.py
 create mode 100644 scripts/Engineering/gui/engineering_diffraction/tabs/calibration/test/__init__.py
 create mode 100644 scripts/Engineering/gui/engineering_diffraction/tabs/calibration/test/test_model.py
 create mode 100644 scripts/Engineering_Diffraction.py

diff --git a/Framework/Properties/Mantid.properties.template b/Framework/Properties/Mantid.properties.template
index 791b1a46247..7c083967d01 100644
--- a/Framework/Properties/Mantid.properties.template
+++ b/Framework/Properties/Mantid.properties.template
@@ -21,7 +21,7 @@ Q.convention = Inelastic
 
 # Set of PyQt interfaces to add to the Interfaces menu, separated by a space.  Interfaces are seperated from their respective categories by a "/".
 
-mantidqt.python_interfaces = Direct/DGS_Reduction.py Direct/DGSPlanner.py Direct/PyChop.py Direct/MSlice.py SANS/ORNL_SANS.py Utility/TofConverter.py Reflectometry/ISIS_Reflectometry_Old.py Diffraction/Powder_Diffraction_Reduction.py Utility/FilterEvents.py Diffraction/HFIR_4Circle_Reduction.py Utility/QECoverage.py SANS/ISIS_SANS.py Muon/Frequency_Domain_Analysis.py Muon/Elemental_Analysis.py Muon/Frequency_Domain_Analysis_Old.py Muon/Muon_Analysis_2.py
+mantidqt.python_interfaces = Direct/DGS_Reduction.py Direct/DGSPlanner.py Direct/PyChop.py Direct/MSlice.py SANS/ORNL_SANS.py Utility/TofConverter.py Reflectometry/ISIS_Reflectometry_Old.py Diffraction/Powder_Diffraction_Reduction.py Diffraction/Engineering_Diffraction.py Utility/FilterEvents.py Diffraction/HFIR_4Circle_Reduction.py Utility/QECoverage.py SANS/ISIS_SANS.py Muon/Frequency_Domain_Analysis.py Muon/Elemental_Analysis.py Muon/Frequency_Domain_Analysis_Old.py Muon/Muon_Analysis_2.py
 
 # Directory containing the above startup scripts
 mantidqt.python_interfaces_directory = @MANTID_ROOT@/scripts
diff --git a/Framework/PythonInterface/mantid/kernel/_aliases.py b/Framework/PythonInterface/mantid/kernel/_aliases.py
index b6ac466b9d7..11e69e16a28 100644
--- a/Framework/PythonInterface/mantid/kernel/_aliases.py
+++ b/Framework/PythonInterface/mantid/kernel/_aliases.py
@@ -1,4 +1,4 @@
-# Mantid Repository : https://github.com/mantidproject/mantid
+# Mantid Repository : https://github.com/mantidproject/mantmatrixWorkspaceid
 #
 # Copyright &copy; 2018 ISIS Rutherford Appleton Laboratory UKRI,
 #     NScD Oak Ridge National Laboratory, European Spallation Source
diff --git a/scripts/CMakeLists.txt b/scripts/CMakeLists.txt
index c213cef13a5..ad119467cfd 100644
--- a/scripts/CMakeLists.txt
+++ b/scripts/CMakeLists.txt
@@ -87,6 +87,7 @@ install(FILES ${_scripts_pth_install}
 # Testing
 add_subdirectory(test)
 add_subdirectory(Diffraction/isis_powder)
+add_subdirectory(Engineering/gui)
 
 # Ensure we don't get stale pyc files around
 clean_orphaned_pyc_files(${CMAKE_CURRENT_SOURCE_DIR})
diff --git a/scripts/Engineering/gui/CMakeLists.txt b/scripts/Engineering/gui/CMakeLists.txt
new file mode 100644
index 00000000000..d6b317c2b8b
--- /dev/null
+++ b/scripts/Engineering/gui/CMakeLists.txt
@@ -0,0 +1,11 @@
+# Tests for ISIS Powder
+
+set(TEST_PY_FILES
+    # Calibration
+    engineering_diffraction/tabs/calibration/test/test_model.py
+)
+
+check_tests_valid(${CMAKE_CURRENT_SOURCE_DIR} ${TEST_PY_FILES})
+
+pyunittest_add_test(${CMAKE_CURRENT_SOURCE_DIR} python.EngineeringDiffraction
+                    ${TEST_PY_FILES})
\ No newline at end of file
diff --git a/scripts/Engineering/gui/__init__.py b/scripts/Engineering/gui/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/scripts/Engineering/gui/engineering_diffraction/__init__.py b/scripts/Engineering/gui/engineering_diffraction/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/scripts/Engineering/gui/engineering_diffraction/tabs/__init__.py b/scripts/Engineering/gui/engineering_diffraction/tabs/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/scripts/Engineering/gui/engineering_diffraction/tabs/calibration/__init__.py b/scripts/Engineering/gui/engineering_diffraction/tabs/calibration/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/scripts/Engineering/gui/engineering_diffraction/tabs/calibration/model.py b/scripts/Engineering/gui/engineering_diffraction/tabs/calibration/model.py
new file mode 100644
index 00000000000..1ef299eabc4
--- /dev/null
+++ b/scripts/Engineering/gui/engineering_diffraction/tabs/calibration/model.py
@@ -0,0 +1,135 @@
+# Mantid Repository : https://github.com/mantidproject/mantid
+#
+# Copyright &copy; 2018 ISIS Rutherford Appleton Laboratory UKRI,
+#     NScD Oak Ridge National Laboratory, European Spallation Source
+#     & Institut Laue - Langevin
+# SPDX - License - Identifier: GPL - 3.0 +
+
+from __future__ import (absolute_import, division, print_function)
+
+from mantid.api import AnalysisDataService as Ads
+from mantid.kernel import logger
+from mantid.simpleapi import Load, EnggVanadiumCorrections, EnggCalibrate, DeleteWorkspace, CloneWorkspace, \
+    CreateWorkspace, AppendSpectra
+from mantidqt.plotting.functions import plot
+from qtpy import QtCore
+
+
+class CalibrationModel(object):
+    def __init__(self):
+        self.VANADIUM_INPUT_WORKSPACE_NAME = "engggui_vanadium_ws"
+        self.CURVES_WORKSPACE_NAME = "engggui_vanadium_curves"
+        self.INTEGRATED_WORKSPACE_NAME = "engggui_vanadium_integration"
+
+    def create_new_calibration(self, vanadium_run_no, ceria_run_no, plot_output):
+        vanadium_corrections = self.calculate_vanadium_correction(vanadium_run_no)
+        van_integration = vanadium_corrections[0]
+        van_curves = vanadium_corrections[1]
+        ceria_workspace = self.load_ceria(ceria_run_no)
+        difc, tzero = [0] * 2
+        self.run_calibration(ceria_workspace, van_integration, van_curves, difc, tzero)
+        if plot_output:
+            self.plot_vanadium_curves()
+            self._plot_difc_zero(difc, tzero)
+
+    @staticmethod
+    def plot_vanadium_curves():
+        van_curve_twin_ws = "__engggui_vanadium_curves_twin_ws"
+
+        if Ads.doesExist(van_curve_twin_ws):
+            DeleteWorkspace(van_curve_twin_ws)
+        CloneWorkspace(InputWorkspace="engggui_vanadium_curves", OutputWorkspace=van_curve_twin_ws)
+        van_curves_ws = Ads.retrieve(van_curve_twin_ws)
+        for i in range(1, 3):
+            if i == 1:
+                curve_plot_bank_1 = plot([van_curves_ws], [0, 1, 2]).activeLayer()
+                curve_plot_bank_1.setTitle("Engg GUI Vanadium Curves Bank 1")
+            if i == 2:
+                curve_plot_bank_2 = plot([van_curves_ws], [3, 4, 5]).activeLayer()
+                curve_plot_bank_2.setTitle("Engg GUI Vanadium Curves Bank 2")
+
+    @staticmethod
+    def _plot_difc_zero(difc, tzero):
+        for i in range(1, 3):
+            bank_ws = Ads.retrieve("engggui_calibration_bank_" + str(i))
+
+            x_val = []
+            y_val = []
+            y2_val = []
+
+            if i == 1:
+                difc_to_plot = difc[0]
+                tzero_to_plot = tzero[0]
+            else:
+                difc_to_plot = difc[1]
+                tzero_to_plot = tzero[1]
+
+            for irow in range(0, bank_ws.rowCount()):
+                x_val.append(bank_ws.cell(irow, 0))
+                y_val.append(bank_ws.cell(irow, 5))
+                y2_val.append(x_val[irow] * difc_to_plot + tzero_to_plot)
+
+            ws1 = CreateWorkspace(DataX=x_val,
+                                  DataY=y_val,
+                                  UnitX="Expected Peaks Centre (dSpacing A)",
+                                  YUnitLabel="Fitted Peaks Centre(TOF, us)")
+            ws2 = CreateWorkspace(DataX=x_val, DataY=y2_val)
+
+            output_ws = "engggui_difc_zero_peaks_bank_" + str(i)
+            if Ads.doesExist(output_ws):
+                DeleteWorkspace(output_ws)
+
+            AppendSpectra(ws1, ws2, OutputWorkspace=output_ws)
+            DeleteWorkspace(ws1)
+            DeleteWorkspace(ws2)
+
+            difc_zero_ws = Ads.retreive(output_ws)
+            # Create plot
+            difc_zero_plot = plot(difc_zero_ws, [0, 1]).activeLayer()
+            difc_zero_plot.setTitle("Engg Gui Difc Zero Peaks Bank " + str(i))
+            difc_zero_plot.setCurveTitle(0, "Peaks Fitted")
+            difc_zero_plot.setCurveTitle(1, "DifC/TZero Fitted Straight Line")
+            difc_zero_plot.xlabel("Expected Peaks Centre(dSpacing, A)")
+            difc_zero_plot.setCurveLineStyly(0, QtCore.Qt.DotLine)
+
+    def load_ceria(self, ceria_run_no):
+        try:
+            return Load(Filename=ceria_run_no, OutputWorkspace="engggui_calibration_sample_ws")
+        except Exception as e:
+            logger.error("Error while loading calibration sample data. "
+                         "Could not run the algorithm Load succesfully for the calibration sample "
+                         "(run number: " + str(ceria_run_no) + "). Error description: " + str(e) +
+                         " Please check also the previous log messages for details.")
+            raise RuntimeError
+
+    def run_calibration(self, ceria_ws, van_integration, van_curves, difc, tzero):
+        for i in range(2):
+            table_name = self._generate_table_workspace_name(i)
+            EnggCalibrate(InputWorkspace=ceria_ws,
+                          VanIntegrationWorkspace=van_integration,
+                          VanCurvesWorkspace=van_curves,
+                          Bank=i,
+                          FittedPeaks=table_name,
+                          OutputParametersTableName=table_name,
+                          DIFC=difc[i],
+                          TZERO=tzero[i])
+
+    def calculate_vanadium_correction(self, vanadium_run_no):
+        try:
+            Load(Filename=vanadium_run_no, OutputWorkspace=self.VANADIUM_INPUT_WORKSPACE_NAME)
+        except Exception as e:
+            logger.error("Error when loading vanadium sample data. "
+                         "Could not run Load algorithm with vanadium run number: " +
+                         str(vanadium_run_no) + ". Error description: " + str(e))
+            raise RuntimeError
+        EnggVanadiumCorrections(VanadiumWorkspace=self.VANADIUM_INPUT_WORKSPACE_NAME,
+                                OutIntegrationWorkspace=self.INTEGRATED_WORKSPACE_NAME,
+                                OutCurvesWorkspace=self.CURVES_WORKSPACE_NAME)
+        Ads.remove(self.VANADIUM_INPUT_WORKSPACE_NAME)
+        integrated_workspace = Ads.Instance().retrive(self.INTEGRATED_WORKSPACE_NAME)
+        curves_workspace = Ads.Instance().retrieve(self.CURVES_WORKSPACE_NAME)
+        return integrated_workspace, curves_workspace
+
+    @staticmethod
+    def _generate_table_workspace_name(bank_num):
+        return "engggui_calibration_bank_" + str(bank_num + 1)
diff --git a/scripts/Engineering/gui/engineering_diffraction/tabs/calibration/test/__init__.py b/scripts/Engineering/gui/engineering_diffraction/tabs/calibration/test/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/scripts/Engineering/gui/engineering_diffraction/tabs/calibration/test/test_model.py b/scripts/Engineering/gui/engineering_diffraction/tabs/calibration/test/test_model.py
new file mode 100644
index 00000000000..e1ae5491361
--- /dev/null
+++ b/scripts/Engineering/gui/engineering_diffraction/tabs/calibration/test/test_model.py
@@ -0,0 +1,60 @@
+# Mantid Repository : https://github.com/mantidproject/mantid
+#
+# Copyright &copy; 2018 ISIS Rutherford Appleton Laboratory UKRI,
+#     NScD Oak Ridge National Laboratory, European Spallation Source
+#     & Institut Laue - Langevin
+# SPDX - License - Identifier: GPL - 3.0 +
+
+from __future__ import (absolute_import, division, print_function)
+
+import unittest
+
+from mantid.py3compat.mock import patch, MagicMock
+from Engineering.gui.engineering_diffraction.tabs.calibration.model import CalibrationModel
+
+VANADIUM_NUMBER = 307521
+CERIUM_NUMBER = 305738
+INTEGRATED_WORKSPACE_NAME = "engggui_vanadium_integration"
+CURVES_WORKSPACE_NAME = "engggui_vanadium_curves"
+INPUT_WORKSPACE_NAME = "engggui_vanadium_ws"
+class_path = 'Engineering.gui.engineering_diffraction.tabs.calibration.model.CalibrationModel'
+
+
+class CalibrationModelTest(unittest.TestCase):
+    def setUp(self):
+        self.model = CalibrationModel()
+
+    def test_fails_on_invalid_run_number(self):
+        self.assertRaises(RuntimeError, self.model.create_new_calibration, "FAIL", 305738, True)
+        self.assertRaises(RuntimeError, self.model.create_new_calibration, 307521, "FAIL", True)
+
+    @patch(class_path + '.run_calibration')
+    @patch(class_path + '.load_ceria')
+    @patch(class_path + '.calculate_vanadium_correction')
+    def test_EnggVanadiumCorrections_algorithm_is_called(self, alg, load_ceria, calib):
+        self.model.create_new_calibration(VANADIUM_NUMBER, CERIUM_NUMBER, False)
+        alg.assert_called_once()
+
+    @patch(class_path + '.load_ceria')
+    @patch(class_path + '.calculate_vanadium_correction')
+    @patch(class_path + '.run_calibration')
+    def test_EnggCalibrate_algorithm_is_called(self, calibrate_alg, vanadium_alg, load_ceria):
+        self.model.create_new_calibration(VANADIUM_NUMBER, CERIUM_NUMBER, False)
+        self.assertEqual(calibrate_alg.call_count, 1)
+
+    @patch(class_path + '.load_ceria')
+    @patch(class_path + '.calculate_vanadium_correction')
+    @patch(class_path + '.plot_vanadium_curves')
+    @patch(class_path + '._plot_difc_zero')
+    @patch(class_path + '.run_calibration')
+    def test_plotting_check(self, calib, plot_difc_zero, plot_van, van, ceria):
+        self.model.create_new_calibration(VANADIUM_NUMBER, CERIUM_NUMBER, False)
+        plot_van.assert_not_called()
+        plot_difc_zero.assert_not_called()
+        self.model.create_new_calibration(VANADIUM_NUMBER, CERIUM_NUMBER, True)
+        plot_van.assert_called_once()
+        plot_difc_zero.assert_called_once()
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/scripts/Engineering_Diffraction.py b/scripts/Engineering_Diffraction.py
new file mode 100644
index 00000000000..e69de29bb2d
-- 
GitLab