From 34b7a9fad05a9982b67a71c00b4379cc188d5500 Mon Sep 17 00:00:00 2001
From: Anton Piccardo-Selg <anton.piccardo-selg@tessella.com>
Date: Wed, 14 Oct 2015 17:14:35 +0100
Subject: [PATCH] Refs #13872 Fix more unit tests for MDFrame

---
 Framework/Crystal/test/FindClusterFacesTest.h |  12 ++-
 .../Crystal/test/PeakClusterProjectionTest.h  |   9 +-
 .../ImportMDHistoWorkspaceBase.h              |   5 +
 .../MDAlgorithms/src/CreateMDWorkspace.cpp    |   5 +-
 .../src/ImportMDHistoWorkspaceBase.cpp        | 101 +++++++++++++++++-
 .../test/CreateMDHistoWorkspaceTest.h         |  18 +++-
 .../test/ImportMDHistoWorkspaceTest.h         |  15 ++-
 Framework/MDAlgorithms/test/LoadMDTest.h      |  29 +++--
 .../MantidTestHelpers/MDEventsTestHelper.h    |  10 ++
 9 files changed, 185 insertions(+), 19 deletions(-)

diff --git a/Framework/Crystal/test/FindClusterFacesTest.h b/Framework/Crystal/test/FindClusterFacesTest.h
index 012e4bf6d0f..a17e21ccb53 100644
--- a/Framework/Crystal/test/FindClusterFacesTest.h
+++ b/Framework/Crystal/test/FindClusterFacesTest.h
@@ -9,8 +9,11 @@
 #include "MantidAPI/FrameworkManager.h"
 #include "MantidDataObjects/PeaksWorkspace.h"
 #include "MantidGeometry/Instrument.h"
+#include "MantidGeometry/MDGeometry/HKL.h"
 #include "MantidTestHelpers/ComponentCreationHelper.h"
 #include "MantidTestHelpers/MDEventsTestHelper.h"
+#include "MantidKernel/UnitLabelTypes.h"
+
 #include <boost/assign/list_of.hpp>
 
 using namespace Mantid::API;
@@ -54,7 +57,14 @@ IMDHistoWorkspace_sptr create_HKL_MDWS(double min = -10, double max = 10,
   std::vector<double> errorValues(totalBins, errorValue);
   mdworkspaceAlg->setProperty("ErrorInput", errorValues);
   mdworkspaceAlg->setPropertyValue("Names", "H,K,L");
-  mdworkspaceAlg->setPropertyValue("Units", "-,-,-");
+  std::string units = Mantid::Kernel::Units::Symbol::RLU.ascii() + "," +
+                      Mantid::Kernel::Units::Symbol::RLU.ascii() + "," +
+                      Mantid::Kernel::Units::Symbol::RLU.ascii();
+  std::string frames = Mantid::Geometry::HKL::HKLName + "," +
+                       Mantid::Geometry::HKL::HKLName + "," +
+                       Mantid::Geometry::HKL::HKLName;
+  TS_ASSERT_THROWS_NOTHING(mdworkspaceAlg->setProperty("Frames", frames));
+  TS_ASSERT_THROWS_NOTHING(mdworkspaceAlg->setProperty("Units", units));
   mdworkspaceAlg->setPropertyValue("OutputWorkspace",
                                    "IntegratePeaksMDTest_MDEWS");
   mdworkspaceAlg->execute();
diff --git a/Framework/Crystal/test/PeakClusterProjectionTest.h b/Framework/Crystal/test/PeakClusterProjectionTest.h
index 59f8d147ea6..27143bd5779 100644
--- a/Framework/Crystal/test/PeakClusterProjectionTest.h
+++ b/Framework/Crystal/test/PeakClusterProjectionTest.h
@@ -63,7 +63,14 @@ private:
     std::vector<double> errorValues(totalBins, errorValue);
     mdworkspaceAlg->setProperty("ErrorInput", errorValues);
     mdworkspaceAlg->setPropertyValue("Names", "H,K,L");
-    mdworkspaceAlg->setPropertyValue("Units", "-,-,-");
+    std::string units = Mantid::Kernel::Units::Symbol::RLU.ascii() + "," +
+                        Mantid::Kernel::Units::Symbol::RLU.ascii() + "," +
+                        Mantid::Kernel::Units::Symbol::RLU.ascii();
+    std::string frames = Mantid::Geometry::HKL::HKLName + "," +
+                         Mantid::Geometry::HKL::HKLName + "," +
+                         Mantid::Geometry::HKL::HKLName;
+    TS_ASSERT_THROWS_NOTHING(mdworkspaceAlg->setProperty("Frames", frames));
+    TS_ASSERT_THROWS_NOTHING(mdworkspaceAlg->setProperty("Units", units));
     mdworkspaceAlg->setPropertyValue("OutputWorkspace",
                                      "IntegratePeaksMDTest_MDEWS");
     mdworkspaceAlg->execute();
diff --git a/Framework/MDAlgorithms/inc/MantidMDAlgorithms/ImportMDHistoWorkspaceBase.h b/Framework/MDAlgorithms/inc/MantidMDAlgorithms/ImportMDHistoWorkspaceBase.h
index 81e9ec99362..94455e0a1a7 100644
--- a/Framework/MDAlgorithms/inc/MantidMDAlgorithms/ImportMDHistoWorkspaceBase.h
+++ b/Framework/MDAlgorithms/inc/MantidMDAlgorithms/ImportMDHistoWorkspaceBase.h
@@ -39,6 +39,7 @@ class DLLExport ImportMDHistoWorkspaceBase : public API::Algorithm {
 public:
   ImportMDHistoWorkspaceBase();
   virtual ~ImportMDHistoWorkspaceBase();
+  virtual std::map<std::string, std::string> validateInputs();
 
 protected:
   /// Vector containing the number of bins in each dimension.
@@ -54,6 +55,10 @@ protected:
 private:
   // Product of the bins across all dimensions.
   size_t m_bin_product;
+  Mantid::Geometry::MDFrame_uptr createMDFrame(std::string frame,
+                                               std::string unit);
+  bool checkIfFrameValid(const std::string &frame,
+                         const std::vector<std::string> &targetFrames);
 };
 
 } // namespace MDAlgorithms
diff --git a/Framework/MDAlgorithms/src/CreateMDWorkspace.cpp b/Framework/MDAlgorithms/src/CreateMDWorkspace.cpp
index 72e3081434b..78f8b23defa 100644
--- a/Framework/MDAlgorithms/src/CreateMDWorkspace.cpp
+++ b/Framework/MDAlgorithms/src/CreateMDWorkspace.cpp
@@ -66,7 +66,10 @@ void CreateMDWorkspace::init() {
       " **General Frame**: Any frame which is not a Q-based frame."
       " **QLab**: Wave-vector converted into the lab frame."
       " **QSample**: Wave-vector converted into the frame of the sample."
-      " **HKL**: Wave-vector converted into the crystal's HKL indices.");
+      " **HKL**: Wave-vector converted into the crystal's HKL indices."
+      " Note if nothing is specified then the **General Frame** is being "
+      "selected. Also note that if you select a frame then this might override "
+      "your unit selection if it is not compatible with the frame.");
   // Set the box controller properties
   this->initBoxControllerProps("5", 1000, 5);
 
diff --git a/Framework/MDAlgorithms/src/ImportMDHistoWorkspaceBase.cpp b/Framework/MDAlgorithms/src/ImportMDHistoWorkspaceBase.cpp
index 59bbfbca787..84b71925e96 100644
--- a/Framework/MDAlgorithms/src/ImportMDHistoWorkspaceBase.cpp
+++ b/Framework/MDAlgorithms/src/ImportMDHistoWorkspaceBase.cpp
@@ -5,7 +5,11 @@
 #include "MantidKernel/BoundedValidator.h"
 #include "MantidKernel/CompositeValidator.h"
 #include "MantidKernel/MandatoryValidator.h"
-
+#include "MantidGeometry/MDGeometry/QSample.h"
+#include "MantidGeometry/MDGeometry/QLab.h"
+#include "MantidGeometry/MDGeometry/HKL.h"
+#include "MantidGeometry/MDGeometry/GeneralFrame.h"
+#include "MantidGeometry/MDGeometry/MDFrameFactory.h"
 #include <algorithm>
 
 using namespace Mantid::API;
@@ -63,6 +67,17 @@ void ImportMDHistoWorkspaceBase::initGenericImportProps() {
   declareProperty(new WorkspaceProperty<IMDHistoWorkspace>(
                       "OutputWorkspace", "", Direction::Output),
                   "MDHistoWorkspace reflecting the input text file.");
+  declareProperty(
+      new ArrayProperty<std::string>("Frames"),
+      " A comma separated list of the frames of each dimension. "
+      " The frames can be"
+      " **General Frame**: Any frame which is not a Q-based frame."
+      " **QLab**: Wave-vector converted into the lab frame."
+      " **QSample**: Wave-vector converted into the frame of the sample."
+      " **HKL**: Wave-vector converted into the crystal's HKL indices."
+      " Note if nothing is specified then the **General Frame** is being "
+      "selected. Also note that if you select a frame then this might override "
+      "your unit selection if it is not compatible with the frame.");
 }
 
 //----------------------------------------------------------------------------------------------
@@ -81,6 +96,7 @@ MDHistoWorkspace_sptr ImportMDHistoWorkspaceBase::createEmptyOutputWorkspace() {
   std::vector<int> nbins = getProperty("NumberOfBins");
   std::vector<std::string> names = getProperty("Names");
   std::vector<std::string> units = getProperty("Units");
+  std::vector<std::string> frames = getProperty("Frames");
 
   // Perform all validation on inputs
   if (extents.size() != ndims * 2)
@@ -96,11 +112,26 @@ MDHistoWorkspace_sptr ImportMDHistoWorkspaceBase::createEmptyOutputWorkspace() {
     throw std::invalid_argument(
         "You must specify as many units as there are dimensions.");
 
+  // If no frames are specified we want to default to the General Frame,
+  // to ensure backward compatibility. But if they are only partly specified,
+  // then we want to throw an error. It should be either used correctly or not
+  // at all
+  if (!frames.empty() && frames.size() != ndims) {
+    throw std::invalid_argument(
+        "You must specify as many frames as there are dimensions.");
+  }
+
+  if (frames.empty()) {
+    frames.resize(ndims);
+    std::fill(frames.begin(), frames.end(), GeneralFrame::GeneralFrameName);
+  }
+
   // Fabricate new dimensions from inputs
   std::vector<MDHistoDimension_sptr> dimensions;
   for (size_t k = 0; k < ndims; ++k) {
+    auto frame = createMDFrame(frames[k], units[k]);
     dimensions.push_back(MDHistoDimension_sptr(new MDHistoDimension(
-        names[k], names[k], units[k], static_cast<coord_t>(extents[k * 2]),
+        names[k], names[k], *frame, static_cast<coord_t>(extents[k * 2]),
         static_cast<coord_t>(extents[(k * 2) + 1]), nbins[k])));
   }
 
@@ -112,5 +143,71 @@ MDHistoWorkspace_sptr ImportMDHistoWorkspaceBase::createEmptyOutputWorkspace() {
   return ws;
 }
 
+/**
+ * Create an MDFrame
+ * @param frame: the selected frame
+ * @param unit: the selected unit
+ * @returns a unique pointer to an MDFrame
+ */
+MDFrame_uptr ImportMDHistoWorkspaceBase::createMDFrame(std::string frame,
+                                                       std::string unit) {
+  auto frameFactory = makeMDFrameFactoryChain();
+  MDFrameArgument frameArg(frame, unit);
+  return frameFactory->create(frameArg);
+}
+
+std::map<std::string, std::string>
+ImportMDHistoWorkspaceBase::validateInputs() {
+  // Check Frame names
+  std::map<std::string, std::string> errors;
+  std::string framePropertyName = "Frames";
+  std::vector<std::string> frames = getProperty(framePropertyName);
+  int ndims_prop = getProperty("Dimensionality");
+  auto ndims = static_cast<size_t>(ndims_prop);
+
+  std::vector<std::string> targetFrames;
+  targetFrames.push_back(Mantid::Geometry::GeneralFrame::GeneralFrameName);
+  targetFrames.push_back(Mantid::Geometry::HKL::HKLName);
+  targetFrames.push_back(Mantid::Geometry::QLab::QLabName);
+  targetFrames.push_back(Mantid::Geometry::QSample::QSampleName);
+
+  auto isValidFrame = true;
+  for (auto it = frames.begin(); it != frames.end(); ++it) {
+    auto result = checkIfFrameValid(*it, targetFrames);
+    if (!result) {
+      isValidFrame = result;
+    }
+  }
+
+  if (!frames.empty() && frames.size() != ndims) {
+    isValidFrame = false;
+  }
+
+  if (!isValidFrame) {
+    std::string message = "The selected frames can be 'HKL', 'QSample', 'QLab' "
+                          "or 'General Frame'. You must specify as many frames "
+                          "as there are dimensions.";
+    errors.insert(std::make_pair(framePropertyName, message));
+  }
+  return errors;
+}
+
+/**
+ * Check if the specified frame matches a target frame
+ * @param frame: the frame name under investigation
+ * @param targetFrames: the allowed frame names
+ * @returns true if the frame name is valid else false
+ */
+bool ImportMDHistoWorkspaceBase::checkIfFrameValid(
+    const std::string &frame, const std::vector<std::string> &targetFrames) {
+  for (auto targetFrame = targetFrames.begin();
+       targetFrame != targetFrames.end(); ++targetFrame) {
+    if (*targetFrame == frame) {
+      return true;
+    }
+  }
+  return false;
+}
+
 } // namespace Mantid
 } // namespace MDAlgorithms
diff --git a/Framework/MDAlgorithms/test/CreateMDHistoWorkspaceTest.h b/Framework/MDAlgorithms/test/CreateMDHistoWorkspaceTest.h
index 534d7b00cde..91a31c184ba 100644
--- a/Framework/MDAlgorithms/test/CreateMDHistoWorkspaceTest.h
+++ b/Framework/MDAlgorithms/test/CreateMDHistoWorkspaceTest.h
@@ -4,7 +4,8 @@
 #include <cxxtest/TestSuite.h>
 #include "MantidKernel/Timer.h"
 #include "MantidKernel/System.h"
-
+#include "MantidGeometry/MDGeometry/QSample.h"
+#include "MantidGeometry/MDGeometry/GeneralFrame.h"
 #include "MantidMDAlgorithms/CreateMDHistoWorkspace.h"
 
 using namespace Mantid;
@@ -103,6 +104,7 @@ public:
     TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("Extents", "-1,1"));
     TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("Names", "A"));
     TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("Units", "U"));
+    TS_ASSERT_THROWS_NOTHING(alg.setPropertyValue("Frames", "QSample"));
     TS_ASSERT_THROWS_NOTHING(
         alg.setPropertyValue("OutputWorkspace", outWSName));
     TS_ASSERT_THROWS_NOTHING(alg.execute(););
@@ -122,7 +124,10 @@ public:
 
     TS_ASSERT_EQUALS("A", dim1->getName());
     TS_ASSERT_EQUALS("A", dim1->getDimensionId());
-    TS_ASSERT_EQUALS("U", dim1->getUnits().ascii());
+    TSM_ASSERT("Should not be set to U any longer", "U" != dim1->getUnits().ascii());
+    TSM_ASSERT_THROWS_NOTHING(
+            "Should be convertible to a QSample frame",
+            dynamic_cast<const Mantid::Geometry::QSample &>(dim1->getMDFrame()));
     TS_ASSERT_EQUALS(1, dim1->getMaximum());
     TS_ASSERT_EQUALS(-1, dim1->getMinimum());
     TS_ASSERT_EQUALS(5, dim1->getNBins());
@@ -177,6 +182,15 @@ public:
     TS_ASSERT_EQUALS(2, dim1->getNBins());
     TS_ASSERT_EQUALS(3, dim2->getNBins());
 
+    // Check frame and label
+    TSM_ASSERT("Should be set to U", "U" == dim1->getUnits().ascii());
+    TSM_ASSERT_THROWS_NOTHING(
+            "Should be convertible to a General Frame",
+            dynamic_cast<const Mantid::Geometry::GeneralFrame &>(dim1->getMDFrame()));
+    TSM_ASSERT_THROWS_NOTHING(
+            "Should be convertible to a General Frame",
+            dynamic_cast<const Mantid::Geometry::GeneralFrame &>(dim2->getMDFrame()));
+
     // Check the data
     double *signals = outWs->getSignalArray();
     TS_ASSERT_DELTA(1, signals[0], 0.0001); // Check the first signal value
diff --git a/Framework/MDAlgorithms/test/ImportMDHistoWorkspaceTest.h b/Framework/MDAlgorithms/test/ImportMDHistoWorkspaceTest.h
index cd09e88274d..8091c8b9006 100644
--- a/Framework/MDAlgorithms/test/ImportMDHistoWorkspaceTest.h
+++ b/Framework/MDAlgorithms/test/ImportMDHistoWorkspaceTest.h
@@ -4,7 +4,7 @@
 #include "MantidAPI/IMDHistoWorkspace.h"
 #include "MantidKernel/ConfigService.h"
 #include "MantidMDAlgorithms/ImportMDHistoWorkspace.h"
-
+#include "MantidGeometry/MDGeometry/QSample.h"
 #include <cxxtest/TestSuite.h>
 
 #include <Poco/Path.h>
@@ -277,7 +277,8 @@ public:
     alg->setPropertyValue("Extents", "-1,1,-1,1,-1,1");
     alg->setPropertyValue("NumberOfBins", "2,2,2");
     alg->setPropertyValue("Names", "A,B,C");
-    alg->setPropertyValue("Units", "U1,U2,U3");
+    alg->setPropertyValue("Units", "U,U,U");
+    TS_ASSERT_THROWS_NOTHING(alg->setPropertyValue("Frames", "QSample, QSample, QSample"));
     alg->setPropertyValue("OutputWorkspace", "test_workspace");
     alg->setRethrows(true);
     alg->execute();
@@ -296,6 +297,16 @@ public:
     // Check the dimensionality
     TS_ASSERT_EQUALS(3, outWs->getNumDims());
 
+    // Check frame
+    for (size_t dim = 0; dim < outWs->getNumDims(); ++dim) {
+      auto dimension = outWs->getDimension(dim);
+      const auto &frame = dimension->getMDFrame();
+      TSM_ASSERT_THROWS_NOTHING(
+          "Should be convertible to a QSample frame",
+          dynamic_cast<const Mantid::Geometry::QSample &>(frame));
+      TSM_ASSERT("Should not be set to U any longer", "U" != dimension->getUnits().ascii());
+    }
+
     ADS.remove("test_workspace");
   }
 };
diff --git a/Framework/MDAlgorithms/test/LoadMDTest.h b/Framework/MDAlgorithms/test/LoadMDTest.h
index 855729c5f34..744d40d6a2e 100644
--- a/Framework/MDAlgorithms/test/LoadMDTest.h
+++ b/Framework/MDAlgorithms/test/LoadMDTest.h
@@ -11,6 +11,7 @@
 #include "MantidDataObjects/MDEventFactory.h"
 #include "MantidDataObjects/MDEventWorkspace.h"
 #include "MantidDataObjects/BoxControllerNeXusIO.h"
+#include "MantidGeometry/MDGeometry/QSample.h"
 #include "MantidMDAlgorithms/LoadMD.h"
 
 #include <cxxtest/TestSuite.h>
@@ -593,9 +594,11 @@ public:
 
   /// More of an integration test as it uses both load and save.
   void test_save_and_load_special_coordinates_MDEventWorkspace() {
+    Mantid::Geometry::QSample frame;
     MDEventWorkspace1Lean::sptr mdeventWS =
-        MDEventsTestHelper::makeMDEW<1>(10, 0.0, 10.0, 2);
-    const SpecialCoordinateSystem appliedCoordinateSystem = QSample;
+        MDEventsTestHelper::makeMDEWWithFrames<1>(10, 0.0, 10.0, frame, 2);
+    const Mantid::Kernel::SpecialCoordinateSystem appliedCoordinateSystem =
+        Mantid::Kernel::SpecialCoordinateSystem::QSample;
     mdeventWS->setCoordinateSystem(appliedCoordinateSystem);
 
     auto loadedWS = testSaveAndLoadWorkspace(mdeventWS, "MDEventWorkspace");
@@ -607,9 +610,11 @@ public:
 
   // backwards-compatability check for coordinate in log
   void test_load_coordinate_system_MDEventWorkspace_from_experiment_info() {
+    Mantid::Geometry::QSample frame;
     MDEventWorkspace1Lean::sptr mdeventWS =
-        MDEventsTestHelper::makeMDEW<1>(10, 0.0, 10.0, 2);
-    const SpecialCoordinateSystem appliedCoordinateSystem = QSample;
+        MDEventsTestHelper::makeMDEWWithFrames<1>(10, 0.0, 10.0, frame, 2);
+    const Mantid::Kernel::SpecialCoordinateSystem appliedCoordinateSystem =
+        Mantid::Kernel::SpecialCoordinateSystem::QSample;
     mdeventWS->setCoordinateSystem(appliedCoordinateSystem);
 
     // Create a log in the first experiment info to simulated an old version of
@@ -628,9 +633,11 @@ public:
   }
 
   void test_save_and_load_special_coordinates_MDHistoWorkspace() {
-    auto mdhistoWS = MDEventsTestHelper::makeFakeMDHistoWorkspace(
-        2.5, 2, 10, 10.0, 3.5, "", 4.5);
-    const SpecialCoordinateSystem appliedCoordinateSystem = QSample;
+    Mantid::Geometry::QSample frame;
+    auto mdhistoWS = MDEventsTestHelper::makeFakeMDHistoWorkspaceWithMDFrame(
+        2.5, 2, frame, 10, 10.0, 3.5, "", 4.5);
+    const Mantid::Kernel::SpecialCoordinateSystem appliedCoordinateSystem =
+        Mantid::Kernel::SpecialCoordinateSystem::QSample;
     mdhistoWS->setCoordinateSystem(appliedCoordinateSystem);
 
     auto loadedWS = testSaveAndLoadWorkspace(mdhistoWS, "MDHistoWorkspace");
@@ -642,9 +649,11 @@ public:
 
   // backwards-compatability check for coordinate in log
   void test_load_coordinate_system_MDHistoWorkspace_from_experiment_info() {
-    auto mdhistoWS = MDEventsTestHelper::makeFakeMDHistoWorkspace(
-        2.5, 2, 10, 10.0, 3.5, "", 4.5);
-    const SpecialCoordinateSystem appliedCoordinateSystem = QSample;
+    Mantid::Geometry::QSample frame;
+    auto mdhistoWS = MDEventsTestHelper::makeFakeMDHistoWorkspaceWithMDFrame(
+        2.5, 2, frame, 10, 10.0, 3.5, "", 4.5);
+    const Mantid::Kernel::SpecialCoordinateSystem appliedCoordinateSystem =
+        Mantid::Kernel::SpecialCoordinateSystem::QSample;
     mdhistoWS->setCoordinateSystem(appliedCoordinateSystem);
 
     // Create a log in the first experiment info to simulated an old version of
diff --git a/Framework/TestHelpers/inc/MantidTestHelpers/MDEventsTestHelper.h b/Framework/TestHelpers/inc/MantidTestHelpers/MDEventsTestHelper.h
index fea8f0e6970..ea95ef80a6e 100644
--- a/Framework/TestHelpers/inc/MantidTestHelpers/MDEventsTestHelper.h
+++ b/Framework/TestHelpers/inc/MantidTestHelpers/MDEventsTestHelper.h
@@ -246,6 +246,16 @@ makeMDEW(size_t splitInto, coord_t min, coord_t max,
   return makeAnyMDEW<MDLeanEvent<nd>, nd>(splitInto, min, max, numEventsPerBox);
 }
 
+/** Make a MDEventWorkspace with MDLeanEvents nad MDFrames*/
+template <size_t nd>
+boost::shared_ptr<MDEventWorkspace<MDLeanEvent<nd>, nd>>
+makeMDEWWithFrames(size_t splitInto, coord_t min, coord_t max,
+                   const Mantid::Geometry::MDFrame &frame,
+                   size_t numEventsPerBox = 0) {
+  return makeAnyMDEWWithFrames<MDLeanEvent<nd>, nd>(splitInto, min, max, frame,
+                                                    numEventsPerBox);
+}
+
 /** Make a MDEventWorkspace with MDEvents  - updated to split dims by splitInto,
  * not 10 */
 template <size_t nd>
-- 
GitLab