diff --git a/Framework/Algorithms/inc/MantidAlgorithms/InterpolationOption.h b/Framework/Algorithms/inc/MantidAlgorithms/InterpolationOption.h
index 4eff9c4fbebac077587de2fead23f8a829d101d6..d18bdbc179db1e4088705d5babddc4e7db29d0e2 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/InterpolationOption.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/InterpolationOption.h
@@ -49,6 +49,7 @@ public:
 
   std::unique_ptr<Kernel::Property> property() const;
   std::string propertyDoc() const;
+  std::string validateInputSize(const size_t size) const;
 
   void applyInplace(HistogramData::Histogram &inOut, size_t stepSize) const;
   void applyInPlace(const HistogramData::Histogram &in,
diff --git a/Framework/Algorithms/inc/MantidAlgorithms/MonteCarloAbsorption.h b/Framework/Algorithms/inc/MantidAlgorithms/MonteCarloAbsorption.h
index b83941a6a7bd17ff271b910be71b01c8c7f38adf..c5fb1581c29308bea8940c7cc7358c15d7047115 100644
--- a/Framework/Algorithms/inc/MantidAlgorithms/MonteCarloAbsorption.h
+++ b/Framework/Algorithms/inc/MantidAlgorithms/MonteCarloAbsorption.h
@@ -62,6 +62,7 @@ public:
 private:
   void init() override;
   void exec() override;
+  std::map<std::string, std::string> validateInputs() override;
 
   API::MatrixWorkspace_uptr
   doSimulation(const API::MatrixWorkspace &inputWS, const size_t nevents,
diff --git a/Framework/Algorithms/src/EQSANSTofStructure.cpp b/Framework/Algorithms/src/EQSANSTofStructure.cpp
index 9ead21fc227ed6270966e6fc3485160c189c7ce9..7e8d339778348fce067c999c77aecad29b43c2e7 100644
--- a/Framework/Algorithms/src/EQSANSTofStructure.cpp
+++ b/Framework/Algorithms/src/EQSANSTofStructure.cpp
@@ -118,14 +118,15 @@ void EQSANSTofStructure::execEvent(
   const size_t numHists = inputWS->getNumberHistograms();
   Progress progress(this, 0.0, 1.0, numHists);
 
-  // Get the nominal sample-to-detector distance (in mm)
+  // This now points to the correct distance and makes the naming clearer
+  // Get the nominal sample flange-to-detector distance (in mm)
   Mantid::Kernel::Property *prop =
-      inputWS->run().getProperty("sample_detector_distance");
+      inputWS->run().getProperty("sampleflange_detector_distance");
   auto dp = dynamic_cast<Mantid::Kernel::PropertyWithValue<double> *>(prop);
   if (!dp) {
-    throw std::runtime_error("sample_detector_distance log not found.");
+    throw std::runtime_error("sampleflange_detector_distance log not found.");
   }
-  const double SDD = *dp / 1000.0;
+  const double SFDD = *dp / 1000.0;
 
   const auto &spectrumInfo = inputWS->spectrumInfo();
   const auto l1 = spectrumInfo.l1();
@@ -141,7 +142,7 @@ void EQSANSTofStructure::execEvent(
       continue;
     }
     const auto l2 = spectrumInfo.l2(ispec);
-    double tof_factor = (l1 + l2) / (l1 + SDD);
+    double tof_factor = (l1 + l2) / (l1 + SFDD);
 
     // Get the pointer to the output event list
     std::vector<TofEvent> &events = inputWS->getSpectrum(ispec).getEvents();
@@ -431,6 +432,8 @@ double EQSANSTofStructure::getTofOffset(EventWorkspace_const_sptr inputWS,
   else
     det_name = temp[0];
 
+  // Checked 8/11/2017 here detector_z is sfdd which has been updated
+  // in eqsansload.cpp
   double source_z = inputWS->getInstrument()->getSource()->getPos().Z();
   double detector_z =
       inputWS->getInstrument()->getComponentByName(det_name)->getPos().Z();
@@ -452,6 +455,7 @@ double EQSANSTofStructure::getTofOffset(EventWorkspace_const_sptr inputWS,
     g_log.information() << i << "    " << chopper_actual_phase[i] << "  "
                         << chopper_wl_1[i] << "  " << chopper_wl_2[i] << '\n';
 
+  // Checked 8/10/2017
   double low_wl_discard = 3.9560346 * low_tof_cut / source_to_detector;
   double high_wl_discard = 3.9560346 * high_tof_cut / source_to_detector;
 
diff --git a/Framework/Algorithms/src/InterpolationOption.cpp b/Framework/Algorithms/src/InterpolationOption.cpp
index dc795dcfd2c665f88050744fa49499c644b38236..659251da346b8a541b1085c369d86d0af18373d8 100644
--- a/Framework/Algorithms/src/InterpolationOption.cpp
+++ b/Framework/Algorithms/src/InterpolationOption.cpp
@@ -18,6 +18,8 @@ std::vector<std::string> OPTIONS{LINEAR_OPT, CSPLINE_OPT};
 namespace Mantid {
 using HistogramData::interpolateLinearInplace;
 using HistogramData::interpolateCSplineInplace;
+using HistogramData::minSizeForCSplineInterpolation;
+using HistogramData::minSizeForLinearInterpolation;
 using Kernel::Property;
 
 namespace Algorithms {
@@ -66,6 +68,32 @@ std::string InterpolationOption::propertyDoc() const {
   return "Method of interpolation used to compute unsimulated values.";
 }
 
+/**
+ * Validate the size of input histogram
+ * @param size number of points in the input histogram
+ * @return an error message if there was one, otherwise an empty string
+ */
+std::string InterpolationOption::validateInputSize(const size_t size) const {
+  size_t nMin;
+  switch (m_value) {
+  case Value::Linear:
+    nMin = minSizeForLinearInterpolation();
+    if (size < nMin) {
+      return "Linear interpolation requires at least " + std::to_string(nMin) +
+             " points.";
+    }
+    break;
+  case Value::CSpline:
+    nMin = minSizeForCSplineInterpolation();
+    if (size < nMin) {
+      return "CSpline interpolation requires at least " + std::to_string(nMin) +
+             " points.";
+    }
+    break;
+  }
+  return std::string();
+}
+
 /**
  * Apply the interpolation method to the given histogram
  * @param inOut A reference to a histogram to interpolate
diff --git a/Framework/Algorithms/src/MonteCarloAbsorption.cpp b/Framework/Algorithms/src/MonteCarloAbsorption.cpp
index 8cdd44d385b28484d9a87dd5fa26e689768243b1..3251cc82c748b20dc9aaba475d9022b470cdea26 100644
--- a/Framework/Algorithms/src/MonteCarloAbsorption.cpp
+++ b/Framework/Algorithms/src/MonteCarloAbsorption.cpp
@@ -153,6 +153,23 @@ void MonteCarloAbsorption::exec() {
   setProperty("OutputWorkspace", std::move(outputWS));
 }
 
+/**
+ * Validate the input properties.
+ * @return a map where keys are property names and values the found issues
+ */
+std::map<std::string, std::string> MonteCarloAbsorption::validateInputs() {
+  std::map<std::string, std::string> issues;
+  const int nlambda = getProperty("NumberOfWavelengthPoints");
+  InterpolationOption interpOpt;
+  const std::string interpValue = getPropertyValue("Interpolation");
+  interpOpt.set(interpValue);
+  const auto nlambdaIssue = interpOpt.validateInputSize(nlambda);
+  if (!nlambdaIssue.empty()) {
+    issues["NumberOfWavelengthPoints"] = nlambdaIssue;
+  }
+  return issues;
+}
+
 /**
  * Run the simulation over the whole input workspace
  * @param inputWS A reference to the input workspace
diff --git a/Framework/Algorithms/test/InterpolationOptionTest.h b/Framework/Algorithms/test/InterpolationOptionTest.h
index c29b2b9f5c07fbea0f96e8f37fd219636566fa4a..d5d2fc95a52c272fc5cee3760d1fb0d4a5c93193 100644
--- a/Framework/Algorithms/test/InterpolationOptionTest.h
+++ b/Framework/Algorithms/test/InterpolationOptionTest.h
@@ -5,6 +5,7 @@
 
 #include "MantidAlgorithms/InterpolationOption.h"
 #include "MantidHistogramData/Histogram.h"
+#include "MantidHistogramData/Interpolate.h"
 #include "MantidHistogramData/Points.h"
 #include "MantidHistogramData/LinearGenerator.h"
 #include "MantidKernel/PropertyWithValue.h"
@@ -89,6 +90,19 @@ public:
     TS_ASSERT_THROWS(interpolateOpt.set(""), std::invalid_argument);
   }
 
+  void test_validateInputSize() {
+    using namespace Mantid::HistogramData;
+    auto minSize = minSizeForCSplineInterpolation();
+    InterpolationOption opt;
+    opt.set("CSpline");
+    TS_ASSERT(opt.validateInputSize(minSize).empty())
+    TS_ASSERT(!opt.validateInputSize(minSize - 1).empty())
+    minSize = minSizeForLinearInterpolation();
+    opt.set("Linear");
+    TS_ASSERT(opt.validateInputSize(minSize).empty())
+    TS_ASSERT(!opt.validateInputSize(minSize - 1).empty())
+  }
+
 private:
   void checkData(const Histogram &input, const Histogram &output,
                  const std::vector<double> &expectedY) {
diff --git a/Framework/Algorithms/test/MonteCarloAbsorptionTest.h b/Framework/Algorithms/test/MonteCarloAbsorptionTest.h
index 67f1d7e6109772f5312194f6c8a389fd7c03885a..f2af9f99ab1273514b49d5b1f2696952f774a6f5 100644
--- a/Framework/Algorithms/test/MonteCarloAbsorptionTest.h
+++ b/Framework/Algorithms/test/MonteCarloAbsorptionTest.h
@@ -241,6 +241,18 @@ public:
     TS_ASSERT_THROWS(mcabs->execute(), std::invalid_argument);
   }
 
+  void test_Lower_Limit_for_Number_of_Wavelengths() {
+    using Mantid::Kernel::DeltaEMode;
+    TestWorkspaceDescriptor wsProps = {1, 10, Environment::SampleOnly,
+                                       DeltaEMode::Direct, -1, -1};
+    int nlambda{1};
+    TS_ASSERT_THROWS(runAlgorithm(wsProps, nlambda, "Linear"),
+                     std::runtime_error)
+    nlambda = 2;
+    TS_ASSERT_THROWS(runAlgorithm(wsProps, nlambda, "CSpline"),
+                     std::runtime_error)
+  }
+
   void test_event_workspace() {
     auto inputWS =
         WorkspaceCreationHelper::createEventWorkspaceWithFullInstrument(5, 2,
diff --git a/Framework/Crystal/inc/MantidCrystal/FindSXPeaksHelper.h b/Framework/Crystal/inc/MantidCrystal/FindSXPeaksHelper.h
index 6cfaa5a275d3bea6c983d3ba022dac29b5c5c044..3d02683b7aee3fdca20c8a3a47bb7f4846368ca4 100644
--- a/Framework/Crystal/inc/MantidCrystal/FindSXPeaksHelper.h
+++ b/Framework/Crystal/inc/MantidCrystal/FindSXPeaksHelper.h
@@ -84,6 +84,8 @@ private:
   int npixels;
   /// Unit vector in the direction of the wavevector
   Kernel::V3D _unitWaveVector;
+  /// Q Convention
+  std::string _convention;
 };
 
 using yIt = Mantid::HistogramData::HistogramY::const_iterator;
diff --git a/Framework/Crystal/src/FindSXPeaks.cpp b/Framework/Crystal/src/FindSXPeaks.cpp
index 39efe9630e75601a701edbd846b12a6ca59ce157..1fe579335872f6b66a245e7db38b66b649d7f360 100644
--- a/Framework/Crystal/src/FindSXPeaks.cpp
+++ b/Framework/Crystal/src/FindSXPeaks.cpp
@@ -1,6 +1,9 @@
 #include "MantidCrystal/FindSXPeaks.h"
 #include "MantidAPI/HistogramValidator.h"
 #include "MantidAPI/WorkspaceUnitValidator.h"
+#include "MantidAPI/Run.h"
+#include "MantidGeometry/Instrument/Goniometer.h"
+#include "MantidIndexing/IndexInfo.h"
 #include "MantidKernel/BoundedValidator.h"
 #include "MantidKernel/CompositeValidator.h"
 #include "MantidKernel/EnabledWhenProperty.h"
@@ -294,6 +297,8 @@ then convert SXPeaks objects to PeakObjects and add them to the output workspace
 @param progress: a progress object
 */
 void FindSXPeaks::reducePeakList(const peakvector &pcv, Progress &progress) {
+  MatrixWorkspace_const_sptr localworkspace = getProperty("InputWorkspace");
+  auto &goniometerMatrix = localworkspace->run().getGoniometer().getR();
   auto compareStrategy = getCompareStrategy();
   auto reductionStrategy = getReducePeakListStrategy(compareStrategy.get());
   auto finalv = reductionStrategy->reduce(pcv, progress);
@@ -305,6 +310,7 @@ void FindSXPeaks::reducePeakList(const peakvector &pcv, Progress &progress) {
       if (peak) {
         peak->setIntensity(finalPeak.getIntensity());
         peak->setDetectorID(finalPeak.getDetectorId());
+        peak->setGoniometerMatrix(goniometerMatrix);
         m_peaks->addPeak(*peak);
         delete peak;
       }
diff --git a/Framework/Crystal/src/FindSXPeaksHelper.cpp b/Framework/Crystal/src/FindSXPeaksHelper.cpp
index 61bf93057bc2557f1b2b2fd8fa4c4bdcd3ce9a66..083bdcc040e06de87c90fccda52202aa81dd15af 100644
--- a/Framework/Crystal/src/FindSXPeaksHelper.cpp
+++ b/Framework/Crystal/src/FindSXPeaksHelper.cpp
@@ -4,6 +4,7 @@
 #include "MantidKernel/make_unique.h"
 #include "MantidTypes/SpectrumDefinition.h"
 #include "MantidAPI/Progress.h"
+#include "MantidKernel/ConfigService.h"
 #include "MantidKernel/Logger.h"
 
 #include <cmath>
@@ -90,6 +91,7 @@ SXPeak::SXPeak(double t, double phi, double intensity,
   auto detDir = (detPos - samplePos);
   detDir.normalize();
   _unitWaveVector = beamDir - detDir;
+  _convention = Kernel::ConfigService::Instance().getString("Q.convention");
 }
 
 /**
@@ -130,6 +132,10 @@ Getter for LabQ
 @return q vector
 */
 Mantid::Kernel::V3D SXPeak::getQ() const {
+  double qSign = 1.0;
+  if (_convention == "Crystallography") {
+    qSign = -1.0;
+  }
   double vi = _Ltot / (_t * 1e-6);
   // wavenumber = h_bar / mv
   double wi = PhysicalConstants::h_bar / (PhysicalConstants::NeutronMass * vi);
@@ -138,7 +144,7 @@ Mantid::Kernel::V3D SXPeak::getQ() const {
   // wavevector=1/wavenumber = 2pi/wavelength
   double wvi = 1.0 / wi;
   // Now calculate the wavevector of the scattered neutron
-  return _unitWaveVector * wvi;
+  return _unitWaveVector * wvi * qSign;
 }
 
 /**
diff --git a/Framework/Crystal/test/FindSXPeaksTest.h b/Framework/Crystal/test/FindSXPeaksTest.h
index 88350e01de13ba3cb93e0aa0a748ede0db16c367..eb8d40c9a03c335d9f4eb3a7b7281e38d849b464 100644
--- a/Framework/Crystal/test/FindSXPeaksTest.h
+++ b/Framework/Crystal/test/FindSXPeaksTest.h
@@ -6,6 +6,7 @@
 #include "MantidTestHelpers/WorkspaceCreationHelper.h"
 #include "MantidCrystal/FindSXPeaks.h"
 #include "MantidGeometry/Crystal/IPeak.h"
+#include "MantidGeometry/Instrument/Goniometer.h"
 
 using namespace Mantid::API;
 using namespace Mantid::Crystal;
@@ -255,6 +256,56 @@ public:
     TSM_ASSERT_EQUALS("Should have found zero peaks after cropping", 0,
                       result->rowCount());
   }
+
+  void testSetGoniometer() {
+    // creates a workspace where all y-values are 2
+    Workspace2D_sptr workspace =
+        WorkspaceCreationHelper::create2DWorkspaceWithFullInstrument(10, 10);
+    // Stick a peak in histoIndex = 1.
+    makeOnePeak(1, 40, 5, workspace);
+
+    // Get baseline for Q of Peak
+    FindSXPeaks alg;
+    alg.initialize();
+    alg.setProperty("InputWorkspace", workspace);
+    alg.setProperty("OutputWorkspace", "found_peaks");
+    alg.execute();
+    TSM_ASSERT("FindSXPeak should have been executed.", alg.isExecuted());
+
+    IPeaksWorkspace_sptr result = boost::dynamic_pointer_cast<IPeaksWorkspace>(
+        Mantid::API::AnalysisDataService::Instance().retrieve("found_peaks"));
+    TSM_ASSERT_EQUALS("Should have found one peak!", 1, result->rowCount());
+
+    Mantid::Kernel::V3D qNoRot = result->getPeak(0).getQSampleFrame();
+
+    // Set Goniometer to 180 degrees
+    Mantid::Geometry::Goniometer gonio;
+    gonio.makeUniversalGoniometer();
+    gonio.setRotationAngle(1, 180);
+    workspace->mutableRun().setGoniometer(gonio, false);
+
+    // Find peaks again
+    FindSXPeaks alg2;
+    alg2.initialize();
+    alg2.setProperty("InputWorkspace", workspace);
+    alg2.setProperty("OutputWorkspace", "found_peaks");
+    alg2.execute();
+    TSM_ASSERT("FindSXPeak should have been executed.", alg2.isExecuted());
+
+    result = boost::dynamic_pointer_cast<IPeaksWorkspace>(
+        Mantid::API::AnalysisDataService::Instance().retrieve("found_peaks"));
+    TSM_ASSERT_EQUALS("Should have found one peak!", 1, result->rowCount());
+
+    Mantid::Kernel::V3D qRot = result->getPeak(0).getQSampleFrame();
+
+    // Peak should be rotated by 180 degrees around y in Q compared to baseline
+    // Use ASSERT_DELTA to account for minor error introduced by deg/rad
+    // conversion
+    TSM_ASSERT_DELTA("Q_x should be unchanged!", qNoRot.X(), qRot.X(), 10e-10);
+    TSM_ASSERT_DELTA("Q_y should be inverted!", qNoRot.Y(), qRot.Y() * (-1),
+                     10e-10);
+    TSM_ASSERT_DELTA("Q_z should be unchanged!", qNoRot.Z(), qRot.Z(), 10e-10);
+  }
 };
 
 //=====================================================================================
diff --git a/Framework/CurveFitting/inc/MantidCurveFitting/Algorithms/SplineInterpolation.h b/Framework/CurveFitting/inc/MantidCurveFitting/Algorithms/SplineInterpolation.h
index 39c5989cadf37861d96f79da8aaa18fd0a241ec2..0d4af58d67a244ad85aff9c680b2435bd2b69027 100644
--- a/Framework/CurveFitting/inc/MantidCurveFitting/Algorithms/SplineInterpolation.h
+++ b/Framework/CurveFitting/inc/MantidCurveFitting/Algorithms/SplineInterpolation.h
@@ -1,9 +1,9 @@
 #ifndef MANTID_CURVEFITTING_SPLINEINTERPOLATION_H_
 #define MANTID_CURVEFITTING_SPLINEINTERPOLATION_H_
 
-#include "MantidKernel/System.h"
 #include "MantidAPI/Algorithm.h"
 #include "MantidCurveFitting/Functions/CubicSpline.h"
+#include "MantidKernel/System.h"
 
 namespace Mantid {
 namespace CurveFitting {
@@ -50,12 +50,8 @@ public:
   const std::string name() const override;
   int version() const override;
   const std::string category() const override;
-  /// Summary of algorithms purpose
-  const std::string summary() const override {
-    return "Interpolates a set of spectra onto a spline defined by a second "
-           "input workspace. Optionally, this algorithm can also calculate "
-           "derivatives up to order 2 as a side product";
-  }
+  const std::string summary() const override;
+  std::map<std::string, std::string> validateInputs() override;
 
 private:
   void init() override;
@@ -70,25 +66,37 @@ private:
   setupOutputWorkspace(API::MatrixWorkspace_sptr mws,
                        API::MatrixWorkspace_sptr iws) const;
 
-  /// convert a binned workspace to point data. Uses mean of the bins as point
+  /// convert a binned workspace to point data using ConvertToPointData
   API::MatrixWorkspace_sptr
-  convertBinnedData(API::MatrixWorkspace_sptr workspace) const;
+  convertBinnedData(API::MatrixWorkspace_sptr workspace);
 
   /// set the points that define the spline used for interpolation of a
   /// workspace
   void setInterpolationPoints(API::MatrixWorkspace_const_sptr inputWorkspace,
-                              const int row) const;
+                              const size_t row) const;
 
   /// Calculate the interpolation of the input workspace against the spline and
   /// store it in outputWorkspace
   void calculateSpline(API::MatrixWorkspace_const_sptr inputWorkspace,
                        API::MatrixWorkspace_sptr outputWorkspace,
-                       int row) const;
+                       const size_t row) const;
 
   /// Calculate the derivatives of the input workspace from the spline.
   void calculateDerivatives(API::MatrixWorkspace_const_sptr inputWorkspace,
                             API::MatrixWorkspace_sptr outputWorkspace,
-                            int order) const;
+                            const size_t order) const;
+
+  /// Find the the interpolation range
+  std::pair<size_t, size_t>
+  findInterpolationRange(API::MatrixWorkspace_const_sptr iwspt,
+                         API::MatrixWorkspace_sptr mwspt, const size_t row);
+
+  /// Extrapolates flat for the points outside the x-range
+  void extrapolateFlat(API::MatrixWorkspace_sptr ows,
+                       API::MatrixWorkspace_const_sptr iwspt, const size_t row,
+                       const std::pair<size_t, size_t> &indices,
+                       const bool doDerivs,
+                       std::vector<API::MatrixWorkspace_sptr> &derivs) const;
 };
 
 } // namespace Algorithms
diff --git a/Framework/CurveFitting/src/Algorithms/SplineInterpolation.cpp b/Framework/CurveFitting/src/Algorithms/SplineInterpolation.cpp
index 2640d3716519783637645978f5f26786049670ba..9cd6f62a1920daf4dab915a1b389015631baa581 100644
--- a/Framework/CurveFitting/src/Algorithms/SplineInterpolation.cpp
+++ b/Framework/CurveFitting/src/Algorithms/SplineInterpolation.cpp
@@ -1,11 +1,15 @@
-#include "MantidAPI/TextAxis.h"
+#include "MantidCurveFitting/Algorithms/SplineInterpolation.h"
+
 #include "MantidAPI/MatrixWorkspace.h"
 #include "MantidAPI/NumericAxis.h"
 #include "MantidAPI/Progress.h"
+#include "MantidAPI/TextAxis.h"
 #include "MantidAPI/WorkspaceFactory.h"
 #include "MantidAPI/WorkspaceGroup.h"
 #include "MantidKernel/BoundedValidator.h"
-#include "MantidCurveFitting/Algorithms/SplineInterpolation.h"
+
+#include <algorithm>
+#include <stdexcept>
 
 namespace Mantid {
 namespace CurveFitting {
@@ -38,6 +42,13 @@ const std::string SplineInterpolation::category() const {
   return "Optimization;CorrectionFunctions\\BackgroundCorrections";
 }
 
+/// Algorithm's summary description. @see Algorithm::summary
+const std::string SplineInterpolation::summary() const {
+  return "Interpolates a set of spectra onto a spline defined by a second "
+         "input workspace. Optionally, this algorithm can also calculate "
+         "derivatives up to order 2 as a side product";
+}
+
 //----------------------------------------------------------------------------------------------
 /** Initialize the algorithm's properties.
  */
@@ -64,6 +75,43 @@ void SplineInterpolation::init() {
   auto validator = boost::make_shared<BoundedValidator<int>>(0, 2);
   declareProperty("DerivOrder", 2, validator,
                   "Order to derivatives to calculate.");
+
+  declareProperty("Linear2Points", false, "Set to true to perform linear "
+                                          "interpolation if only 2 points are "
+                                          "present.");
+}
+
+//----------------------------------------------------------------------------------------------
+/** Input validation for the WorkspaceToInterpolate
+  */
+std::map<std::string, std::string> SplineInterpolation::validateInputs() {
+  // initialise map (result)
+  std::map<std::string, std::string> result;
+
+  // get inputs that need validation
+  const bool linear = getProperty("Linear2Points");
+  const int derivOrder = getProperty("DerivOrder");
+
+  MatrixWorkspace_const_sptr iwsValid = getProperty("WorkspaceToInterpolate");
+  const size_t binsNo = iwsValid->blocksize();
+
+  // The minimum number of points for cubic splines is 3
+  if (binsNo < 2) {
+    result["WorkspaceToInterpolate"] = "Workspace must have minimum 2 points.";
+  } else if (binsNo == 2) {
+    if (!linear) {
+      result["WorkspaceToInterpolate"] =
+          "Workspace has only 2 points, "
+          "you can enable linear interpolation by "
+          "setting the property Linear2Points. Otherwise "
+          "provide a minimum of 3 points.";
+    } else if (derivOrder == 2) {
+      result["DerivOrder"] = "Linear interpolation is requested, hence "
+                             "derivative order can be maximum 1.";
+    }
+  }
+
+  return result;
 }
 
 //----------------------------------------------------------------------------------------------
@@ -71,76 +119,122 @@ void SplineInterpolation::init() {
  */
 void SplineInterpolation::exec() {
   // read in algorithm parameters
-  int order = static_cast<int>(getProperty("DerivOrder"));
+  const int derivOrder = getProperty("DerivOrder");
+  const size_t order = static_cast<size_t>(derivOrder);
 
   // set input workspaces
   MatrixWorkspace_sptr mws = getProperty("WorkspaceToMatch");
   MatrixWorkspace_sptr iws = getProperty("WorkspaceToInterpolate");
 
-  int histNo = static_cast<int>(iws->getNumberHistograms());
+  const size_t histNo = iws->getNumberHistograms();
+  const size_t binsNo = iws->blocksize();
+  const size_t histNoToMatch = mws->getNumberHistograms();
 
   // vector of multiple derivative workspaces
   std::vector<MatrixWorkspace_sptr> derivs(histNo);
 
   // warn user that we only use first spectra in matching workspace
-  if (mws->getNumberHistograms() > 1) {
+  if (histNoToMatch > 1) {
     g_log.warning()
         << "Algorithm can only interpolate against a single data set. "
-           "Only the first data set will be used.\n";
+           "Only the x-axis of the first spectrum will be used.\n";
   }
 
-  // convert data to binned data as required
-  MatrixWorkspace_sptr mwspt = convertBinnedData(mws);
-  MatrixWorkspace_const_sptr iwspt = convertBinnedData(iws);
-
   MatrixWorkspace_sptr outputWorkspace = setupOutputWorkspace(mws, iws);
 
   Progress pgress(this, 0.0, 1.0, histNo);
 
-  // for each histogram in workspace, calculate interpolation and derivatives
-  for (int i = 0; i < histNo; ++i) {
-    // Create and instance of the cubic spline function
-    m_cspline = boost::make_shared<CubicSpline>();
-    // set the interpolation points
-    setInterpolationPoints(iwspt, i);
-
-    // compare the data set against our spline
-    calculateSpline(mwspt, outputWorkspace, i);
-    outputWorkspace->setSharedX(i, mws->sharedX(0));
-
-    // check if we want derivatives
-    if (order > 0) {
+  // first prepare the derivatives if needed
+  if (order > 0) {
+    for (size_t i = 0; i < histNo; ++i) {
       derivs[i] = WorkspaceFactory::Instance().create(mws, order);
-      auto vAxis = new API::NumericAxis(order);
-
-      // calculate the derivatives for each order chosen
-      for (int j = 0; j < order; ++j) {
-        vAxis->setValue(j, j + 1);
+      NumericAxis *vAxis = new NumericAxis(order);
+      for (size_t j = 0; j < order; ++j) {
+        vAxis->setValue(j, static_cast<int>(j) + 1.);
         derivs[i]->setSharedX(j, mws->sharedX(0));
-        calculateDerivatives(mwspt, derivs[i], j + 1);
       }
-
       derivs[i]->replaceAxis(1, vAxis);
     }
-
-    pgress.report();
   }
 
+  // convert data to binned data if initially histogrammed, do not alter the
+  // original inputs; these should be used in subsequent processing, however,
+  // note that the parent of the output workspace is still mws, and not mwspt!
+  // meaning that it can be either histogram or point data dependent on the mws
+  MatrixWorkspace_sptr mwspt = convertBinnedData(mws);
+  MatrixWorkspace_const_sptr iwspt = convertBinnedData(iws);
+
+  if (binsNo > 2) {
+    // perform cubic spline interpolation
+    // for each histogram in workspace, calculate interpolation and derivatives
+    for (size_t i = 0; i < histNo; ++i) {
+      // Create and instance of the cubic spline function
+      m_cspline = boost::make_shared<CubicSpline>();
+      // set the interpolation points
+      setInterpolationPoints(iwspt, i);
+      // compare the data set against our spline
+      calculateSpline(mwspt, outputWorkspace, i);
+      // calculate derivatives for each order
+      for (size_t j = 0; j < order; ++j) {
+        calculateDerivatives(mwspt, derivs[i], j + 1);
+      }
+      pgress.report();
+    }
+  } else {
+    // perform linear interpolation
+
+    // first check that the x-axis (first spectrum) is sorted ascending
+    if (!std::is_sorted(mwspt->x(0).rawData().begin(),
+                        mwspt->x(0).rawData().end())) {
+      throw std::runtime_error(
+          "X-axis of the workspace to match is not sorted. "
+          "Consider calling SortXAxis before.");
+    }
+
+    for (size_t i = 0; i < histNo; ++i) {
+      // set up the function that needs to be interpolated
+      std::unique_ptr<gsl_interp_accel, void (*)(gsl_interp_accel *)> acc(
+          gsl_interp_accel_alloc(), gsl_interp_accel_free);
+      std::unique_ptr<gsl_interp, void (*)(gsl_interp *)> linear(
+          gsl_interp_alloc(gsl_interp_linear, binsNo), gsl_interp_free);
+      gsl_interp_linear->init(linear.get(), &(iwspt->x(i)[0]),
+                              &(iwspt->y(i)[0]), binsNo);
+
+      // figure out the interpolation range
+      const std::pair<size_t, size_t> range =
+          findInterpolationRange(iwspt, mwspt, i);
+
+      // perform interpolation in the range
+      for (size_t k = range.first; k < range.second; ++k) {
+        gsl_interp_linear->eval(linear.get(), &(iwspt->x(i)[0]),
+                                &(iwspt->y(i)[0]), binsNo, mwspt->x(0)[k],
+                                acc.get(), &(outputWorkspace->mutableY(i)[k]));
+        // calculate only 1st order derivative if needed
+        if (order > 0) {
+          gsl_interp_linear->eval_deriv(
+              linear.get(), &(iwspt->x(i)[0]), &(iwspt->y(i)[0]), binsNo,
+              mwspt->x(0)[k], acc.get(), &(derivs[i]->mutableY(0)[k]));
+        }
+      }
+      // flat extrapolation outside the range
+      extrapolateFlat(outputWorkspace, iwspt, i, range, order > 0, derivs);
+      pgress.report();
+    }
+  }
   // Store the output workspaces
   std::string derivWsName = getPropertyValue("OutputWorkspaceDeriv");
   if (order > 0 && derivWsName != "") {
     // Store derivatives in a grouped workspace
     WorkspaceGroup_sptr wsg = WorkspaceGroup_sptr(new WorkspaceGroup);
-    for (int i = 0; i < histNo; ++i) {
+    for (size_t i = 0; i < histNo; ++i) {
       wsg->addWorkspace(derivs[i]);
     }
     setProperty("OutputWorkspaceDeriv", wsg);
   }
-
   setProperty("OutputWorkspace", outputWorkspace);
 }
 
-/**Copy the meta data for the input workspace to an output workspace and create
+/** Copy the meta data for the input workspace to an output workspace and create
  *it with the desired number of spectra.
  * Also labels the axis of each spectra with Yi, where i is the index
  *
@@ -151,49 +245,36 @@ void SplineInterpolation::exec() {
 API::MatrixWorkspace_sptr
 SplineInterpolation::setupOutputWorkspace(API::MatrixWorkspace_sptr mws,
                                           API::MatrixWorkspace_sptr iws) const {
-  size_t numSpec = iws->getNumberHistograms();
+  const size_t numSpec = iws->getNumberHistograms();
   MatrixWorkspace_sptr outputWorkspace =
       WorkspaceFactory::Instance().create(mws, numSpec);
-
-  // Use the vertical axis form the workspace to interpolate on the output WS
+  // share x-axes with the first spectrum of mws
+  for (size_t i = 0; i < numSpec; ++i) {
+    outputWorkspace->setSharedX(i, mws->sharedX(0));
+  }
+  // use the vertical (spectrum) axis form the iws
   Axis *vAxis = iws->getAxis(1)->clone(mws.get());
   outputWorkspace->replaceAxis(1, vAxis);
-
   return outputWorkspace;
 }
 
-/**Convert a binned workspace to point data
+/** Convert a binned workspace to point data
  *
  * @param workspace :: The input workspace
- * @return the converted workspace containing point data
+ * @return The converted workspace containing point data
  */
 MatrixWorkspace_sptr
-SplineInterpolation::convertBinnedData(MatrixWorkspace_sptr workspace) const {
+SplineInterpolation::convertBinnedData(MatrixWorkspace_sptr workspace) {
   if (workspace->isHistogramData()) {
-    const size_t histNo = workspace->getNumberHistograms();
-    const size_t size = workspace->y(0).size();
-
-    // make a new workspace for the point data
-    MatrixWorkspace_sptr pointWorkspace =
-        WorkspaceFactory::Instance().create(workspace, histNo, size, size);
-
-    // loop over each histogram
-    for (size_t i = 0; i < histNo; ++i) {
-      const auto &xValues = workspace->x(i);
-      pointWorkspace->setSharedY(i, workspace->sharedY(i));
-
-      auto &newXValues = pointWorkspace->mutableX(i);
-
-      // set x values to be average of bin bounds
-      for (size_t j = 0; j < size; ++j) {
-        newXValues[j] = (xValues[j] + xValues[j + 1]) / 2;
-      }
-    }
-
-    return pointWorkspace;
+    g_log.warning("Histogram data provided, converting to point data");
+    Algorithm_sptr converter = createChildAlgorithm("ConvertToPointData");
+    converter->initialize();
+    converter->setProperty("InputWorkspace", workspace);
+    converter->execute();
+    return converter->getProperty("OutputWorkspace");
+  } else {
+    return workspace;
   }
-
-  return workspace;
 }
 
 /** Sets the points defining the spline
@@ -203,15 +284,15 @@ SplineInterpolation::convertBinnedData(MatrixWorkspace_sptr workspace) const {
  * @param row :: The row of spectra to use
  */
 void SplineInterpolation::setInterpolationPoints(
-    MatrixWorkspace_const_sptr inputWorkspace, const int row) const {
+    MatrixWorkspace_const_sptr inputWorkspace, const size_t row) const {
   const auto &xIn = inputWorkspace->x(row);
   const auto &yIn = inputWorkspace->y(row);
-  int size = static_cast<int>(xIn.size());
+  const size_t size = xIn.size();
 
   // pass x attributes and y parameters to CubicSpline
-  m_cspline->setAttributeValue("n", size);
+  m_cspline->setAttributeValue("n", static_cast<int>(size));
 
-  for (int i = 0; i < size; ++i) {
+  for (size_t i = 0; i < size; ++i) {
     m_cspline->setXAttribute(i, xIn[i]);
     m_cspline->setParameter(i, yIn[i]);
   }
@@ -225,7 +306,7 @@ void SplineInterpolation::setInterpolationPoints(
  */
 void SplineInterpolation::calculateDerivatives(
     API::MatrixWorkspace_const_sptr inputWorkspace,
-    API::MatrixWorkspace_sptr outputWorkspace, int order) const {
+    API::MatrixWorkspace_sptr outputWorkspace, const size_t order) const {
   // get x and y parameters from workspaces
   const size_t nData = inputWorkspace->y(0).size();
   const double *xValues = &(inputWorkspace->x(0)[0]);
@@ -243,7 +324,7 @@ void SplineInterpolation::calculateDerivatives(
  */
 void SplineInterpolation::calculateSpline(
     MatrixWorkspace_const_sptr inputWorkspace,
-    MatrixWorkspace_sptr outputWorkspace, int row) const {
+    MatrixWorkspace_sptr outputWorkspace, const size_t row) const {
   // setup input parameters
   const size_t nData = inputWorkspace->y(0).size();
   const double *xValues = &(inputWorkspace->x(0)[0]);
@@ -253,6 +334,88 @@ void SplineInterpolation::calculateSpline(
   m_cspline->function1D(yValues, xValues, nData);
 }
 
+/** Extrapolates flat for the points outside the x-range
+ * This is used for linear case only, to be consistent with cubic spline case
+ * @param ows : output workspace
+ * @param iwspt : workspace to interpolate
+ * @param row : the workspace index
+ * @param indices : the pair of x-axis indices defining the extrapolation range
+ * @param doDerivs : whether derivatives are requested
+ * @param derivs : the vector of derivative workspaces
+*/
+void SplineInterpolation::extrapolateFlat(
+    MatrixWorkspace_sptr ows, MatrixWorkspace_const_sptr iwspt,
+    const size_t row, const std::pair<size_t, size_t> &indices,
+    const bool doDerivs, std::vector<MatrixWorkspace_sptr> &derivs) const {
+
+  const double yFirst = iwspt->y(row).front();
+  const double yLast = iwspt->y(row).back();
+  for (size_t bin = 0; bin < indices.first; ++bin) {
+    ows->mutableY(row)[bin] = yFirst;
+    if (doDerivs) {
+      // if derivatives are requested
+      derivs[row]->mutableY(0)[bin] = 0.;
+    }
+  }
+  for (size_t bin = indices.second; bin < ows->blocksize(); ++bin) {
+    ows->mutableY(row)[bin] = yLast;
+    if (doDerivs) {
+      // if derivatives are requested
+      derivs[row]->mutableY(0)[bin] = 0.;
+    }
+  }
+}
+
+/** Find the region that has to be interpolated
+ * E.g. iwspt x-axis is from 50-100, while mwspt x-axis is 0-200, this will
+ * return
+ * the pair of the indices of mwspt, that are just above 50, and just below 100
+ * This is used for linear case only, to be consistent with cubic spline case
+ * @param iwspt : workspace to interpolate
+ * @param mwspt : workspace to match
+ * @param row : the workspace index
+ * @return : pair of indices for representing the interpolation range
+*/
+std::pair<size_t, size_t>
+SplineInterpolation::findInterpolationRange(MatrixWorkspace_const_sptr iwspt,
+                                            MatrixWorkspace_sptr mwspt,
+                                            const size_t row) {
+
+  auto xAxisIn = iwspt->x(row).rawData();
+  std::sort(xAxisIn.begin(), xAxisIn.end());
+  const auto &xAxisOut = mwspt->x(0).rawData();
+
+  size_t firstIndex = 0;
+  size_t lastIndex = xAxisOut.size();
+
+  if (xAxisOut.front() >= xAxisIn.back()) {
+    lastIndex = firstIndex;
+  } else if (xAxisOut.back() <= xAxisIn.front()) {
+    firstIndex = lastIndex;
+  } else {
+    for (size_t i = 0; i < xAxisOut.size(); ++i) {
+      if (xAxisOut[i] > xAxisIn.front()) {
+        firstIndex = i;
+        break;
+      }
+    }
+    for (size_t i = 0; i < xAxisOut.size(); ++i) {
+      if (xAxisOut[i] > xAxisIn.back()) {
+        lastIndex = i;
+        break;
+      }
+    }
+  }
+
+  std::string log = "Workspace index " + std::to_string(row) +
+                    ": Will perform flat extrapolation outside bin range: " +
+                    std::to_string(firstIndex) + " to " +
+                    std::to_string(lastIndex) + "\n";
+
+  g_log.debug(log);
+
+  return std::make_pair(firstIndex, lastIndex);
+}
 } // namespace Algorithms
 } // namespace CurveFitting
 } // namespace Mantid
diff --git a/Framework/CurveFitting/test/Algorithms/SplineInterpolationTest.h b/Framework/CurveFitting/test/Algorithms/SplineInterpolationTest.h
index abffe7f19eb8ddc150e0912e0f376946e9271583..e6f5a2540149ad0078eb00f670cf7620331350e5 100644
--- a/Framework/CurveFitting/test/Algorithms/SplineInterpolationTest.h
+++ b/Framework/CurveFitting/test/Algorithms/SplineInterpolationTest.h
@@ -64,6 +64,82 @@ public:
     checkOutput(alg);
   }
 
+  void testLinear2Point() {
+
+    MatrixWorkspace_sptr iws =
+        WorkspaceCreationHelper::create2DWorkspaceFromFunction(
+            SplineFunc(), 3, 2.1, 4.9, 1.4, true);
+
+    MatrixWorkspace_sptr mws =
+        WorkspaceCreationHelper::create2DWorkspaceFromFunction(
+            SplineFunc(), 2, 1.6, 5.6, 0.4, true);
+
+    SplineInterpolation alg;
+    runAlgorithm(alg, 1, iws, mws, true);
+
+    checkOutputLinear(alg);
+  }
+
+  void checkOutputLinear(const SplineInterpolation &alg) const {
+    MatrixWorkspace_const_sptr ows = alg.getProperty("OutputWorkspace");
+    WorkspaceGroup_const_sptr derivs = alg.getProperty("OutputWorkspaceDeriv");
+
+    TS_ASSERT(ows->isHistogramData())
+    TS_ASSERT_EQUALS(ows->getNumberHistograms(), 3)
+    TS_ASSERT_EQUALS(ows->blocksize(), 9)
+
+    NumericAxis *xAxis = dynamic_cast<NumericAxis *>(ows->getAxis(0));
+    TS_ASSERT(xAxis);
+
+    for (size_t i = 0; i < ows->blocksize(); i++) {
+      double ref = 1.6 + static_cast<int>(i) * 0.4;
+      TS_ASSERT_EQUALS((*xAxis)(i), ref);
+    }
+
+    const auto &y = ows->y(0).rawData();
+
+    TS_ASSERT_EQUALS(y[0], 4.2)
+    TS_ASSERT_EQUALS(y[1], 4.2)
+    TS_ASSERT_EQUALS(y[2], 4.2)
+    TS_ASSERT_DELTA(y[3], 4.6, 1e-10)
+    TS_ASSERT_DELTA(y[4], 5.4, 1e-10)
+    TS_ASSERT_DELTA(y[5], 6.2, 1e-10)
+    TS_ASSERT_DELTA(y[6], 7., 1e-10)
+    TS_ASSERT_EQUALS(y[7], 7.)
+    TS_ASSERT_EQUALS(y[8], 7.)
+
+    for (size_t i = 0; i < ows->getNumberHistograms(); ++i) {
+      MatrixWorkspace_const_sptr derivsWs =
+          boost::dynamic_pointer_cast<const MatrixWorkspace>(
+              derivs->getItem(i));
+
+      NumericAxis *derivVAxis =
+          dynamic_cast<NumericAxis *>(derivsWs->getAxis(1));
+      TS_ASSERT(derivVAxis);
+      TS_ASSERT_EQUALS((*derivVAxis)(0), 1);
+      NumericAxis *derivXAxis =
+          dynamic_cast<NumericAxis *>(derivsWs->getAxis(0));
+      TS_ASSERT(derivXAxis);
+
+      for (size_t i = 0; i < ows->blocksize(); i++) {
+        double ref = 1.6 + static_cast<int>(i) * 0.4;
+        TS_ASSERT_EQUALS((*derivXAxis)(i), ref);
+      }
+
+      const auto &deriv = derivsWs->y(0);
+
+      TS_ASSERT_EQUALS(deriv[0], 0.)
+      TS_ASSERT_EQUALS(deriv[1], 0.)
+      TS_ASSERT_EQUALS(deriv[2], 0.)
+      TS_ASSERT_DELTA(deriv[3], 2., 1e-10)
+      TS_ASSERT_DELTA(deriv[4], 2., 1e-10)
+      TS_ASSERT_DELTA(deriv[5], 2., 1e-10)
+      TS_ASSERT_DELTA(deriv[6], 2., 1e-10)
+      TS_ASSERT_EQUALS(deriv[7], 0.)
+      TS_ASSERT_EQUALS(deriv[8], 0.)
+    }
+  }
+
   void testExecMultipleSpectra() {
     int order(2), spectra(3);
 
@@ -146,7 +222,8 @@ public:
 
   void runAlgorithm(SplineInterpolation &alg, int order,
                     const Mantid::API::MatrixWorkspace_sptr &iws,
-                    const Mantid::API::MatrixWorkspace_sptr &mws) const {
+                    const Mantid::API::MatrixWorkspace_sptr &mws,
+                    const bool linear = false) const {
     alg.initialize();
     alg.isInitialized();
     alg.setChild(true);
@@ -157,6 +234,7 @@ public:
 
     alg.setProperty("WorkspaceToInterpolate", iws);
     alg.setProperty("WorkspaceToMatch", mws);
+    alg.setProperty("Linear2Points", linear);
 
     TS_ASSERT_THROWS_NOTHING(alg.execute());
     TS_ASSERT(alg.isExecuted());
diff --git a/Framework/HistogramData/inc/MantidHistogramData/Interpolate.h b/Framework/HistogramData/inc/MantidHistogramData/Interpolate.h
index 57a71b50c23ba11c3343374646e248c9c668b492..11b073cd43669469a246c4a8db2a4c0238031ec4 100644
--- a/Framework/HistogramData/inc/MantidHistogramData/Interpolate.h
+++ b/Framework/HistogramData/inc/MantidHistogramData/Interpolate.h
@@ -49,6 +49,11 @@ MANTID_HISTOGRAMDATA_DLL void interpolateCSplineInplace(Histogram &inOut,
 
 MANTID_HISTOGRAMDATA_DLL void interpolateCSplineInplace(const Histogram &input,
                                                         Histogram &output);
+MANTID_HISTOGRAMDATA_DLL
+size_t minSizeForCSplineInterpolation();
+
+MANTID_HISTOGRAMDATA_DLL
+size_t minSizeForLinearInterpolation();
 
 } // namespace HistogramData
 } // namespace Mantid
diff --git a/Framework/HistogramData/src/Interpolate.cpp b/Framework/HistogramData/src/Interpolate.cpp
index ee94e9e6b6ad12cce4ed305ad081312fd1bd5f47..ee5691b4c86e6189de232abee7855e3e2c248eeb 100644
--- a/Framework/HistogramData/src/Interpolate.cpp
+++ b/Framework/HistogramData/src/Interpolate.cpp
@@ -13,6 +13,9 @@ using Mantid::HistogramData::HistogramY;
 
 namespace {
 
+/// Enumeration for supported interpolation types.
+enum class InterpolationType { LINEAR, CSPLINE };
+
 constexpr const char *LINEAR_NAME = "Linear";
 constexpr const char *CSPLINE_NAME = "CSpline";
 
@@ -66,9 +69,14 @@ void sanityCheck(const Histogram &input, const size_t stepSize,
  * @param output A histogram where interpolated values are store
  * @throw runtime_error Signals that the sanity check failed.
  */
-void sanityCheck(const Histogram &input, const Histogram &output) {
+void sanityCheck(const Histogram &input, const Histogram &output,
+                 const size_t minInputSize) {
   const auto inPoints = input.points();
   const auto outPoints = output.points();
+  if (inPoints.size() < minInputSize) {
+    throw std::runtime_error(
+        "interpolate - input histogram has too few points");
+  }
   if (outPoints.front() < inPoints.front() ||
       outPoints.back() > inPoints.back()) {
     throw std::runtime_error("interpolate - input does not cover all points in "
@@ -80,9 +88,6 @@ void sanityCheck(const Histogram &input, const Histogram &output) {
   }
 }
 
-/// Enumeration for supported interpolation types.
-enum class InterpolationType { LINEAR, CSPLINE };
-
 /**
  * Perform interpolation in place
  * @param xs A container of x values
@@ -187,6 +192,22 @@ void interpolateYCSplineInplace(const Histogram &input, const size_t stepSize,
 namespace Mantid {
 namespace HistogramData {
 
+/**
+ * Return the minimum size of input points for cpline interpolation.
+ * @return the minimum number of points
+ */
+size_t minSizeForCSplineInterpolation() {
+  return gsl_interp_type_min_size(gsl_interp_cspline);
+}
+
+/**
+ * Return the minimum size of input points for linear interpolation.
+ * @return the minimum number of points
+ */
+size_t minSizeForLinearInterpolation() {
+  return gsl_interp_type_min_size(gsl_interp_linear);
+}
+
 /**
  * Linearly interpolate through the y values of a histogram assuming that the
  * calculated "nodes" are stepSize apart. Currently errors are not treated.
@@ -198,7 +219,7 @@ namespace HistogramData {
  * interpolation. The XMode of the output will match the input histogram.
  */
 Histogram interpolateLinear(const Histogram &input, const size_t stepSize) {
-  sanityCheck(input, stepSize, 2, LINEAR_NAME);
+  sanityCheck(input, stepSize, minSizeForLinearInterpolation(), LINEAR_NAME);
 
   HistogramY ynew(input.y().size());
   interpolateYLinearInplace(input, stepSize, ynew);
@@ -219,7 +240,7 @@ Histogram interpolateLinear(const Histogram &input, const size_t stepSize) {
  * @param stepSize See interpolateLinear
  */
 void interpolateLinearInplace(Histogram &inOut, const size_t stepSize) {
-  sanityCheck(inOut, stepSize, 2, LINEAR_NAME);
+  sanityCheck(inOut, stepSize, minSizeForLinearInterpolation(), LINEAR_NAME);
   interpolateYLinearInplace(inOut, stepSize, inOut.mutableY());
 }
 
@@ -229,7 +250,7 @@ void interpolateLinearInplace(Histogram &inOut, const size_t stepSize) {
  * @param output A histogram containing the interpolated values
  */
 void interpolateLinearInplace(const Histogram &input, Histogram &output) {
-  sanityCheck(input, output);
+  sanityCheck(input, output, minSizeForLinearInterpolation());
   const auto &points = input.points().rawData();
   const auto &y = input.y().rawData();
   const auto &interpPoints = output.points();
@@ -249,7 +270,7 @@ void interpolateLinearInplace(const Histogram &input, Histogram &output) {
  * interpolation. The XMode of the output will match the input histogram.
  */
 Histogram interpolateCSpline(const Histogram &input, const size_t stepSize) {
-  sanityCheck(input, stepSize, 4, CSPLINE_NAME);
+  sanityCheck(input, stepSize, minSizeForCSplineInterpolation(), CSPLINE_NAME);
 
   HistogramY ynew(input.y().size());
   interpolateYCSplineInplace(input, stepSize, ynew);
@@ -270,7 +291,7 @@ Histogram interpolateCSpline(const Histogram &input, const size_t stepSize) {
  * @param stepSize See interpolateCSpline
  */
 void interpolateCSplineInplace(Histogram &inOut, const size_t stepSize) {
-  sanityCheck(inOut, stepSize, 4, CSPLINE_NAME);
+  sanityCheck(inOut, stepSize, minSizeForCSplineInterpolation(), CSPLINE_NAME);
   interpolateYCSplineInplace(inOut, stepSize, inOut.mutableY());
 }
 
@@ -280,7 +301,7 @@ void interpolateCSplineInplace(Histogram &inOut, const size_t stepSize) {
  * @param output A histogram where to store the interpolated values
  */
 void interpolateCSplineInplace(const Histogram &input, Histogram &output) {
-  sanityCheck(input, output);
+  sanityCheck(input, output, minSizeForCSplineInterpolation());
   const auto &points = input.points().rawData();
   const auto &y = input.y().rawData();
   const auto &interpPoints = output.points();
diff --git a/Framework/HistogramData/test/InterpolateTest.h b/Framework/HistogramData/test/InterpolateTest.h
index b28617e60f4c01801e63c64166c33be936293b6e..8f5c0c07a9bb95a1f23a09e47087b82bdb8f4797 100644
--- a/Framework/HistogramData/test/InterpolateTest.h
+++ b/Framework/HistogramData/test/InterpolateTest.h
@@ -82,6 +82,13 @@ public:
     checkData(input, inOut, expectedY);
   }
 
+  void test_interpolateLinearInplace_interpolates() {
+    Histogram input(Points(2, LinearGenerator(0, 1.0)), {-0.72, -0.72});
+    Histogram output(Points(1, LinearGenerator(0.5, 1.0)), {0.0});
+    interpolateLinearInplace(input, output);
+    TS_ASSERT_EQUALS(output.y()[0], -0.72)
+  }
+
   // ---------------------------------------------------------------------------
   // Success cases - cspline in-place no copy
   // ---------------------------------------------------------------------------
@@ -116,6 +123,13 @@ public:
     checkData(input, inOut, expectedY);
   }
 
+  void test_interpolateCSplineInplace_interpolates() {
+    Histogram input(Points(3, LinearGenerator(0, 1.0)), {-0.72, -0.72, -0.72});
+    Histogram output(Points(1, LinearGenerator(0.1, 1.0)), {0.0});
+    interpolateCSplineInplace(input, output);
+    TS_ASSERT_EQUALS(output.y()[0], -0.72);
+  }
+
   // ---------------------------------------------------------------------------
   // Success cases - linear edge X data
   // ---------------------------------------------------------------------------
@@ -250,6 +264,14 @@ public:
         interpolateLinear(Histogram(Points(2, LinearGenerator(0, 0.5))), 1),
         std::runtime_error);
   }
+
+  void test_interpolatelinearinplace_throws_if_input_has_less_than_2_points() {
+    Histogram input(Points(1, LinearGenerator(0.1, 0.1)));
+    Histogram output(Points(1, LinearGenerator(0.1, 0.1)));
+    TS_ASSERT_THROWS(interpolateLinearInplace(input, output),
+                     std::runtime_error)
+  }
+
   void
   test_interpolatelinear_throws_if_stepsize_greater_or_equal_number_points() {
     TS_ASSERT_THROWS(
@@ -277,6 +299,14 @@ public:
         interpolateCSpline(Histogram(Points(3, LinearGenerator(0, 0.5))), 1),
         std::runtime_error);
   }
+
+  void test_interpolatecsplineinplace_throws_if_input_has_less_than_3_points() {
+    Histogram input(Points(2, LinearGenerator(0, 1.0)));
+    Histogram output(Points(5, LinearGenerator(0.1, 0.1)));
+    TS_ASSERT_THROWS(interpolateCSplineInplace(input, output),
+                     std::runtime_error)
+  }
+
   void
   test_interpolatecspline_throws_if_stepsize_greater_or_equal_number_points() {
     TS_ASSERT_THROWS(
diff --git a/Framework/Kernel/inc/MantidKernel/WarningSuppressions.h b/Framework/Kernel/inc/MantidKernel/WarningSuppressions.h
index 6240e9ee9c25bb28f61bdb0e7758c2878bb5f800..ada11e03eea175c75235c032da5b2c828234fc2c 100644
--- a/Framework/Kernel/inc/MantidKernel/WarningSuppressions.h
+++ b/Framework/Kernel/inc/MantidKernel/WarningSuppressions.h
@@ -80,7 +80,7 @@
 // Defining this macro separately since clang-tidy tries to add spaces around
 // the hyphen and we use it in a lot of test files.
 // clang-format off
-#if defined(GCC_VERSION) && GCC_VERSION >= 50000
+#if defined(__cplusplus) && defined(GCC_VERSION) && GCC_VERSION >= 50000
 #define GCC_DIAG_OFF_SUGGEST_OVERRIDE GCC_DIAG_OFF(suggest-override)
 #define GCC_DIAG_ON_SUGGEST_OVERRIDE GCC_DIAG_ON(suggest-override)
 #else
diff --git a/Framework/Kernel/src/Diffraction.cpp b/Framework/Kernel/src/Diffraction.cpp
index 3cb7ffaebb0182ca324aa0206afbb9d643873474..103d878a8a028bb1fc11ea32b850c104f6f38924 100644
--- a/Framework/Kernel/src/Diffraction.cpp
+++ b/Framework/Kernel/src/Diffraction.cpp
@@ -57,7 +57,7 @@ struct tof_to_d_difc_only {
 
 /// Applies the equation d=(TOF-tzero)/difc
 struct tof_to_d_difc_and_tzero {
-  tof_to_d_difc_and_tzero(const double difc, const double tzero)
+  explicit tof_to_d_difc_and_tzero(const double difc, const double tzero)
       : factor(1. / difc), offset(-1. * tzero / difc) {}
 
   double operator()(const double tof) const { return factor * tof + offset; }
@@ -69,7 +69,7 @@ struct tof_to_d_difc_and_tzero {
 };
 
 struct tof_to_d {
-  tof_to_d(const double difc, const double difa, const double tzero) {
+  explicit tof_to_d(const double difc, const double difa, const double tzero) {
     factor1 = -0.5 * difc / difa;
     factor2 = 1. / difa;
     factor3 = (factor1 * factor1) - (tzero / difa);
@@ -111,7 +111,7 @@ std::function<double(double)> getTofToDConversionFunc(const double difc,
 // convert from d-spacing to time-of-flight
 namespace { // anonymous namespace
 struct d_to_tof_difc_only {
-  d_to_tof_difc_only(const double difc) { this->difc = difc; }
+  explicit d_to_tof_difc_only(const double difc) { this->difc = difc; }
 
   double operator()(const double dspacing) const { return difc * dspacing; }
 
@@ -119,7 +119,7 @@ struct d_to_tof_difc_only {
 };
 
 struct d_to_tof_difc_and_tzero {
-  d_to_tof_difc_and_tzero(const double difc, const double tzero) {
+  explicit d_to_tof_difc_and_tzero(const double difc, const double tzero) {
     this->difc = difc;
     this->tzero = tzero;
   }
@@ -133,7 +133,7 @@ struct d_to_tof_difc_and_tzero {
 };
 
 struct d_to_tof {
-  d_to_tof(const double difc, const double difa, const double tzero) {
+  explicit d_to_tof(const double difc, const double difa, const double tzero) {
     this->difc = difc;
     this->difa = difa;
     this->tzero = tzero;
diff --git a/Framework/Properties/Mantid.properties.template b/Framework/Properties/Mantid.properties.template
index 73cc078955f6ac784bbee22f6bb74047a6665852..1c43db9424f4365395f8d03f50c4797c1b27db2e 100644
--- a/Framework/Properties/Mantid.properties.template
+++ b/Framework/Properties/Mantid.properties.template
@@ -20,7 +20,7 @@ default.instrument =
 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 SANS/ORNL_SANS.py Reflectometry/REFL_Reduction.py Reflectometry/REFL_SF_Calculator.py Reflectometry/REFM_Reduction.py Utility/TofConverter.py Reflectometry/ISIS_Reflectometry_Old.py Diffraction/Powder_Diffraction_Reduction.py Utility/FilterEvents.py Diffraction/HFIR_Powder_Diffraction_Reduction.py Diffraction/HFIR_4Circle_Reduction.py Utility/QECoverage.py
+mantidqt.python_interfaces = Direct/DGS_Reduction.py Direct/DGSPlanner.py Direct/PyChop.py SANS/ORNL_SANS.py Reflectometry/REFL_Reduction.py Reflectometry/REFL_SF_Calculator.py Reflectometry/REFM_Reduction.py Utility/TofConverter.py Reflectometry/ISIS_Reflectometry_Old.py Diffraction/Powder_Diffraction_Reduction.py Utility/FilterEvents.py Diffraction/HFIR_Powder_Diffraction_Reduction.py Diffraction/HFIR_4Circle_Reduction.py Utility/QECoverage.py SANS/ISIS_SANS_v2_experimental.py
 
 mantidqt.python_interfaces_directory = @MANTID_ROOT@/scripts
 
diff --git a/Framework/PythonInterface/inc/MantidPythonInterface/kernel/Registry/PropertyManagerFactory.h b/Framework/PythonInterface/inc/MantidPythonInterface/kernel/Registry/PropertyManagerFactory.h
new file mode 100644
index 0000000000000000000000000000000000000000..aac2385308128704a015ad760e0a91e1ecba2d7b
--- /dev/null
+++ b/Framework/PythonInterface/inc/MantidPythonInterface/kernel/Registry/PropertyManagerFactory.h
@@ -0,0 +1,42 @@
+#ifndef MANTID_PYTHONINTERFACE_PROPERTYMANAGERFACTORY_H
+#define MANTID_PYTHONINTERFACE_PROPERTYMANAGERFACTORY_H
+/*
+  Copyright &copy; 2017 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge
+  National Laboratory & European Spallation Source
+
+  This file is part of Mantid.
+
+  Mantid is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 3 of the License, or
+  (at your option) any later version.
+
+  Mantid is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+  File change history is stored at: <https://github.com/mantidproject/mantid>
+  Code Documentation is available at: <http://doxygen.mantidproject.org>
+*/
+#include <boost/shared_ptr.hpp>
+#include <boost/python/dict.hpp>
+
+namespace Mantid {
+namespace Kernel {
+class PropertyManager;
+}
+namespace PythonInterface {
+namespace Registry {
+
+/// Create a C++ PropertyMananager from a Python dictionary
+boost::shared_ptr<Kernel::PropertyManager>
+createPropertyManager(const boost::python::dict &mapping);
+}
+}
+}
+
+#endif // MANTID_PYTHONINTERFACE_PROPERTYMANAGERFACTORY_H
diff --git a/Framework/PythonInterface/mantid/CMakeLists.txt b/Framework/PythonInterface/mantid/CMakeLists.txt
index 0e13e726c2e2da2bb90e300781d8a898362bd63c..0787726737ba6f196bef090ec6afa77e7fef391a 100644
--- a/Framework/PythonInterface/mantid/CMakeLists.txt
+++ b/Framework/PythonInterface/mantid/CMakeLists.txt
@@ -41,10 +41,11 @@ add_dependencies ( PythonKernelModule PythonModule ) # Ensure the module files a
 add_subdirectory ( geometry )
 add_subdirectory ( api )
 add_subdirectory ( dataobjects )
+add_subdirectory ( _plugins )
 
 # Create an overall target
 add_custom_target ( PythonInterface DEPENDS PythonKernelModule PythonGeometryModule 
-                    PythonAPIModule PythonDataObjectsModule )
+                    PythonAPIModule PythonDataObjectsModule PythonCurveFittingModule )
 set_property ( TARGET PythonInterface PROPERTY FOLDER "MantidFramework/Python" )
 
 ###########################################################################
diff --git a/Framework/PythonInterface/mantid/__init__.py b/Framework/PythonInterface/mantid/__init__.py
index b76a24c277547aac0e15883569af0be80ac0fa2d..d66fdfb6390fb263576079cb3c37b627c19ea253 100644
--- a/Framework/PythonInterface/mantid/__init__.py
+++ b/Framework/PythonInterface/mantid/__init__.py
@@ -74,6 +74,7 @@ import mantid.kernel as kernel
 import mantid.geometry as geometry
 import mantid.api as api
 import mantid.dataobjects as dataobjects
+import mantid._plugins as _plugins
 
 ###############################################################################
 # Make the aliases from each module accessible in a the mantid namspace
diff --git a/Framework/PythonInterface/mantid/_plugins/CMakeLists.txt b/Framework/PythonInterface/mantid/_plugins/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..8425cf15d05172774f4b2d2c360f500c883b91bf
--- /dev/null
+++ b/Framework/PythonInterface/mantid/_plugins/CMakeLists.txt
@@ -0,0 +1,77 @@
+#############################################################################################
+# __curvefitting Python module
+#############################################################################################
+
+set ( MODULE_TEMPLATE src/curvefitting.cpp.in )
+
+# Files containing export definitions, these are automatically processed
+# -- Do NOT sort this list. The order defines the order in which the export
+#    definitions occur and some depend on their base classes being exported first --
+set ( EXPORT_FILES
+  src/Exports/ProductFunction.cpp
+)
+
+set ( MODULE_DEFINITION ${CMAKE_CURRENT_BINARY_DIR}/curvefitting.cpp )
+create_module ( ${MODULE_TEMPLATE} ${MODULE_DEFINITION} ${EXPORT_FILES} )
+
+#############################################################################################
+# Helper code
+#############################################################################################
+set ( SRC_FILES )
+
+set ( INC_FILES )
+
+set ( PY_FILES __init__.py )
+
+
+#############################################################################################
+# Copy over the pure Python files for the module
+#############################################################################################
+# Set the destination directory
+set ( OUTPUT_DIR ${PYTHON_PKG_ROOT}/_plugins )
+
+if(CMAKE_GENERATOR STREQUAL Xcode)
+  # Set the output directory for the libraries.
+  set ( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PYTHON_PKG_ROOT}/_plugins )
+endif()
+
+copy_files_to_dir ( "${PY_FILES}" ${CMAKE_CURRENT_SOURCE_DIR} ${OUTPUT_DIR}
+                     PYTHON_INSTALL_FILES )
+
+#############################################################################################
+# Create the target for this directory
+#############################################################################################
+set ( FRAMEWORK_DIR ../../.. )
+include_directories ( ${FRAMEWORK_DIR}/CurveFitting/inc )
+
+add_library ( PythonCurveFittingModule ${MODULE_DEFINITION} ${EXPORT_FILES} ${SRC_FILES}
+              ${INC_FILES} ${PYTHON_INSTALL_FILES} )
+set_python_properties( PythonCurveFittingModule _curvefitting )
+set_target_output_directory ( PythonCurveFittingModule ${OUTPUT_DIR} .pyd )
+
+# Add the required dependencies
+target_link_libraries ( PythonCurveFittingModule LINK_PRIVATE ${TCMALLOC_LIBRARIES_LINKTIME}
+            PythonAPIModule
+            PythonGeometryModule
+            PythonKernelModule
+            API
+            CurveFitting
+            Kernel
+            HistogramData
+            Geometry
+            ${PYTHON_LIBRARIES}
+            ${POCO_LIBRARIES}
+            ${Boost_LIBRARIES} )
+
+
+if (OSX_VERSION VERSION_GREATER 10.8)
+  set_target_properties( PythonCurveFittingModule PROPERTIES
+                         INSTALL_RPATH "@loader_path/../../../MacOS;@loader_path/../kernel/;@loader_path/../geometry/;@loader_path/../api/")
+endif ()
+###########################################################################
+# Installation settings
+###########################################################################
+install ( TARGETS PythonCurveFittingModule ${SYSTEM_PACKAGE_TARGET} DESTINATION ${BIN_DIR}/mantid/_plugins )
+
+# Pure Python files
+install ( FILES ${PY_FILES} DESTINATION ${BIN_DIR}/mantid/_plugins )
diff --git a/Framework/PythonInterface/mantid/_plugins/__init__.py b/Framework/PythonInterface/mantid/_plugins/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..4c704bc3867a478538a3a051688b20def102409b
--- /dev/null
+++ b/Framework/PythonInterface/mantid/_plugins/__init__.py
@@ -0,0 +1,22 @@
+"""
+Plugins
+=======
+
+Defines Python objects that wrap classes from the framework defined as plugins. 
+The classes defined here simply export the class types to Python, but not any additional functionality. 
+This allows Boost Python to automatically downcast a type to the actual leaf type, 
+making it easier to work with these objects in Python
+
+For example, ProductFunction is made available as ProductFunction rather than IFunction 
+and so methods, such as __len__() & add() inherited from CompositeFunction are made available.
+
+The names from the library are not imported by default as it is best if the interface classes
+are used for checks such as isinstance()
+"""
+from __future__ import (absolute_import, division,
+                        print_function)
+
+###############################################################################
+# Load the C++ library and register the C++ class exports
+###############################################################################
+from . import _curvefitting
diff --git a/Framework/PythonInterface/mantid/_plugins/src/Exports/ProductFunction.cpp b/Framework/PythonInterface/mantid/_plugins/src/Exports/ProductFunction.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..cab757e1b270e33a54c0fbd72730ddc9c2332cb4
--- /dev/null
+++ b/Framework/PythonInterface/mantid/_plugins/src/Exports/ProductFunction.cpp
@@ -0,0 +1,13 @@
+#include "MantidCurveFitting/Functions/ProductFunction.h"
+#include <boost/python/class.hpp>
+#include <boost/python/overloads.hpp>
+
+using Mantid::CurveFitting::Functions::ProductFunction;
+using Mantid::API::CompositeFunction;
+using namespace boost::python;
+
+void export_ProductFunction() {
+
+  class_<ProductFunction, bases<CompositeFunction>, boost::noncopyable>(
+      "ProductFunction", "Composite Fit functions");
+}
diff --git a/Framework/PythonInterface/mantid/_plugins/src/curvefitting.cpp.in b/Framework/PythonInterface/mantid/_plugins/src/curvefitting.cpp.in
new file mode 100644
index 0000000000000000000000000000000000000000..16ab375a4d8ccf6f46b6022a0f66c1ee2c8d1f00
--- /dev/null
+++ b/Framework/PythonInterface/mantid/_plugins/src/curvefitting.cpp.in
@@ -0,0 +1,18 @@
+/*****************************************************************************************/
+/********** PLEASE NOTE! THIS FILE WAS AUTO-GENERATED FROM CMAKE.  ***********************/
+/********** Source = curvefitting.cpp.in **********************************************************/
+/*****************************************************************************************/
+#include <boost/python/def.hpp>
+#include <boost/python/module.hpp>
+#include <boost/python/docstring_options.hpp>
+
+// Forward declare
+@EXPORT_DECLARE@
+
+BOOST_PYTHON_MODULE(_curvefitting)
+{
+  // Doc string options - User defined, python arguments, C++ call signatures
+  boost::python::docstring_options docstrings(true, true, false);
+
+@EXPORT_FUNCTIONS@
+}
diff --git a/Framework/PythonInterface/mantid/kernel/CMakeLists.txt b/Framework/PythonInterface/mantid/kernel/CMakeLists.txt
index a1690bd727d38c629c26c1b5d5afa3a031d5769a..a53b47eb01d8838f2fe76bf44b688297039185a9 100644
--- a/Framework/PythonInterface/mantid/kernel/CMakeLists.txt
+++ b/Framework/PythonInterface/mantid/kernel/CMakeLists.txt
@@ -75,6 +75,7 @@ set ( SRC_FILES
   src/Converters/PyObjectToVMD.cpp
   src/Converters/WrapWithNumpy.cpp
   src/Registry/MappingTypeHandler.cpp
+  src/Registry/PropertyManagerFactory.cpp
   src/Registry/PropertyWithValueFactory.cpp
   src/Registry/SequenceTypeHandler.cpp
   src/Registry/TypeRegistry.cpp
@@ -109,6 +110,7 @@ set ( INC_FILES
   ${HEADER_DIR}/kernel/Policies/VectorToNumpy.h
   ${HEADER_DIR}/kernel/Registry/MappingTypeHandler.h
   ${HEADER_DIR}/kernel/Registry/PropertyValueHandler.h
+  ${HEADER_DIR}/kernel/Registry/PropertyManagerFactory.h
   ${HEADER_DIR}/kernel/Registry/PropertyWithValueFactory.h
   ${HEADER_DIR}/kernel/Registry/SequenceTypeHandler.h
   ${HEADER_DIR}/kernel/Registry/TypedPropertyValueHandler.h
diff --git a/Framework/PythonInterface/mantid/kernel/src/Exports/IPropertyManager.cpp b/Framework/PythonInterface/mantid/kernel/src/Exports/IPropertyManager.cpp
index 89ad48a464a106017c125eadb557e080a618ceb1..879cbe384f8efc73b873c5cd1d8132117e8f37b1 100644
--- a/Framework/PythonInterface/mantid/kernel/src/Exports/IPropertyManager.cpp
+++ b/Framework/PythonInterface/mantid/kernel/src/Exports/IPropertyManager.cpp
@@ -11,6 +11,7 @@
 #include <boost/python/list.hpp>
 #include <boost/python/register_ptr_to_python.hpp>
 #include <boost/python/return_internal_reference.hpp>
+#include <boost/python/str.hpp>
 
 using namespace Mantid::Kernel;
 namespace Registry = Mantid::PythonInterface::Registry;
@@ -29,11 +30,15 @@ namespace {
  */
 void setProperty(IPropertyManager &self, const std::string &name,
                  const boost::python::object &value) {
-  typedef extract<std::string> from_pystr;
-  // String values can be set directly
-  from_pystr cppstr(value);
+  extract<std::string> cppstr(value);
+
   if (cppstr.check()) {
     self.setPropertyValue(name, cppstr());
+#if PY_VERSION_HEX < 0x03000000
+  } else if (PyUnicode_Check(value.ptr())) {
+    self.setPropertyValue(name,
+                          extract<std::string>(str(value).encode("utf-8"))());
+#endif
   } else {
     try {
       Property *p = self.getProperty(name);
diff --git a/Framework/PythonInterface/mantid/kernel/src/Exports/PropertyManager.cpp b/Framework/PythonInterface/mantid/kernel/src/Exports/PropertyManager.cpp
index e801bcabc29d3fb9f10424b0b754d05a790506f2..725aa4ee068a5e35e36e5ab5440f210e90ebe91b 100644
--- a/Framework/PythonInterface/mantid/kernel/src/Exports/PropertyManager.cpp
+++ b/Framework/PythonInterface/mantid/kernel/src/Exports/PropertyManager.cpp
@@ -4,31 +4,32 @@
                                 // design
 #endif
 #include "MantidPythonInterface/kernel/GetPointer.h"
+#include "MantidPythonInterface/kernel/Registry/PropertyManagerFactory.h"
 #include "MantidKernel/IPropertyManager.h"
 #include "MantidKernel/PropertyManager.h"
 
 #include <boost/python/class.hpp>
+#include <boost/python/make_constructor.hpp>
 
+using Mantid::PythonInterface::Registry::createPropertyManager;
 using Mantid::Kernel::IPropertyManager;
 using Mantid::Kernel::PropertyManager;
+using Mantid::Kernel::PropertyManager_sptr;
 
 using namespace boost::python;
 
 GET_POINTER_SPECIALIZATION(PropertyManager)
 
 void export_PropertyManager() {
-  typedef boost::shared_ptr<PropertyManager> PropertyManager_sptr;
 
   // The second argument defines the actual type held within the Python object.
-  // This means that when a PropertyManager is constructed in Python it actually
-  // used
-  // a shared_ptr to the object rather than a raw pointer. This knowledge is
-  // used by
-  // DataServiceExporter::extractCppValue to assume that it can always extract a
-  // shared_ptr
-  // type
+  // This means that when a PropertyManager is constructed in Python
+  // it actually used a shared_ptr to the object rather than a raw pointer.
+  // This knowledge is used by DataServiceExporter::extractCppValue to assume
+  // that it can always extract a shared_ptr type
   class_<PropertyManager, PropertyManager_sptr, bases<IPropertyManager>,
-         boost::noncopyable>("PropertyManager");
+         boost::noncopyable>("PropertyManager")
+      .def("__init__", make_constructor(&createPropertyManager));
 }
 
 #ifdef _MSC_VER
diff --git a/Framework/PythonInterface/mantid/kernel/src/Exports/PropertyManagerDataService.cpp b/Framework/PythonInterface/mantid/kernel/src/Exports/PropertyManagerDataService.cpp
index 7113e286462c8ff7fcf117d28b6a78c5a9ad9af5..be80c22864f22bd33dced769f171306b7663d5ad 100644
--- a/Framework/PythonInterface/mantid/kernel/src/Exports/PropertyManagerDataService.cpp
+++ b/Framework/PythonInterface/mantid/kernel/src/Exports/PropertyManagerDataService.cpp
@@ -1,5 +1,6 @@
 #include "MantidPythonInterface/kernel/GetPointer.h"
 #include "MantidPythonInterface/kernel/DataServiceExporter.h"
+#include "MantidPythonInterface/kernel/Registry/PropertyManagerFactory.h"
 
 #include "MantidKernel/PropertyManagerDataService.h"
 #include "MantidKernel/PropertyManager.h"
@@ -10,11 +11,37 @@
 using namespace Mantid::API;
 using namespace Mantid::Kernel;
 using Mantid::PythonInterface::DataServiceExporter;
+using Mantid::PythonInterface::Registry::createPropertyManager;
 using namespace boost::python;
 
 /// Weak pointer to DataItem typedef
 typedef boost::weak_ptr<PropertyManager> PropertyManager_wptr;
 
+namespace {
+/**
+ * Add a dictionary to the data service directly. It creates a PropertyManager
+ * on the way in.
+ * @param self A reference to the PropertyManagerDataService
+ * @param name The name of the object
+ * @param mapping A dict object
+ */
+void addFromDict(PropertyManagerDataServiceImpl &self, const std::string &name,
+                 const dict &mapping) {
+  self.add(name, createPropertyManager(mapping));
+}
+/**
+ * Add or replace a dictionary to the data service directly. It creates
+ * a PropertyManager on the way in.
+ * @param self A reference to the PropertyManagerDataService
+ * @param name The name of the object
+ * @param mapping A dict object
+ */
+void addOrReplaceFromDict(PropertyManagerDataServiceImpl &self,
+                          const std::string &name, const dict &mapping) {
+  self.addOrReplace(name, createPropertyManager(mapping));
+}
+}
+
 GET_POINTER_SPECIALIZATION(PropertyManagerDataServiceImpl)
 
 void export_PropertyManagerDataService() {
@@ -28,5 +55,8 @@ void export_PropertyManagerDataService() {
   pmdType.def("Instance", &PropertyManagerDataService::Instance,
               return_value_policy<reference_existing_object>(),
               "Return a reference to the singleton instance")
-      .staticmethod("Instance");
+      .staticmethod("Instance")
+      // adds an overload from a dictionary
+      .def("add", &addFromDict)
+      .def("addOrReplace", &addOrReplaceFromDict);
 }
diff --git a/Framework/PythonInterface/mantid/kernel/src/Registry/MappingTypeHandler.cpp b/Framework/PythonInterface/mantid/kernel/src/Registry/MappingTypeHandler.cpp
index 4fb274e8d537988fe90fac30d81fc3763f28ece6..0ef7925eae536abbe9b4cd6149a6585d754de050 100644
--- a/Framework/PythonInterface/mantid/kernel/src/Registry/MappingTypeHandler.cpp
+++ b/Framework/PythonInterface/mantid/kernel/src/Registry/MappingTypeHandler.cpp
@@ -1,16 +1,14 @@
 #include "MantidPythonInterface/kernel/Registry/MappingTypeHandler.h"
+#include "MantidPythonInterface/kernel/Registry/PropertyManagerFactory.h"
 #include "MantidPythonInterface/kernel/Registry/PropertyWithValueFactory.h"
 
 #include "MantidKernel/PropertyManager.h"
 #include "MantidKernel/PropertyManagerProperty.h"
 #include "MantidKernel/PropertyWithValue.h"
 
-#include <boost/make_shared.hpp>
 #include <boost/python/dict.hpp>
-#include <boost/python/extract.hpp>
 
 using boost::python::dict;
-using boost::python::extract;
 using boost::python::handle;
 using boost::python::len;
 using boost::python::object;
@@ -23,31 +21,6 @@ using Kernel::PropertyWithValue;
 namespace PythonInterface {
 namespace Registry {
 
-namespace {
-/**
- * Create a new PropertyManager from the given dict
- * @param mapping A wrapper around a Python dict instance
- * @return A shared_ptr to a new PropertyManager
- */
-PropertyManager_sptr createPropertyManager(const dict &mapping) {
-  auto pmgr = boost::make_shared<PropertyManager>();
-#if PY_MAJOR_VERSION >= 3
-  object view(mapping.attr("items")());
-  object itemIter(handle<>(PyObject_GetIter(view.ptr())));
-#else
-  object itemIter(mapping.attr("iteritems")());
-#endif
-  auto length = len(mapping);
-  for (ssize_t i = 0; i < length; ++i) {
-    const object keyValue(handle<>(PyIter_Next(itemIter.ptr())));
-    const std::string cppkey = extract<std::string>(keyValue[0])();
-    pmgr->declareProperty(PropertyWithValueFactory::create(cppkey, keyValue[1],
-                                                           Direction::Input));
-  }
-  return pmgr;
-}
-}
-
 /**
  * Sets the named property in the PropertyManager by extracting a new
  * PropertyManager from the Python object
diff --git a/Framework/PythonInterface/mantid/kernel/src/Registry/PropertyManagerFactory.cpp b/Framework/PythonInterface/mantid/kernel/src/Registry/PropertyManagerFactory.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..7fffa286d4a43ce1d92d035cee2fac336f77e004
--- /dev/null
+++ b/Framework/PythonInterface/mantid/kernel/src/Registry/PropertyManagerFactory.cpp
@@ -0,0 +1,43 @@
+#include "MantidPythonInterface/kernel/Registry/PropertyManagerFactory.h"
+#include "MantidPythonInterface/kernel/Registry/PropertyWithValueFactory.h"
+#include "MantidKernel/PropertyManager.h"
+
+#include <boost/make_shared.hpp>
+#include <boost/python/extract.hpp>
+
+using boost::python::extract;
+using boost::python::handle;
+using boost::python::object;
+
+namespace Mantid {
+using Kernel::Direction;
+using Kernel::PropertyManager;
+
+namespace PythonInterface {
+namespace Registry {
+
+/**
+ * @param mapping A Python dictionary instance
+ * @return A new C++ PropertyManager instance
+ */
+boost::shared_ptr<Kernel::PropertyManager>
+createPropertyManager(const boost::python::dict &mapping) {
+  auto pmgr = boost::make_shared<PropertyManager>();
+#if PY_MAJOR_VERSION >= 3
+  object view(mapping.attr("items")());
+  object itemIter(handle<>(PyObject_GetIter(view.ptr())));
+#else
+  object itemIter(mapping.attr("iteritems")());
+#endif
+  auto length = len(mapping);
+  for (ssize_t i = 0; i < length; ++i) {
+    const object keyValue(handle<>(PyIter_Next(itemIter.ptr())));
+    const std::string cppkey = extract<std::string>(keyValue[0])();
+    pmgr->declareProperty(PropertyWithValueFactory::create(cppkey, keyValue[1],
+                                                           Direction::Input));
+  }
+  return pmgr;
+}
+}
+}
+}
diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ConvertMultipleRunsToSingleCrystalMD.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ConvertMultipleRunsToSingleCrystalMD.py
index fdf958d3b992c9bc81f61a0bdd620af383787fd9..16123503e88339c030506866320d3c042da87871 100644
--- a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ConvertMultipleRunsToSingleCrystalMD.py
+++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/ConvertMultipleRunsToSingleCrystalMD.py
@@ -7,7 +7,7 @@ from mantid.api import (DataProcessorAlgorithm, mtd, AlgorithmFactory,
 from mantid.simpleapi import (LoadIsawUB, LoadInstrument,
                               SetGoniometer, ConvertToMD, Load,
                               LoadIsawDetCal, LoadMask,
-                              DeleteWorkspace,
+                              DeleteWorkspace, MaskDetectors,
                               ConvertToMDMinMaxGlobal)
 from mantid.kernel import VisibleWhenProperty, PropertyCriterion, Direction
 from mantid import logger
@@ -124,9 +124,11 @@ class ConvertMultipleRunsToSingleCrystalMD(DataProcessorAlgorithm):
                 LoadIsawDetCal(InputWorkspace='__run', Filename=self.getProperty("DetCal").value)
 
             if _masking:
-                LoadMask(Instrument=mtd['__run'].getInstrument().getName(),
-                         InputFile=self.getProperty("MaskFile").value,
-                         OutputWorkspace='__run')
+                if not mtd.doesExist('__mask'):
+                    LoadMask(Instrument=mtd['__run'].getInstrument().getName(),
+                             InputFile=self.getProperty("MaskFile").value,
+                             OutputWorkspace='__mask')
+                MaskDetectors(Workspace='__run',MaskedWorkspace='__mask')
 
             if self.getProperty('SetGoniometer').value:
                 SetGoniometer(Workspace='__run',
@@ -174,6 +176,9 @@ class ConvertMultipleRunsToSingleCrystalMD(DataProcessorAlgorithm):
             DeleteWorkspace('__run')
             progress.report()
 
+        if mtd.doesExist('__mask'):
+            DeleteWorkspace('__mask')
+
         self.setProperty("OutputWorkspace", mtd[_outWS_name])
 
 
diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/EQSANSAzimuthalAverage1D.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/EQSANSAzimuthalAverage1D.py
index ff011810517e041581b563a72f15d375e7f65544..1b9d47e8dfb1418b87fb095ec2080c3271278151 100644
--- a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/EQSANSAzimuthalAverage1D.py
+++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/EQSANSAzimuthalAverage1D.py
@@ -353,6 +353,9 @@ class EQSANSAzimuthalAverage1D(PythonAlgorithm):
         """
         log_binning = self.getProperty("LogBinning").value
         nbins = self.getProperty("NumberOfBins").value
+
+        # This code has been checked that it is using the correct property from the workspace
+        # it just so happens that this is not pointing to what it used to - see EQSANSLoad.cpp
         sample_detector_distance = workspace.getRun().getProperty("sample_detector_distance").value
         nx_pixels = int(workspace.getInstrument().getNumberParameter("number-of-x-pixels")[0])
         ny_pixels = int(workspace.getInstrument().getNumberParameter("number-of-y-pixels")[0])
diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/IndirectILLReductionFWS.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/IndirectILLReductionFWS.py
index 5c8091035f24615a48327421425f1a6f49433eeb..623e80c5777f6f8328741ddacdccb7371756fb29 100644
--- a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/IndirectILLReductionFWS.py
+++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/IndirectILLReductionFWS.py
@@ -381,6 +381,8 @@ class IndirectILLReductionFWS(PythonAlgorithm):
             # Inelastic, do something more complex
             self._ifws_integrate(ws)
 
+        ConvertToPointData(InputWorkspace=ws, OutputWorkspace=ws)
+
         self._perform_unmirror(ws)
 
         self._subscribe_run(ws, energy, label)
@@ -554,7 +556,6 @@ class IndirectILLReductionFWS(PythonAlgorithm):
         for energy in sorted(self._all_runs[label]):
 
             ws_list = self._all_runs[label][energy]
-            size = len(self._all_runs[label][energy])
 
             wsname = self._insert_energy_value(groupname, energy, label)
 
@@ -562,13 +563,9 @@ class IndirectILLReductionFWS(PythonAlgorithm):
             nspectra = mtd[ws_list[0]].getNumberHistograms()
             observable_array = self._get_observable_values(self._all_runs[label][energy])
 
-            y_values = np.zeros(size*nspectra)
-            e_values = np.zeros(size*nspectra)
-            x_values = np.zeros(size*nspectra)
+            ConjoinXRuns(InputWorkspaces=ws_list, OutputWorkspace=wsname)
 
-            CreateWorkspace(DataX=x_values, DataY=y_values, DataE=e_values, NSpec=nspectra,
-                            WorkspaceTitle=wsname, Distribution=True, ParentWorkspace=mtd[ws_list[0]],
-                            OutputWorkspace=wsname)
+            mtd[wsname].setDistribution(True)
 
             run_list = ''  # to set to sample logs
 
@@ -586,16 +583,6 @@ class IndirectILLReductionFWS(PythonAlgorithm):
 
                 mtd[wsname].setX(spectrum, np.array(observable_array))
 
-                y_data = np.zeros(size)
-                e_data = np.zeros(size)
-
-                for channel in range(size):
-                    y_data[channel] = mtd[ws_list[channel]].readY(spectrum)[0]
-                    e_data[channel] = mtd[ws_list[channel]].readE(spectrum)[0]
-
-                mtd[wsname].setY(spectrum, y_data)
-                mtd[wsname].setE(spectrum, e_data)
-
             if self._sortX:
                 SortXAxis(InputWorkspace=wsname, OutputWorkspace=wsname)
 
diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/MDNormSCDPreprocessIncoherent.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/MDNormSCDPreprocessIncoherent.py
new file mode 100644
index 0000000000000000000000000000000000000000..5a12480428170664ab101048da7e072fa0fedf3a
--- /dev/null
+++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/MDNormSCDPreprocessIncoherent.py
@@ -0,0 +1,186 @@
+from __future__ import (absolute_import, division, print_function)
+
+from mantid.api import (DataProcessorAlgorithm, mtd, AlgorithmFactory,
+                        FileProperty, FileAction,
+                        MultipleFileProperty, WorkspaceProperty,
+                        PropertyMode)
+from mantid.simpleapi import (ConvertUnits, CropWorkspace,
+                              LoadInstrument, Minus, Load,
+                              DeleteWorkspace, LoadIsawDetCal,
+                              LoadMask, GroupDetectors, Rebin,
+                              MaskDetectors, SumSpectra, SortEvents,
+                              IntegrateFlux, AnvredCorrection,
+                              NormaliseByCurrent)
+from mantid.kernel import Direction, Property, FloatMandatoryValidator, VisibleWhenProperty, PropertyCriterion
+
+
+class MDNormSCDPreprocessIncoherent(DataProcessorAlgorithm):
+
+    def category(self):
+        return "MDAlgorithms\\Normalisation"
+
+    def name(self):
+        return "MDNormSCDPreprocessIncoherent"
+
+    def summary(self):
+        return "Creates the Solid Angle and Flux workspace from an incoherent scatterer for MDNormSCD"
+
+    def PyInit(self):
+        # files to reduce
+        self.declareProperty(MultipleFileProperty(name="Filename",
+                                                  extensions=["_event.nxs", ".nxs.h5", ".nxs"]),
+                             "Files to combine in reduction")
+
+        # background
+        self.declareProperty(FileProperty(name="Background",defaultValue="",action=FileAction.OptionalLoad,
+                                          extensions=["_event.nxs", ".nxs.h5", ".nxs"]),
+                             "Background run")
+        self.declareProperty("BackgroundScale", 1.0,
+                             doc="The background will be scaled by this number before being subtracted.")
+
+        # Filter by TOF
+        self.copyProperties('LoadEventNexus', ['FilterByTofMin', 'FilterByTofMax'])
+
+        # Cropping
+        self.declareProperty('MomentumMin', Property.EMPTY_DBL, doc="Minimum value in momentum.", validator=FloatMandatoryValidator())
+        self.declareProperty('MomentumMax', Property.EMPTY_DBL, doc="Maximum value in momentum.", validator=FloatMandatoryValidator())
+
+        # Grouping
+        self.declareProperty(FileProperty(name="GroupingFile",defaultValue="",action=FileAction.OptionalLoad,
+                                          extensions=[".xml",".map"]),
+                             "A file that consists of lists of spectra numbers to group. See :ref:`GroupDetectors <algm-GroupDetectors>`")
+
+        # Corrections
+        self.declareProperty('NormaliseByCurrent', True, "Normalise the Solid Angle workspace by the proton charge.")
+        self.declareProperty(FileProperty(name="LoadInstrument",defaultValue="",action=FileAction.OptionalLoad,
+                                          extensions=[".xml"]),
+                             "Load a different instrument IDF onto the data from a file. See :ref:`LoadInstrument <algm-LoadInstrument>`")
+        self.declareProperty(FileProperty(name="DetCal",defaultValue="",action=FileAction.OptionalLoad,
+                                          extensions=[".detcal"]),
+                             "Load an ISAW DetCal calibration onto the data from a file. See :ref:`LoadIsawDetCal <algm-LoadIsawDetCal>`")
+        self.declareProperty(FileProperty(name="MaskFile",defaultValue="",action=FileAction.OptionalLoad,
+                                          extensions=[".xml",".msk"]),
+                             "Masking file for masking. Supported file format is XML and ISIS ASCII. See :ref:`LoadMask <algm-LoadMask>`")
+        # Anvred
+        self.declareProperty('SphericalAbsorptionCorrection', False,
+                             "Apply Spherical Absorption correction using :ref:`AnvredCorrection <algm-AnvredCorrection>`")
+        condition = VisibleWhenProperty("SphericalAbsorptionCorrection", PropertyCriterion.IsNotDefault)
+        self.copyProperties('AnvredCorrection', ['LinearScatteringCoef','LinearAbsorptionCoef','Radius'])
+        self.setPropertySettings("LinearScatteringCoef", condition)
+        self.setPropertySettings("LinearAbsorptionCoef", condition)
+        self.setPropertySettings("Radius", condition)
+
+        # Output
+        self.declareProperty(WorkspaceProperty("SolidAngleOutputWorkspace", "",
+                                               optional=PropertyMode.Mandatory,
+                                               direction=Direction.Output),
+                             "Output Workspace for Solid Angle")
+
+        self.declareProperty(WorkspaceProperty("FluxOutputWorkspace", "",
+                                               optional=PropertyMode.Mandatory,
+                                               direction=Direction.Output),
+                             "Output Workspace for Flux")
+
+        # Background
+        self.setPropertyGroup("Background","Background")
+        self.setPropertyGroup("BackgroundScale","Background")
+
+        # Corrections
+        self.setPropertyGroup("NormaliseByCurrent","Corrections")
+        self.setPropertyGroup("LoadInstrument","Corrections")
+        self.setPropertyGroup("DetCal","Corrections")
+        self.setPropertyGroup("MaskFile","Corrections")
+        self.setPropertyGroup("SphericalAbsorptionCorrection","Corrections")
+        self.setPropertyGroup("LinearScatteringCoef","Corrections")
+        self.setPropertyGroup("LinearAbsorptionCoef","Corrections")
+        self.setPropertyGroup("Radius","Corrections")
+
+    def PyExec(self):
+        _background = bool(self.getProperty("Background").value)
+        _load_inst = bool(self.getProperty("LoadInstrument").value)
+        _norm_current = bool(self.getProperty("NormaliseByCurrent").value)
+        _detcal = bool(self.getProperty("DetCal").value)
+        _masking = bool(self.getProperty("MaskFile").value)
+        _grouping = bool(self.getProperty("GroupingFile").value)
+        _anvred = bool(self.getProperty("SphericalAbsorptionCorrection").value)
+        _SA_name = self.getPropertyValue("SolidAngleOutputWorkspace")
+        _Flux_name = self.getPropertyValue("FluxOutputWorkspace")
+
+        XMin = self.getProperty("MomentumMin").value
+        XMax = self.getProperty("MomentumMax").value
+        rebin_param = ','.join([str(XMin),str(XMax),str(XMax)])
+
+        Load(Filename=self.getPropertyValue("Filename"),
+             OutputWorkspace='__van',
+             FilterByTofMin=self.getProperty("FilterByTofMin").value,
+             FilterByTofMax=self.getProperty("FilterByTofMax").value)
+
+        if _norm_current:
+            NormaliseByCurrent(InputWorkspace='__van',
+                               OutputWorkspace='__van')
+
+        if _background:
+            Load(Filename=self.getProperty("Background").value,
+                 OutputWorkspace='__bkg',
+                 FilterByTofMin=self.getProperty("FilterByTofMin").value,
+                 FilterByTofMax=self.getProperty("FilterByTofMax").value)
+            if _norm_current:
+                NormaliseByCurrent(InputWorkspace='__bkg',
+                                   OutputWorkspace='__bkg')
+            else:
+                pc_van = mtd['__van'].run().getProtonCharge()
+                pc_bkg = mtd['__bkg'].run().getProtonCharge()
+                mtd['__bkg'] *= pc_van/pc_bkg
+            mtd['__bkg'] *= self.getProperty('BackgroundScale').value
+            Minus(LHSWorkspace='__van', RHSWorkspace='__bkg', OutputWorkspace='__van')
+            DeleteWorkspace('__bkg')
+
+        if _load_inst:
+            LoadInstrument(Workspace='__van', Filename=self.getProperty("LoadInstrument").value, RewriteSpectraMap=False)
+        if _detcal:
+            LoadIsawDetCal(InputWorkspace='__van', Filename=self.getProperty("DetCal").value)
+
+        if _masking:
+            LoadMask(Instrument=mtd['__van'].getInstrument().getName(),
+                     InputFile=self.getProperty("MaskFile").value,
+                     OutputWorkspace='__mask')
+            MaskDetectors(Workspace='__van',MaskedWorkspace='__mask')
+            DeleteWorkspace('__mask')
+
+        ConvertUnits(InputWorkspace='__van',OutputWorkspace='__van',Target='Momentum')
+        Rebin(InputWorkspace='__van',OutputWorkspace='__van',Params=rebin_param)
+        CropWorkspace(InputWorkspace='__van',OutputWorkspace='__van',XMin=XMin,XMax=XMax)
+
+        if _anvred:
+            AnvredCorrection(InputWorkspace='__van', OutputWorkspace='__van',
+                             LinearScatteringCoef=self.getProperty("LinearScatteringCoef").value,
+                             LinearAbsorptionCoef=self.getProperty("LinearAbsorptionCoef").value,
+                             Radius=self.getProperty("Radius").value,
+                             OnlySphericalAbsorption='1', PowerLambda ='0')
+
+        # Create solid angle
+        Rebin(InputWorkspace='__van',
+              OutputWorkspace=_SA_name,
+              Params=rebin_param,PreserveEvents=False)
+
+        # Create flux
+        if _grouping:
+            GroupDetectors(InputWorkspace='__van', OutputWorkspace='__van', MapFile=self.getProperty("GroupingFile").value)
+        else:
+            SumSpectra(InputWorkspace='__van', OutputWorkspace='__van')
+
+        Rebin(InputWorkspace='__van',OutputWorkspace='__van',Params=rebin_param)
+        flux = mtd['__van']
+        for i in range(flux.getNumberHistograms()):
+            el=flux.getSpectrum(i)
+            if flux.readY(i)[0] > 0:
+                el.divide(flux.readY(i)[0],flux.readE(i)[0])
+        SortEvents(InputWorkspace='__van', SortBy="X Value")
+        IntegrateFlux(InputWorkspace='__van', OutputWorkspace=_Flux_name, NPoints=10000)
+        DeleteWorkspace('__van')
+
+        self.setProperty("SolidAngleOutputWorkspace", mtd[_SA_name])
+        self.setProperty("FluxOutputWorkspace", mtd[_Flux_name])
+
+
+AlgorithmFactory.subscribe(MDNormSCDPreprocessIncoherent)
diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSCalculateTransmission.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSCalculateTransmission.py
index d8c247dd2658a03233b01799079e367e0ccc1152..85bfaf36bbb484af16b580b68fc1dcbf03fa3859 100644
--- a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSCalculateTransmission.py
+++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSCalculateTransmission.py
@@ -143,7 +143,7 @@ class SANSCalculateTransmission(DataProcessorAlgorithm):
 
         # Get the fit setting for the correct data type, ie either for the Sample of the Can
         fit_type = calculate_transmission_state.fit[DataType.to_string(data_type)].fit_type
-        if fit_type is FitType.Log:
+        if fit_type is FitType.Logarithmic:
             fit_string = "Log"
         elif fit_type is FitType.Polynomial:
             fit_string = "Polynomial"
diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSConvertToQ.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSConvertToQ.py
index 38615003d775ce7f04dc3d9c359dc928b81246a3..2edba033fdd2aaa5c906b28b9dbec550804cd7ac 100644
--- a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSConvertToQ.py
+++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSConvertToQ.py
@@ -152,7 +152,7 @@ class SANSConvertToQ(DataProcessorAlgorithm):
         # Extract relevant settings
         convert_to_q = state.convert_to_q
         max_q_xy = convert_to_q.q_xy_max
-        delta_q_prefix = -1 if convert_to_q.q_xy_step_type is RangeStepType.Log else 1
+        delta_q_prefix = -1. if convert_to_q.q_xy_step_type is RangeStepType.Log else 1.
         delta_q = delta_q_prefix*convert_to_q.q_xy_step
         radius_cutoff = convert_to_q.radius_cutoff / 1000.  # Qxy expects the radius cutoff to be in mm
         wavelength_cutoff = convert_to_q.wavelength_cutoff
diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSCrop.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSCrop.py
index 080e8f59905ae0a7d48c2178cd2d9eafe6a5d6a4..b4313322517434ae871d4b1ade6aade8bef70a4c 100644
--- a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSCrop.py
+++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANS/SANSCrop.py
@@ -9,6 +9,7 @@ from mantid.api import (DataProcessorAlgorithm, MatrixWorkspaceProperty, Algorit
 from sans.common.constants import EMPTY_NAME
 from sans.common.enums import DetectorType
 from sans.common.general_functions import (create_unmanaged_algorithm, append_to_sans_file_tag)
+from sans.algorithm_detail.crop_helper import get_component_name
 
 
 class SANSCrop(DataProcessorAlgorithm):
@@ -28,8 +29,10 @@ class SANSCrop(DataProcessorAlgorithm):
                              doc='The input workspace')
 
         # The component, i.e. HAB or LAB
-        allowed_detectors = StringListValidator(["LAB", "HAB"])
-        self.declareProperty("Component", "LAB", validator=allowed_detectors, direction=Direction.Input,
+        allowed_detectors = StringListValidator([DetectorType.to_string(DetectorType.LAB),
+                                                 DetectorType.to_string(DetectorType.HAB)])
+        self.declareProperty("Component", DetectorType.to_string(DetectorType.LAB), validator=allowed_detectors,
+                             direction=Direction.Input,
                              doc="The component of the instrument to which we want to crop.")
 
         self.declareProperty(MatrixWorkspaceProperty("OutputWorkspace", '',
@@ -61,27 +64,9 @@ class SANSCrop(DataProcessorAlgorithm):
         progress.report("Finished cropping")
 
     def _get_component(self, workspace):
-        comp = self.getProperty("Component").value
-        is_hab = comp == "HAB"
-        if is_hab:
-            component = DetectorType.HAB
-        else:
-            component = DetectorType.LAB
-
-        instrument = workspace.getInstrument()
-        instrument_name = instrument.getName().strip()
-
-        # TODO: Can clean up here: The detector bank selection could be made nicer here, but it is currently not
-        #                          essential.
-        if instrument_name == "SANS2D":
-            component = "front-detector" if component is DetectorType.HAB else "rear-detector"
-        elif instrument_name == "LOQ":
-            component = "HAB" if component is DetectorType.HAB else "main-detector-bank"
-        elif instrument_name == "LARMOR":
-            component = "DetectorBench"
-        else:
-            raise RuntimeError("SANSCrop: The instrument {0} is currently not supported.".format(instrument_name))
-        return component
+        component_as_string = self.getProperty("Component").value
+        component = DetectorType.from_string(component_as_string)
+        return get_component_name(workspace, component)
 
 
 # Register algorithm with Mantid
diff --git a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANSAzimuthalAverage1D.py b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANSAzimuthalAverage1D.py
index 381537902bf94936a6579572293f6596829ac0c8..6c84af42bcaf397376e08106fa568ae1622085df 100644
--- a/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANSAzimuthalAverage1D.py
+++ b/Framework/PythonInterface/plugins/algorithms/WorkflowAlgorithms/SANSAzimuthalAverage1D.py
@@ -200,6 +200,7 @@ class SANSAzimuthalAverage1D(PythonAlgorithm):
             qmin = workspace.getRun().getProperty("qmin").value
             qmax = workspace.getRun().getProperty("qmax").value
         else:
+            #  Checked 8/10/2017 -  this is using the right distance for calculating q
             sample_detector_distance = workspace.getRun().getProperty("sample_detector_distance").value
             nx_pixels = int(workspace.getInstrument().getNumberParameter("number-of-x-pixels")[0])
             ny_pixels = int(workspace.getInstrument().getNumberParameter("number-of-y-pixels")[0])
diff --git a/Framework/PythonInterface/test/python/mantid/CMakeLists.txt b/Framework/PythonInterface/test/python/mantid/CMakeLists.txt
index 7d687eeae4d2bfc6092053b9eb0e9dbab03591b7..438c607131f58d1f88c62b44c31ca312fc5f7a41 100644
--- a/Framework/PythonInterface/test/python/mantid/CMakeLists.txt
+++ b/Framework/PythonInterface/test/python/mantid/CMakeLists.txt
@@ -5,6 +5,7 @@ add_subdirectory( kernel )
 add_subdirectory( geometry )
 add_subdirectory( api )
 add_subdirectory( dataobjects )
+add_subdirectory( _plugins )
 
 set ( TEST_PY_FILES
   ImportModuleTest.py
diff --git a/Framework/PythonInterface/test/python/mantid/_plugins/CMakeLists.txt b/Framework/PythonInterface/test/python/mantid/_plugins/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..4342e2ff8f8264e45996dd792db53bf5ef52a032
--- /dev/null
+++ b/Framework/PythonInterface/test/python/mantid/_plugins/CMakeLists.txt
@@ -0,0 +1,11 @@
+##
+## mantid._plugin tests
+##
+set ( TEST_PY_FILES
+  ProductFunctionTest.py
+)
+
+check_tests_valid ( ${CMAKE_CURRENT_SOURCE_DIR} ${TEST_PY_FILES} )
+
+# Prefix for test=PythonInterfacePlugins
+pyunittest_add_test ( ${CMAKE_CURRENT_SOURCE_DIR} python._plugins ${TEST_PY_FILES} )
\ No newline at end of file
diff --git a/Framework/PythonInterface/test/python/mantid/_plugins/ProductFunctionTest.py b/Framework/PythonInterface/test/python/mantid/_plugins/ProductFunctionTest.py
new file mode 100644
index 0000000000000000000000000000000000000000..4fe513ab7ded849b7e03b8442734ac4e6f7b07c3
--- /dev/null
+++ b/Framework/PythonInterface/test/python/mantid/_plugins/ProductFunctionTest.py
@@ -0,0 +1,30 @@
+# pylint: disable=invalid-name, too-many-public-methods
+from __future__ import (absolute_import, division, print_function)
+
+import unittest
+
+# from mantid.kernel import DateAndTime
+# from mantid.api import EventType
+from mantid.api import CompositeFunction, FunctionFactory
+from mantid._plugins._curvefitting import ProductFunction
+
+class ProductFunctionTest(unittest.TestCase):
+
+    def test_type(self):
+        p = FunctionFactory.createFunction("ProductFunction")
+        self.assertTrue( isinstance(p,ProductFunction) )
+        self.assertTrue( isinstance(p,CompositeFunction) )
+
+    def test_length(self):
+        p = FunctionFactory.createFunction("ProductFunction")
+        self.assertEquals(len(p), 0)
+        
+    def test_addition(self):
+        p = FunctionFactory.createFunction("ProductFunction")
+        g = FunctionFactory.createFunction("Gaussian")
+        p.add(g)
+        p.add(g)
+        self.assertEquals(len(p), 2)
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/Framework/PythonInterface/test/python/mantid/api/AlgorithmTest.py b/Framework/PythonInterface/test/python/mantid/api/AlgorithmTest.py
index e93b83e27edb3d123e5d575c5fba3a25e8aad784..d96483d93234d0c851bb3d62e690b21f145101e2 100644
--- a/Framework/PythonInterface/test/python/mantid/api/AlgorithmTest.py
+++ b/Framework/PythonInterface/test/python/mantid/api/AlgorithmTest.py
@@ -1,10 +1,10 @@
 from __future__ import (absolute_import, division, print_function)
+import six
 
 import unittest
 from mantid.api import AlgorithmID, AlgorithmManager
 from testhelpers import run_algorithm
 
-###########################################################
 
 class AlgorithmTest(unittest.TestCase):
 
@@ -52,7 +52,29 @@ class AlgorithmTest(unittest.TestCase):
         self.assertTrue(ws.getMemorySize() > 0.0 )
 
         as_str = str(alg)
-        self.assertEquals(as_str, '{"name":"CreateWorkspace","properties":{"DataX":"1,2,3","DataY":"1,2,3","OutputWorkspace":"UNUSED_NAME_FOR_CHILD","UnitX":"Wavelength"},"version":1}\n')
+        self.assertEquals(as_str, '{"name":"CreateWorkspace","properties":{"DataX":"1,2,3","DataY":"1,2,3",'
+                          '"OutputWorkspace":"UNUSED_NAME_FOR_CHILD","UnitX":"Wavelength"},"version":1}\n')
+
+    def test_execute_succeeds_with_unicode_props(self):
+        data = [1.0,2.0,3.0]
+        unitx = 'Wavelength'
+        if six.PY2:
+            # force a property value to be unicode to assert conversion happens correctly
+            # this is only an issue in python2
+            unitx = unicode(unitx)
+
+        alg = run_algorithm('CreateWorkspace',DataX=data,DataY=data,NSpec=1,UnitX=unitx,child=True)
+        self.assertEquals(alg.isExecuted(), True)
+        self.assertEquals(alg.isRunning(), False)
+        self.assertEquals(alg.getProperty('NSpec').value, 1)
+        self.assertEquals(type(alg.getProperty('NSpec').value), int)
+        self.assertEquals(alg.getProperty('NSpec').name, 'NSpec')
+        ws = alg.getProperty('OutputWorkspace').value
+        self.assertTrue(ws.getMemorySize() > 0.0 )
+
+        as_str = str(alg)
+        self.assertEquals(as_str, '{"name":"CreateWorkspace","properties":{"DataX":"1,2,3","DataY":"1,2,3",'
+                          '"OutputWorkspace":"UNUSED_NAME_FOR_CHILD","UnitX":"Wavelength"},"version":1}\n')
 
     def test_getAlgorithmID_returns_AlgorithmID_object(self):
         alg = AlgorithmManager.createUnmanaged('Load')
@@ -84,13 +106,14 @@ class AlgorithmTest(unittest.TestCase):
     def test_createChildAlgorithm_respects_keyword_arguments(self):
         parent_alg = AlgorithmManager.createUnmanaged('Load')
         try:
-            child_alg = parent_alg.createChildAlgorithm(name='Rebin',version=1,startProgress=0.5,endProgress=0.9,enableLogging=True)
+            child_alg = parent_alg.createChildAlgorithm(name='Rebin',version=1,startProgress=0.5,
+                                                        endProgress=0.9,enableLogging=True)
         except Exception as exc:
             self.fail("Expected createChildAlgorithm not to throw but it did: %s" % (str(exc)))
 
         # Unknown keyword
-        self.assertRaises(Exception, parent_alg.createChildAlgorithm, name='Rebin',version=1,startProgress=0.5,endProgress=0.9,enableLogging=True, unknownKW=1)
+        self.assertRaises(Exception, parent_alg.createChildAlgorithm, name='Rebin',version=1,startProgress=0.5,
+                          endProgress=0.9,enableLogging=True, unknownKW=1)
 
 if __name__ == '__main__':
     unittest.main()
-
diff --git a/Framework/PythonInterface/test/python/mantid/kernel/CMakeLists.txt b/Framework/PythonInterface/test/python/mantid/kernel/CMakeLists.txt
index 8fe8c0eda2c83dab6601f20427be1242b01f3eef..a62aac820a5c8831e6b0441d7ac088689141f549 100644
--- a/Framework/PythonInterface/test/python/mantid/kernel/CMakeLists.txt
+++ b/Framework/PythonInterface/test/python/mantid/kernel/CMakeLists.txt
@@ -27,6 +27,7 @@ set ( TEST_PY_FILES
   PropertyHistoryTest.py
   PropertyWithValueTest.py
   PropertyManagerTest.py
+  PropertyManagerDataServiceTest.py
   PropertyManagerPropertyTest.py
   PythonPluginsTest.py
   StatisticsTest.py
diff --git a/Framework/PythonInterface/test/python/mantid/kernel/PropertyManagerDataServiceTest.py b/Framework/PythonInterface/test/python/mantid/kernel/PropertyManagerDataServiceTest.py
new file mode 100644
index 0000000000000000000000000000000000000000..058984e4facba81b5d9aaad96ca70a48d0666929
--- /dev/null
+++ b/Framework/PythonInterface/test/python/mantid/kernel/PropertyManagerDataServiceTest.py
@@ -0,0 +1,40 @@
+from __future__ import (absolute_import, division, print_function)
+
+import unittest
+from mantid.kernel import PropertyManager, PropertyManagerDataService
+
+class PropertyManagerDataServiceTest(unittest.TestCase):
+
+    def test_add_existing_mgr_object(self):
+        name = "PropertyManagerDataServiceTest_test_add_existing_mgr_object"
+        values = {'key': 100.5}
+        mgr = PropertyManager(values)
+        self._do_add_test(name, mgr)
+
+    def test_add_straight_from_dict(self):
+        name = "PropertyManagerDataServiceTest_test_add_straight_from_dict"
+        values = {'key': 100.5}
+        self._do_add_test(name, values)
+
+    def test_addOrReplace_straight_from_dict(self):
+        name = "PropertyManagerDataServiceTest_addOrReplace_straight_from_dict"
+        values = {'key': 100.5}
+        values2 = {'key2': 50}
+        self._do_addOrReplace_test(name, values, values2)
+
+    def _do_add_test(self, name, value):
+        pmds = PropertyManagerDataService.Instance()
+        pmds.add(name, value)
+        self.assertTrue(name in pmds)
+        pmds.remove(name)
+
+    def _do_addOrReplace_test(self, name, value, value2):
+        pmds = PropertyManagerDataService.Instance()
+        pmds.add(name, value)
+        pmds.addOrReplace(name, value2)
+        pmgr = pmds[name]
+        self.assertEquals(value2['key2'], pmgr['key2'].value)
+        pmds.remove(name)
+
+if __name__ == "__main__":
+    unittest.main()
diff --git a/Framework/PythonInterface/test/python/mantid/kernel/PropertyManagerTest.py b/Framework/PythonInterface/test/python/mantid/kernel/PropertyManagerTest.py
index 05ec479b72128cd5289ebd15a6acca1bf1cdaafc..e16f512d9334a2a318e929c3d3241f946b3d7f5e 100644
--- a/Framework/PythonInterface/test/python/mantid/kernel/PropertyManagerTest.py
+++ b/Framework/PythonInterface/test/python/mantid/kernel/PropertyManagerTest.py
@@ -4,7 +4,7 @@ import unittest
 from mantid.kernel import PropertyManager, IPropertyManager
 
 class PropertyManagerTest(unittest.TestCase):
-    def test_propertymanager(self):
+    def test_propertymanager_population(self):
         manager = PropertyManager()
 
         # check that it is empty
@@ -64,5 +64,21 @@ class PropertyManagerTest(unittest.TestCase):
         del manager["f"]
         self.assertTrue(len(manager), 2)
 
+    def test_propertymanager_can_be_created_from_dict(self):
+        values = {
+            "int": 5,
+            "float": 20.0,
+            "str": 'a string'
+        }
+        pmgr = PropertyManager(values)
+        self.assertEquals(len(pmgr), 3)
+        self.assertEquals(5, pmgr["int"].value)
+        self.assertEquals(20.0, pmgr["float"].value)
+        self.assertEquals('a string', pmgr["str"].value)
+
+    def test_propertymanager_cannot_be_created_from_arbitrary_sequence(self):
+        with self.assertRaises(Exception):
+            PropertyManager((1,2,3,4,5))
+
 if __name__ == "__main__":
     unittest.main()
diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/CMakeLists.txt b/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/CMakeLists.txt
index 1d486eb798e854ea4b615f012265a60fdc7a73af..91fc6f7a125d08b817193ffb4654b00dfea26ff7 100644
--- a/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/CMakeLists.txt
+++ b/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/CMakeLists.txt
@@ -30,6 +30,7 @@ set ( TEST_PY_FILES
   IqtFitSequentialTest.py
   ISISIndirectDiffractionReductionTest.py
   ISISIndirectEnergyTransferTest.py
+  MDNormSCDPreprocessIncoherentTest.py
   MolDynTest.py
   MSDFitTest.py
   OSIRISDiffractionReductionTest.py
diff --git a/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/MDNormSCDPreprocessIncoherentTest.py b/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/MDNormSCDPreprocessIncoherentTest.py
new file mode 100644
index 0000000000000000000000000000000000000000..7859f424a491dc147e1c166ab84f89ba490d0915
--- /dev/null
+++ b/Framework/PythonInterface/test/python/plugins/algorithms/WorkflowAlgorithms/MDNormSCDPreprocessIncoherentTest.py
@@ -0,0 +1,40 @@
+from __future__ import (absolute_import, division, print_function)
+import unittest
+import numpy as np
+from mantid.simpleapi import MDNormSCDPreprocessIncoherent
+
+
+class MDNormSCDPreprocessIncoherentTest(unittest.TestCase):
+    def testCNCS(self):
+        # CNCS_7860 is not an incoherent scatterer but for this test
+        # it doesn't matter
+        SA, Flux = MDNormSCDPreprocessIncoherent(Filename='CNCS_7860',
+                                                 MomentumMin=1,
+                                                 MomentumMax=1.5)
+
+        # Just compare 10 points of the Flux
+        flux_cmp = np.array([0.00000000e+00, 7.74945234e-04, 4.96143098e-03,
+                             1.18914010e-02, 1.18049991e-01, 7.71872176e-01,
+                             9.93078957e-01, 9.96312349e-01, 9.98450129e-01,
+                             1.00000002e+00])
+        np.testing.assert_allclose(Flux.extractY()[0][::1000], flux_cmp)
+        self.assertEqual(Flux.getXDimension().name, 'Momentum')
+        self.assertEqual(Flux.getXDimension().getUnits(), 'Angstrom^-1')
+        self.assertEqual(Flux.blocksize(), 10000)
+        self.assertEqual(Flux.getNumberHistograms(), 1)
+
+        # Compare every 20-th bin of row 64
+        SA_cmp = np.array([0.11338311, 0.18897185, 0.15117748, 0.11338311, 0.03779437,
+                           0.07558874, 0.15117748, 0.18897185, 0.03779437, 0.15117748,
+                           0.11338311, 0.07558874, 0.03779437, 0.        , 0.56691555,
+                           0.26456059, 0.11338311, 0.07558874, 0.11338311, 0.])
+        np.testing.assert_allclose(SA.extractY().reshape((-1,128))[::20,64], SA_cmp)
+        self.assertEqual(SA.getXDimension().name, 'Momentum')
+        self.assertEqual(SA.getXDimension().getUnits(), 'Angstrom^-1')
+        self.assertEqual(SA.blocksize(), 1)
+        self.assertEqual(SA.getNumberHistograms(), 51200)
+        self.assertEqual(SA.getNEvents(), 51200)
+
+
+if __name__=="__main__":
+    unittest.main()
diff --git a/Framework/WorkflowAlgorithms/src/ConvolutionFitSequential.cpp b/Framework/WorkflowAlgorithms/src/ConvolutionFitSequential.cpp
index c092f92d5f2b440986ef4d7d513ac3d61d20c9f6..26ce6ac239b47ffe58d1d0fffd78b10f0f76904c 100644
--- a/Framework/WorkflowAlgorithms/src/ConvolutionFitSequential.cpp
+++ b/Framework/WorkflowAlgorithms/src/ConvolutionFitSequential.cpp
@@ -70,6 +70,10 @@ void ConvolutionFitSequential::init() {
                   "The function that describes the parameters of the fit.",
                   Direction::Input);
 
+  declareProperty("PassWSIndexToFunction", false,
+                  "For each spectrum in Input pass its workspace index to all "
+                  "functions that have attribute WorkspaceIndex.");
+
   std::vector<std::string> backType{"Fixed Flat", "Fit Flat", "Fit Linear"};
 
   declareProperty("BackgroundType", "Fixed Flat",
@@ -98,9 +102,11 @@ void ConvolutionFitSequential::init() {
                                           "negative",
                   Direction::Input);
 
-  declareProperty("Convolve", true,
-                  "If true, the fit is treated as a convolution workspace.",
-                  Direction::Input);
+  declareProperty(
+      "Convolve", true,
+      "If true, output fitted model components will be convolved with "
+      "the resolution.",
+      Direction::Input);
 
   declareProperty(
       "ExtractMembers", false,
@@ -140,6 +146,7 @@ void ConvolutionFitSequential::exec() {
   // Initialise variables with properties
   MatrixWorkspace_sptr inputWs = getProperty("InputWorkspace");
   const std::string function = getProperty("Function");
+  const bool passIndex = getProperty("PassWSIndexToFunction");
   const std::string backType =
       convertBackToShort(getProperty("backgroundType"));
   const double startX = getProperty("StartX");
@@ -209,13 +216,6 @@ void ConvolutionFitSequential::exec() {
     plotPeakStringProg.report("Constructing PlotPeak name");
   }
 
-  // passWSIndex
-  auto passIndex = false;
-  if (funcName.find("Diff") != std::string::npos ||
-      funcName.find("Stretched") != std::string::npos) {
-    passIndex = true;
-  }
-
   // Run PlotPeaksByLogValue
   auto plotPeaks = createChildAlgorithm("PlotPeakByLogValue", 0.05, 0.90, true);
   plotPeaks->setProperty("Input", plotPeakInput);
diff --git a/Framework/WorkflowAlgorithms/src/EQSANSLoad.cpp b/Framework/WorkflowAlgorithms/src/EQSANSLoad.cpp
index 7cca98bafe3d798fffccca1e06d339914c884c04..c5536b678ce7ba80ca84eae5e8d21f99c5ce6294 100644
--- a/Framework/WorkflowAlgorithms/src/EQSANSLoad.cpp
+++ b/Framework/WorkflowAlgorithms/src/EQSANSLoad.cpp
@@ -87,6 +87,13 @@ void EQSANSLoad::init() {
   declareProperty("SampleDetectorDistanceOffset", EMPTY_DBL(),
                   "Offset to the sample to detector distance (use only when "
                   "using the distance found in the meta data), in mm");
+  declareProperty("SampleOffset", EMPTY_DBL(),
+                  "Offset to be applied to the sample position (use only when "
+                  "using the detector distance found in the meta data), in mm");
+  declareProperty(
+      "DetectorOffset", EMPTY_DBL(),
+      "Offset to be applied to the detector position (use only when "
+      "using the distance found in the meta data), in mm");
   declareProperty("LoadMonitors", true,
                   "If true, the monitor workspace will be loaded");
   declareProperty("OutputMessage", "", Direction::Output);
@@ -547,11 +554,13 @@ void EQSANSLoad::exec() {
     }
   }
 
-  // Get the sample-detector distance
-  double sdd = 0.0;
-  const double sample_det_dist = getProperty("SampleDetectorDistance");
-  if (!isEmpty(sample_det_dist)) {
-    sdd = sample_det_dist;
+  // Get the sample flange-to-detector distance
+  // We have to call it "SampleDetectorDistance" in the workspace
+  double sfdd = 0.0;
+  double s2d = 0.0;
+  const double sampleflange_det_dist = getProperty("SampleDetectorDistance");
+  if (!isEmpty(sampleflange_det_dist)) {
+    sfdd = sampleflange_det_dist;
   } else {
     if (!dataWS->run().hasProperty("detectorZ")) {
       g_log.error()
@@ -569,27 +578,41 @@ void EQSANSLoad::exec() {
     if (!dp)
       throw std::runtime_error("Could not cast (interpret) the property " +
                                dzName + " as a time series property value.");
-    sdd = dp->getStatistics().mean;
+    sfdd = dp->getStatistics().mean;
+    s2d = sfdd;
+
+    // Modify SDD according to the DetectorDistance offset if given
+    const double sampleflange_det_offset = getProperty("DetectorOffset");
+    if (!isEmpty(sampleflange_det_offset))
+      sfdd += sampleflange_det_offset;
 
-    // Modify SDD according to offset if given
+    // Modify S2D according to the SampleDistance offset if given
+    // This assumes that a positive offset moves the sample toward the detector
+    const double sampleflange_sample_offset = getProperty("SampleOffset");
+    if (!isEmpty(sampleflange_sample_offset))
+      s2d = s2d - sampleflange_sample_offset + sampleflange_det_offset;
+
+    // Modify SDD according to SampleDetectorDistanceOffset offset if given
     const double sample_det_offset =
         getProperty("SampleDetectorDistanceOffset");
     if (!isEmpty(sample_det_offset))
-      sdd += sample_det_offset;
+      s2d += sample_det_offset;
   }
-  dataWS->mutableRun().addProperty("sample_detector_distance", sdd, "mm", true);
+  dataWS->mutableRun().addProperty("sampleflange_detector_distance", sfdd, "mm",
+                                   true);
+  dataWS->mutableRun().addProperty("sample_detector_distance", s2d, "mm", true);
 
   // Move the detector to its correct position
   IAlgorithm_sptr mvAlg =
       createChildAlgorithm("MoveInstrumentComponent", 0.2, 0.4);
   mvAlg->setProperty<MatrixWorkspace_sptr>("Workspace", dataWS);
   mvAlg->setProperty("ComponentName", "detector1");
-  mvAlg->setProperty("Z", sdd / 1000.0);
+  mvAlg->setProperty("Z", sfdd / 1000.0);
   mvAlg->setProperty("RelativePosition", false);
   mvAlg->executeAsChildAlg();
-  g_log.information() << "Moving detector to " << sdd / 1000.0 << " meters\n";
+  g_log.information() << "Moving detector to " << sfdd / 1000.0 << " meters\n";
   m_output_message += "   Detector position: " +
-                      Poco::NumberFormatter::format(sdd / 1000.0, 3) + " m\n";
+                      Poco::NumberFormatter::format(sfdd / 1000.0, 3) + " m\n";
 
   // Get the run number so we can find the proper config file
   int run_number = 0;
@@ -733,9 +756,11 @@ void EQSANSLoad::exec() {
   }
 
   // Convert to wavelength
+  // Checked on 8/10/17 - changed from "sdd" to "sfdd" as was done above
+  // sfdd + ssd gives total distance (corrected by offset) from the source
   const double ssd =
       fabs(dataWS->getInstrument()->getSource()->getPos().Z()) * 1000.0;
-  const double conversion_factor = 3.9560346 / (sdd + ssd);
+  const double conversion_factor = 3.9560346 / (sfdd + ssd);
   m_output_message += "   TOF to wavelength conversion factor: " +
                       Poco::NumberFormatter::format(conversion_factor) + "\n";
 
diff --git a/Framework/WorkflowAlgorithms/src/EQSANSQ2D.cpp b/Framework/WorkflowAlgorithms/src/EQSANSQ2D.cpp
index 39bf5490876f4dc140ee05b3342077d13b01c792..e05143fd4ad5671bdb62f478369e3a91af6b5ffc 100644
--- a/Framework/WorkflowAlgorithms/src/EQSANSQ2D.cpp
+++ b/Framework/WorkflowAlgorithms/src/EQSANSQ2D.cpp
@@ -90,6 +90,8 @@ void EQSANSQ2D::exec() {
     qmax = getRunProperty(inputWS, "qmax");
     g_log.debug() << "Using Qmax from run properties = " << qmax << std::endl;
   } else {
+    // This is pointing to the correct parameter in the workspace,
+    // which has been changed to the right distance in EQSANSLoad.cpp
     const double sample_detector_distance =
         getRunProperty(inputWS, "sample_detector_distance");
 
@@ -109,6 +111,8 @@ void EQSANSQ2D::exec() {
     double dymax = pixel_size_y * std::max(beam_ctr_y, ny_pixels - beam_ctr_y);
     double maxdist = std::max(dxmax, dymax);
 
+    // This uses the correct parameter in the workspace, which has been
+    // changed to the right distance in EQSANSLoad.cpp
     qmax = 4 * M_PI / wavelength_min *
            std::sin(0.5 * std::atan(maxdist / sample_detector_distance));
     g_log.debug() << "Using calculated Qmax = " << qmax << std::endl;
diff --git a/Framework/WorkflowAlgorithms/src/SetupEQSANSReduction.cpp b/Framework/WorkflowAlgorithms/src/SetupEQSANSReduction.cpp
index f221e3d744c04eb29b1f1b038adae7edec8f9a47..3124508905725f5226ffc3218b899515f41c0e3c 100644
--- a/Framework/WorkflowAlgorithms/src/SetupEQSANSReduction.cpp
+++ b/Framework/WorkflowAlgorithms/src/SetupEQSANSReduction.cpp
@@ -54,8 +54,15 @@ void SetupEQSANSReduction::init() {
   declareProperty(
       "SampleDetectorDistance", EMPTY_DBL(),
       "Sample to detector distance to use (overrides meta data), in mm");
+
   declareProperty("SampleDetectorDistanceOffset", EMPTY_DBL(),
                   "Offset to the sample to detector distance (use only when "
+                  "using the detector distance found in the meta data), in mm");
+  declareProperty("SampleOffset", EMPTY_DBL(),
+                  "Offset applies to the sample position (use only when "
+                  "using the detector distance found in the meta data), in mm");
+  declareProperty("DetectorOffset", EMPTY_DBL(),
+                  "Offset applies to the detector position (use only when "
                   "using the distance found in the meta data), in mm");
 
   declareProperty(
@@ -81,6 +88,8 @@ void SetupEQSANSReduction::init() {
   setPropertyGroup("SampleDetectorDistance", load_grp);
   setPropertyGroup("SampleDetectorDistanceOffset", load_grp);
 
+  setPropertyGroup("SampleOffset", load_grp);
+  setPropertyGroup("DetectorOffset", load_grp);
   setPropertyGroup("SolidAngleCorrection", load_grp);
   setPropertyGroup("DetectorTubes", load_grp);
 
@@ -658,6 +667,10 @@ void SetupEQSANSReduction::exec() {
   loadAlg->setProperty("SampleDetectorDistance", sdd);
   const double sddOffset = getProperty("SampleDetectorDistanceOffset");
   loadAlg->setProperty("SampleDetectorDistanceOffset", sddOffset);
+  const double dOffset = getProperty("DetectorOffset");
+  loadAlg->setProperty("DetectorOffset", dOffset);
+  const double sOffset = getProperty("SampleOffset");
+  loadAlg->setProperty("SampleOffset", sOffset);
   const double wlStep = getProperty("WavelengthStep");
   loadAlg->setProperty("WavelengthStep", wlStep);
 
diff --git a/MantidPlot/make_package.rb.in b/MantidPlot/make_package.rb.in
index b0a52ef46ebec222b3506f368e580b549312780a..c5c9ffd2c7e833de9f498d60d15115b97416b134 100755
--- a/MantidPlot/make_package.rb.in
+++ b/MantidPlot/make_package.rb.in
@@ -44,6 +44,7 @@ library_filenames = ["libboost_regex-mt.dylib",
                      "libboost_python-mt.dylib",
                      "libboost_serialization-mt.dylib",
                      "libboost_filesystem-mt.dylib",
+                     "libboost_system-mt.dylib",
                      "libgsl.dylib",
                      "libgslcblas.dylib",
                      "libjsoncpp.dylib",
@@ -132,10 +133,10 @@ if( "@MAKE_VATES@" == "ON" )
   `mkdir Contents/Libraries`
   `cp #{ParaView_dir}/lib/*Python.so Contents/Libraries`
   vatesfiles = ["Contents/MacOS/MantidPlot",
-                "Contents/MacOS/libMantidQtAPI.dylib",
-                "Contents/MacOS/VatesSimpleGui",
+                "Contents/MacOS/libMantidQtWidgetsCommon.dylib",
                 "Contents/MacOS/libMantidParaViewQtWidgets.dylib",
                 "Contents/MacOS/libMantidVatesAPI.dylib",
+                "plugins/libMantidVatesAlgorithms.dylib",
                 "pvplugins/libMantidVatesSimpleGuiViewWidgets.dylib"]
   vatesfiles += Dir["Contents/Libraries/*Python.so"] + Dir["pvplugins/pvplugins/*.dylib"]
   vatesfiles.each do |file|
@@ -173,7 +174,7 @@ if( "@MAKE_VATES@" == "ON" )
 end
 
 #use install_name_tool to change dependencies from /usr/local to libraries in the package.
-search_patterns = ["**/*.dylib","**/*.so","**/MantidPlot","**/VatesSimpleGui"]
+search_patterns = ["**/*.dylib","**/*.so","**/MantidPlot"]
 search_patterns.each do |pattern|
   Dir[pattern].each do |library|
     dependencies = `otool -L #{library}`
@@ -195,8 +196,7 @@ end
 #We'll use macdeployqt to fix qt dependencies.
 Qt_Executables = "-executable=Contents/MacOS/mantidqtpython.so -executable=Contents/MacOS/libqwtplot3d.dylib -executable=Contents/MacOS/libqwt.dylib -executable=Contents/MacOS/libqscintilla2.dylib"
 if( "@MAKE_VATES@" == "ON" )
-  list = ["Contents/MacOS/VatesSimpleGui",
-          "Contents/Libraries/vtkParaViewWebCorePython.so",
+  list = ["Contents/Libraries/vtkParaViewWebCorePython.so",
           "Contents/Libraries/vtkPVAnimationPython.so",
           "Contents/Libraries/vtkPVCatalystPython.so",
           "Contents/Libraries/vtkPVCinemaReaderPython.so",
diff --git a/MantidPlot/test/squish_test_suites/refl_gui_tests/envvars b/MantidPlot/test/squish_test_suites/refl_gui_tests/envvars
index 1274936e45e9606db180045b43cd9413160fe6e1..7554408f3b0767df5d41476612ab45eb5dca25e4 100644
--- a/MantidPlot/test/squish_test_suites/refl_gui_tests/envvars
+++ b/MantidPlot/test/squish_test_suites/refl_gui_tests/envvars
@@ -1 +1,2 @@
-LD_LIBRARY_PATH=/opt/mantidnightly/lib/paraview-5.4
+LD_LIBRARY_PATH=/opt/mantidnightly/lib/paraview-5.4:/opt/mantidnightly/plugins/qtplugins/mantid
+QT_API=pyqt
diff --git a/Testing/SystemTests/lib/systemtests/stresstesting.py b/Testing/SystemTests/lib/systemtests/stresstesting.py
index d5bd41e752856afa09ac6fa60dfd83592fb34093..65385a86dbf67cf7e9754763c1c82b8248b37bfe 100644
--- a/Testing/SystemTests/lib/systemtests/stresstesting.py
+++ b/Testing/SystemTests/lib/systemtests/stresstesting.py
@@ -958,7 +958,7 @@ class MantidFrameworkConfig:
         # datasearch
         if self.__datasearch:
             config["datasearch.searcharchive"] = 'On'
-            config['network.default.timeout'] = '1'
+            config['network.default.timeout'] = '5'
 
         # Save this configuration
         config.saveConfig(self.__userPropsFile)
diff --git a/Testing/SystemTests/tests/analysis/BuildSQWTest.py b/Testing/SystemTests/tests/analysis/BuildSQWTest.py
index 00d160b73e13d27e4b648e2c01da3c7176fc9eb0..2474dc064d813730cce9b7bb41eb4e29c1e2541c 100644
--- a/Testing/SystemTests/tests/analysis/BuildSQWTest.py
+++ b/Testing/SystemTests/tests/analysis/BuildSQWTest.py
@@ -7,6 +7,7 @@
     the result file that is ~30Gb. The files are not included with the standard
     repository & required to be accessible from any machine that wishes to run the test.
 """
+from __future__ import (absolute_import, division, print_function)
 import stresstesting
 import os
 from mantid.simpleapi import *
@@ -70,7 +71,7 @@ class BuildSQWTest(stresstesting.MantidStressTest):
             if os.path.exists(target):
                 os.remove(target)
 
-            print "Converting '%s' to '%s' " % (source_path,target)
+            print("Converting '%s' to '%s' " % (source_path,target))
             _cur_spe_ws = LoadNXSPE(Filename=source_path)
             SetUB(Workspace=_cur_spe_ws,a='2.87',b='2.87',c='2.87')
             # rotated by proper number of degrees around axis Y
diff --git a/Testing/SystemTests/tests/analysis/CRISPLoadingTest.py b/Testing/SystemTests/tests/analysis/CRISPLoadingTest.py
index 82f082ea629473dcc78cb56f56b073dcde35722c..8d35434527efd6ad77788fce22b3a694d2271b5d 100644
--- a/Testing/SystemTests/tests/analysis/CRISPLoadingTest.py
+++ b/Testing/SystemTests/tests/analysis/CRISPLoadingTest.py
@@ -1,3 +1,4 @@
+from __future__ import (absolute_import, division, print_function)
 from LoadAndCheckBase import *
 
 
diff --git a/Testing/SystemTests/tests/analysis/CalibrateRectangularDetector_Test.py b/Testing/SystemTests/tests/analysis/CalibrateRectangularDetector_Test.py
index 08e20e998fd6eaeb318a5b67a791e120a08a6a9d..c1c49b2e663b979b9e01cbb257a57b1cb3e127b7 100644
--- a/Testing/SystemTests/tests/analysis/CalibrateRectangularDetector_Test.py
+++ b/Testing/SystemTests/tests/analysis/CalibrateRectangularDetector_Test.py
@@ -1,7 +1,9 @@
 #pylint: disable=invalid-name,no-init,attribute-defined-outside-init
+from __future__ import (absolute_import, division, print_function)
 import stresstesting
 import os
 from mantid.simpleapi import *
+from six import string_types
 
 
 def _skip_test():
@@ -41,7 +43,7 @@ class PG3Calibration(stresstesting.MantidStressTest):
                                                MaxOffset=0.01, PeakPositions = '.6866,.7283,.8185,.8920,1.0758,1.2615,2.0599',
                                                CrossCorrelation = False, RunNumber = 'PG3_2538')
 
-        if isinstance(output, basestring):
+        if isinstance(output, string_types):
             self.saved_cal_file = output.replace('.h5','.cal')
         else:
             raise NotImplementedError("Output from CalibrateRectangularDetectors is NOT string for calibration file name!")
@@ -89,7 +91,7 @@ class PG3CCCalibration(stresstesting.MantidStressTest):
                                                MaxOffset=0.01, PeakPositions = '0.7282933,1.261441',DetectorsPeaks = '17,6',
                                                CrossCorrelation = True, RunNumber = 'PG3_2538')
 
-        if isinstance(output, basestring):
+        if isinstance(output, string_types):
             self.saved_cal_file = output.replace('.h5','.cal')
         else:
             raise NotImplementedError("Output from CalibrateRectangularDetectors is NOT string for calibration file name!")
diff --git a/Testing/SystemTests/tests/analysis/CodeConventions.py b/Testing/SystemTests/tests/analysis/CodeConventions.py
index 687c5c8e436d275792ecc95f3c94735230d4b063..06fe703e9675a6a69bea516eda6ba8ba05406ef5 100644
--- a/Testing/SystemTests/tests/analysis/CodeConventions.py
+++ b/Testing/SystemTests/tests/analysis/CodeConventions.py
@@ -1,8 +1,11 @@
 #pylint: disable=no-init
+from __future__ import (absolute_import, division, print_function)
 import stresstesting
 import re
 import mantid
 from mantid.simpleapi import *
+from six.moves import range
+from six import iteritems
 
 MAX_ALG_LEN = 40 # TODO convention says 20 is the maximum
 
@@ -80,12 +83,12 @@ class Algorithms(stresstesting.MantidStressTest):
 
     def verifyAlgName(self, name):
         if not self.algRegExp.match(name):
-            print "Algorithm " + name + " has a name that violates conventions"
+            print("Algorithm " + name + " has a name that violates conventions")
             return False
 
         if bool(len(name) > MAX_ALG_LEN):
-            print "%s has a name that is longer than " % name, \
-                "%d characters (%d > %d)" % (MAX_ALG_LEN, len(name), MAX_ALG_LEN)
+            print("%s has a name that is longer than " % name,
+                  "%d characters (%d > %d)" % (MAX_ALG_LEN, len(name), MAX_ALG_LEN))
             return False
 
         # passed all of the checks
@@ -93,11 +96,11 @@ class Algorithms(stresstesting.MantidStressTest):
 
     def verifyCategories(self, name, categories):
         if len(categories) <= 0:
-            print name + " has no categories"
+            print(name + " has no categories")
 
         for category in categories:
             if not self.categoryRegExp.match(category):
-                print name + " has a bad category " + category
+                print(name + " has a bad category " + category)
                 return False
 
         return True
@@ -112,13 +115,13 @@ class Algorithms(stresstesting.MantidStressTest):
         upper = name.upper()
         if (upper in SPECIAL_UPPER) and (name not in SPECIAL):
             index = SPECIAL_UPPER.index(upper)
-            print alg_descr + " property (" + name + ") has special name "\
-                + "with wrong case: " + name + " should be " + SPECIAL[index]
+            print(alg_descr + " property (" + name + ") has special name "
+                  + "with wrong case: " + name + " should be " + SPECIAL[index])
             return False
 
         if not self.paramRegExp.match(name):
             if not self.checkAllowed(alg_descr, name):
-                print alg_descr + " property (" + name +") violates conventions"
+                print(alg_descr + " property (" + name +") violates conventions")
                 return False
 
         # passed all of the checks
@@ -127,7 +130,7 @@ class Algorithms(stresstesting.MantidStressTest):
     def runTest(self):
         algs = AlgorithmFactory.getRegisteredAlgorithms(True)
 
-        for (name, versions) in algs.iteritems():
+        for (name, versions) in iteritems(algs):
             if not self.verifyAlgName(name):
                 self.__ranOk += 1
                 continue
@@ -148,8 +151,8 @@ class Algorithms(stresstesting.MantidStressTest):
 
     def validate(self):
         if self.__ranOk > 0:
-            print "Found %d errors. Coding conventions found at" % self.__ranOk,\
-                "http://www.mantidproject.org/Mantid_Standards"
+            print("Found %d errors. Coding conventions found at" % self.__ranOk,
+                  "http://www.mantidproject.org/Mantid_Standards")
             return False
 
         return True
@@ -168,12 +171,12 @@ class FitFunctions(stresstesting.MantidStressTest):
             return True
 
         if not self.funcRegExp.match(name):
-            print "Function " + name + " has a name that violates conventions"
+            print("Function " + name + " has a name that violates conventions")
             return False
 
         if bool(len(name) > MAX_ALG_LEN):
-            print "%s has a name that is longer than " % name, \
-                "%d characters (%d > %d)" % (MAX_ALG_LEN, len(name), MAX_ALG_LEN)
+            print("%s has a name that is longer than " % name,
+                  "%d characters (%d > %d)" % (MAX_ALG_LEN, len(name), MAX_ALG_LEN))
             return False
 
         # passed all of the checks
@@ -181,7 +184,7 @@ class FitFunctions(stresstesting.MantidStressTest):
 
     def verifyCategories(self, name, categories):
         if len(categories) <= 0:
-            print name + " has no categories"
+            print(name + " has no categories")
 
         for category in categories:
             # TODO remove the special case
@@ -189,7 +192,7 @@ class FitFunctions(stresstesting.MantidStressTest):
                 return True
 
             if not self.categoryRegExp.match(category):
-                print name + " has a bad category " + category
+                print(name + " has a bad category " + category)
                 return False
 
         return True
@@ -204,7 +207,7 @@ class FitFunctions(stresstesting.MantidStressTest):
 
         if not self.paramRegExp.match(name):
             if not self.checkAllowed(alg_descr, name):
-                print alg_descr + " property (" + name +") violates conventions"
+                print(alg_descr + " property (" + name +") violates conventions")
                 return False
 
         # passed all of the checks
@@ -222,14 +225,14 @@ class FitFunctions(stresstesting.MantidStressTest):
             if not self.verifyCategories(name, function.categories()):
                 self.__ranOk += 1
 
-            for i in xrange(function.numParams()):
+            for i in range(function.numParams()):
                 if not self.verifyParameter(name, function.getParamName(i)):
                     self.__ranOk += 1
 
     def validate(self):
         if self.__ranOk > 0:
-            print "Found %d errors. Coding conventions found at" % self.__ranOk,\
-                "http://www.mantidproject.org/Mantid_Standards"
+            print("Found %d errors. Coding conventions found at" % self.__ranOk,
+                  "http://www.mantidproject.org/Mantid_Standards")
             return False
 
         return True
diff --git a/Testing/SystemTests/tests/analysis/ConvertToMDworkflow.py b/Testing/SystemTests/tests/analysis/ConvertToMDworkflow.py
index efd58983b5506e995a736d05519deeedb7b23ff6..cd01315d34f4d05a4dc05bd4101235ce1ab6d4ad 100644
--- a/Testing/SystemTests/tests/analysis/ConvertToMDworkflow.py
+++ b/Testing/SystemTests/tests/analysis/ConvertToMDworkflow.py
@@ -1,4 +1,5 @@
 #pylint: disable=no-init
+from __future__ import (absolute_import, division, print_function)
 import stresstesting
 from mantid.simpleapi import *
 
@@ -27,10 +28,10 @@ class ConvertToMDworkflow(stresstesting.MantidStressTest):
         try:
             DeleteWorkspace(RezWS)
         except ValueError:
-            print "Target ws ",RezWS," not found in analysis data service\n"
+            print("Target ws ",RezWS," not found in analysis data service\n")
     #
         #---> Start loop over contributing files
-        for i in xrange(0,20,5):
+        for i in range(0,20,5):
             # the following operations simulate different workspaces, obtained from experiment using rotating crystal;
             # For real experiment we  usually just load these workspaces from nxspe files with proper Psi values defined there
             # and have to set up ub matrix
@@ -72,8 +73,8 @@ class ConvertToMDworkflow(stresstesting.MantidStressTest):
 
         checker.execute()
         if checker.getPropertyValue("Equals") != "1":
-            print " Workspaces do not match, result: ",checker.getPropertyValue("Result")
-            print self.__class__.__name__
+            print(" Workspaces do not match, result: ",checker.getPropertyValue("Result"))
+            print(self.__class__.__name__)
             SaveMD(InputWorkspace=valNames[0],Filename=self.__class__.__name__+'-mismatch.nxs')
             return False
 
diff --git a/Testing/SystemTests/tests/analysis/CountReflectionsTest.py b/Testing/SystemTests/tests/analysis/CountReflectionsTest.py
index 1e919ac4ee1999da35920b25ce2bd47238f4c0c5..3d058d2c3dcf777073abc513d9f2f1d00fc4c679 100644
--- a/Testing/SystemTests/tests/analysis/CountReflectionsTest.py
+++ b/Testing/SystemTests/tests/analysis/CountReflectionsTest.py
@@ -1,3 +1,4 @@
+from __future__ import (absolute_import, division, print_function)
 import stresstesting
 from mantid.simpleapi import *
 from SortHKLTest import HKLStatisticsTestMixin
@@ -32,8 +33,8 @@ class CountReflectionsTest(HKLStatisticsTestMixin, stresstesting.MantidStressTes
                                 LatticeCentering=centering, MinDSpacing=0.5, MaxDSpacing=10.0)
 
     def _compare_statistics(self, statistics, reference_statistics):
-        self.assertEquals(round(statistics['Redundancy'], 1), round(reference_statistics['<N>'], 1))
-        self.assertEquals(statistics['UniqueReflections'], int(reference_statistics['Nunique']))
+        self.assertEqual(round(statistics['Redundancy'], 1), round(reference_statistics['<N>'], 1))
+        self.assertEqual(statistics['UniqueReflections'], int(reference_statistics['Nunique']))
         self.assertDelta(round(statistics['Completeness'] * 100.0, 1),
                          round(reference_statistics['Completeness'], 1),
                          0.5)
diff --git a/Testing/SystemTests/tests/analysis/DOSTest.py b/Testing/SystemTests/tests/analysis/DOSTest.py
index 7e28c5afa63c9bb2c7723949e92e135fd4c3016f..68b2787b92e05e6f326ba895ebc9b5ccea39474c 100644
--- a/Testing/SystemTests/tests/analysis/DOSTest.py
+++ b/Testing/SystemTests/tests/analysis/DOSTest.py
@@ -1,4 +1,5 @@
 #pylint: disable=no-init,attribute-defined-outside-init
+from __future__ import (absolute_import, division, print_function)
 import stresstesting
 from mantid.kernel import *
 from mantid.api import *
diff --git a/Testing/SystemTests/tests/analysis/Diffraction_Workflow_Test.py b/Testing/SystemTests/tests/analysis/Diffraction_Workflow_Test.py
index 5aa27f7d2683b2530e2892cf3e4b4cf74148f1f5..13d4ae3fa1cd3f36caa3042b0ff64e14400ee8c6 100644
--- a/Testing/SystemTests/tests/analysis/Diffraction_Workflow_Test.py
+++ b/Testing/SystemTests/tests/analysis/Diffraction_Workflow_Test.py
@@ -3,6 +3,7 @@
 System test that loads TOPAZ single-crystal data,
 and runs Diffraction Workflow.
 """
+from __future__ import (absolute_import, division, print_function)
 import stresstesting
 import numpy
 import os
@@ -153,7 +154,7 @@ class Diffraction_Workflow_Test(stresstesting.MantidStressTest):
         newUB = numpy.array(mtd["TOPAZ_3132"].sample().getOrientedLattice().getUB())
         # UB Matrices are not necessarily the same, some of the H,K and/or L sign can be reversed
         diff = abs(newUB) - abs(originalUB) < 0.001
-        for c in xrange(3):
+        for c in range(3):
             # This compares each column, allowing old == new OR old == -new
             if not numpy.all(diff[:,c]) :
                 raise Exception("More than 0.001 difference between UB matrices: Q (lab frame):\n%s\nQ (sample frame):\n%s"
diff --git a/Testing/SystemTests/tests/analysis/EQSANSIQOutputAPIv2.py b/Testing/SystemTests/tests/analysis/EQSANSIQOutputAPIv2.py
index ab569c401bd75b9ace1dfb3699fbd10a7c879218..6b3ac508ba79640e18d179ac718ada678fcadb00 100644
--- a/Testing/SystemTests/tests/analysis/EQSANSIQOutputAPIv2.py
+++ b/Testing/SystemTests/tests/analysis/EQSANSIQOutputAPIv2.py
@@ -1,4 +1,5 @@
 #pylint: disable=no-init,invalid-name,attribute-defined-outside-init
+from __future__ import (absolute_import, division, print_function)
 import stresstesting
 import math
 import os
@@ -6,6 +7,7 @@ from mantid.simpleapi import *
 from reduction_workflow.instruments.sans.sns_command_interface import *
 from reduction_workflow.instruments.sans.hfir_command_interface import *
 from mantid.api import *
+from functools import reduce
 
 
 def do_cleanup():
@@ -192,7 +194,7 @@ class EQSANSDQOutput(stresstesting.MantidStressTest):
         output = reduce(lambda x,y:x and y, diff)
         if not output:
             for i,dqi in enumerate(dq):
-                print i, dqi, dq_ref[i], math.fabs(dq_ref[i]-dqi)<0.0001
+                print(i, dqi, dq_ref[i], math.fabs(dq_ref[i]-dqi)<0.0001)
         return output
 
 
@@ -258,5 +260,5 @@ class EQSANSDQOutput_FS(stresstesting.MantidStressTest):
 
         if not output:
             for i,dqi in enumerate(dq):
-                print i, dqi, dq_ref[i], math.fabs(dq_ref[i]-dqi)<0.0001
+                print(i, dqi, dq_ref[i], math.fabs(dq_ref[i]-dqi)<0.0001)
         return output
diff --git a/Testing/SystemTests/tests/analysis/EQSANSSolidAPIv2.py b/Testing/SystemTests/tests/analysis/EQSANSSolidAPIv2.py
index f518d2ca37e720e53c41bd7aa91b52a0ff41df5f..3e08e14c4460d60baa8fdc23d0f736f5b4c33e5c 100644
--- a/Testing/SystemTests/tests/analysis/EQSANSSolidAPIv2.py
+++ b/Testing/SystemTests/tests/analysis/EQSANSSolidAPIv2.py
@@ -1,4 +1,5 @@
 #pylint: disable=no-init,attribute-defined-outside-init
+from __future__ import (absolute_import, division, print_function)
 import stresstesting
 from mantid.simpleapi import *
 from reduction_workflow.instruments.sans.sns_command_interface import *
@@ -12,7 +13,7 @@ def do_cleanup():
     absfile = FileFinder.getFullPath("EQSANS_1466_event_reduction.log")
     if os.path.exists(absfile):
         os.remove(absfile)
-        print "cleaned"
+        print("cleaned")
     return True
 
 
diff --git a/Testing/SystemTests/tests/analysis/HFIRTestsAPIv2.py b/Testing/SystemTests/tests/analysis/HFIRTestsAPIv2.py
index 43d23b90f658696e83aec63f8c543f9ac778ec75..2741b928a36f8f987ba9327c3af5d626adc9f3ff 100644
--- a/Testing/SystemTests/tests/analysis/HFIRTestsAPIv2.py
+++ b/Testing/SystemTests/tests/analysis/HFIRTestsAPIv2.py
@@ -7,6 +7,7 @@
     The following tests were converted from the unittest framework
     that is part of python to the stresstesting framework used in Mantid.
 """
+from __future__ import (absolute_import, division, print_function)
 import types
 
 import traceback
@@ -18,6 +19,7 @@ from mantid.api import *
 from mantid.simpleapi import *
 from reduction_workflow.instruments.sans.hfir_command_interface import *
 from reduction_workflow.command_interface import AppendDataFile, Reduce, Reduce1D
+from functools import reduce
 
 
 # Set directory containing the test data, relative to the Mantid release
@@ -58,7 +60,7 @@ def _read_IGOR(filepath):
                 diq = float(toks[2])
                 data.append([q, iq, diq])
             except:
-                print "_read_IGOR:", sys.exc_value
+                print("_read_IGOR:", sys.exc_info()[1])
                 raise
     return data
 
@@ -75,14 +77,14 @@ def _check_result(ws, test_file, tolerance=1e-6):
     x = ws.dataX(0)[:len(ws.dataX(0))]
     y = ws.dataY(0)
     e = ws.dataE(0)
-    data_mantid = zip(x, y, e)
+    data_mantid = list(zip(x, y, e))
 
     # Read the test data to compare with
     data_igor = _read_IGOR(test_file)
 
     # Check length
     if not len(data_mantid) == len(data_igor):
-        print "Incompatible data lengths"
+        print("Incompatible data lengths")
         return False
 
     # Utility methods for manipulating the lists
@@ -99,25 +101,25 @@ def _check_result(ws, test_file, tolerance=1e-6):
         return x + y
 
     # Check that I(q) is the same for both data sets
-    deltas = map(_diff_iq, data_mantid, data_igor)
+    deltas = list(map(_diff_iq, data_mantid, data_igor))
     delta = reduce(_add, deltas) / len(deltas)
     if math.fabs(delta) > tolerance or math.isnan(delta):
         passed = False
-        print "Sum of I(q) deltas is outside tolerance: %g > %g" % (math.fabs(delta), tolerance)
+        print("Sum of I(q) deltas is outside tolerance: %g > %g" % (math.fabs(delta), tolerance))
 
     # Then compare the errors
-    deltas = map(_diff_err, data_mantid, data_igor)
+    deltas = list(map(_diff_err, data_mantid, data_igor))
     delta_err = reduce(_add, deltas) / len(deltas)
     if math.fabs(delta_err) > tolerance or math.isnan(delta):
         passed = False
-        print "Sum of dI(q) deltas is outside tolerance: %g > %g" % (math.fabs(delta_err), tolerance)
+        print("Sum of dI(q) deltas is outside tolerance: %g > %g" % (math.fabs(delta_err), tolerance))
 
     # Compute chi2 of our result relative to IGOR
-    deltas = map(_diff_chi2, data_mantid, data_igor)
+    deltas = list(map(_diff_chi2, data_mantid, data_igor))
     chi2 = reduce(_add, deltas) / len(data_igor)
     if chi2 > 10.0 * tolerance or math.isnan(delta):
         passed = False
-        print "Chi2 is outside tolerance: %g > %g" % (chi2, 10.0 * tolerance)
+        print("Chi2 is outside tolerance: %g > %g" % (chi2, 10.0 * tolerance))
 
     return passed
 
@@ -184,10 +186,10 @@ class HFIRTestsAPIv2(stresstesting.MantidStressTest):
                 ReductionSingleton.clean()
                 # Execute the test
                 try:
-                    print self._test_method.__name__
+                    print(self._test_method.__name__)
                     return self._test_method()
                 except:
-                    print traceback.format_exc()
+                    print(traceback.format_exc())
                     raise
                 return False
 
@@ -360,7 +362,7 @@ class HFIRTestsAPIv2(stresstesting.MantidStressTest):
                  0.192082, 0.193783, 0.193787, 0.190557, 0.190471, 0.186827, 0.190088, 0.188204, 0.187547, 0.182206,
                  0.181384, 0.180358, 0.182663, 0.178844, 0.176556]
 
-        deltas = map(_diff_iq, data, check)
+        deltas = list(map(_diff_iq, data, check))
         delta = reduce(_add, deltas) / len(deltas)
         self.assertTrue(math.fabs(delta) < 0.00001)
 
@@ -415,10 +417,10 @@ class HFIRTestsAPIv2(stresstesting.MantidStressTest):
             0.05658625,0.05933774,0.06222303,0.06524861,0.06842131,0.07174829,
             0.07523703,0.07889542,0.08273169,0.08675451,0.09097293,0.09539647,
             0.1000351,0.10489929,0.11]
-        deltas = map(_diff_iq, data, check)
+        deltas = list(map(_diff_iq, data, check))
         delta = reduce(_add, deltas) / len(deltas)
         self.assertTrue(math.fabs(delta) < 0.00001)
-        print data
+        print(data)
 
     def test_no_solid_angle(self):
         GPSANS()
@@ -471,7 +473,7 @@ class HFIRTestsAPIv2(stresstesting.MantidStressTest):
                  0.190122, 0.189119, 0.18864, 0.185473,
                  0.184958, 0.183981, 0.182581]
 
-        deltas = map(_diff_iq, data, check)
+        deltas = list(map(_diff_iq, data, check))
         delta = reduce(_add, deltas) / len(deltas)
         self.assertTrue(math.fabs(delta) < 0.00001)
 
@@ -504,7 +506,7 @@ class HFIRTestsAPIv2(stresstesting.MantidStressTest):
                  0.195653, 0.19322, 0.193537, 0.191503, 0.190253,
                  0.189253, 0.188771, 0.1856, 0.185099, 0.184111, 0.182717]
 
-        deltas = map(_diff_iq, data, check)
+        deltas = list(map(_diff_iq, data, check))
         delta = reduce(_add, deltas) / len(deltas)
         self.assertTrue(math.fabs(delta) < 0.00001)
 
@@ -540,7 +542,7 @@ class HFIRTestsAPIv2(stresstesting.MantidStressTest):
                  0.369733, 0.370353, 0.366464, 0.364109, 0.362184, 0.361299,
                  0.355246, 0.354339, 0.352412, 0.349748]
 
-        deltas = map(_diff_iq, data, check)
+        deltas = list(map(_diff_iq, data, check))
         delta = reduce(_add, deltas) / len(deltas)
         self.assertTrue(math.fabs(delta) < 0.001)
 
@@ -693,12 +695,12 @@ class HFIRTestsAPIv2(stresstesting.MantidStressTest):
                  0.3479, 0.352355, 0.344987, 0.340605]
 
         # Check that I(q) is the same for both data sets
-        deltas = map(_diff_iq, data, check)
+        deltas = list(map(_diff_iq, data, check))
         delta = reduce(_add, deltas) / len(deltas)
         self.assertTrue(math.fabs(delta) < 0.00001)
 
     def test_SampleGeometry_functions(self):
-        print "SKIPPING test_SampleGeometry_functions()"
+        print("SKIPPING test_SampleGeometry_functions()")
         return
         # pylint: disable=unreachable
         GPSANS()
@@ -724,7 +726,7 @@ class HFIRTestsAPIv2(stresstesting.MantidStressTest):
 
         check = [500091.0, 60.0, 40.8333, 13.6333, 13.4667, 13.6667]
         # Check that I(q) is the same for both data sets
-        deltas = map(_diff_iq, data, check)
+        deltas = list(map(_diff_iq, data, check))
         delta = reduce(_add, deltas) / len(deltas)
         self.assertTrue(math.fabs(delta) < 0.1)
 
@@ -948,9 +950,9 @@ class HFIRTestsAPIv2(stresstesting.MantidStressTest):
         self.assertAlmostEqual(data[20], -0.047785, delta=0.00001)
 
     def validate(self):
-        print "HFIRTests: %d / %d tests passed" % (self.n_passed, self.n_tests)
+        print("HFIRTests: %d / %d tests passed" % (self.n_passed, self.n_tests))
         for items in self.failed_tests:
-            print items
+            print(items)
         return self.all_passed
 
 
@@ -970,9 +972,9 @@ def assertAlmostEqual(first, second, places=None, _msg=None, delta=None, rel_del
         if abs(first - second) <= delta:
             return True
         elif abs(first - second) / abs(second) < rel_delta:
-            print '\n-----> %s != %s but within %s percent' % (str(first),
+            print('\n-----> %s != %s but within %s percent' % (str(first),
                                                                str(second),
-                                                               str(rel_delta * 100.0))
+                                                               str(rel_delta * 100.0)))
             return True
 
         standardMsg = '%s != %s within %s delta' % (str(first),
@@ -988,5 +990,5 @@ def assertAlmostEqual(first, second, places=None, _msg=None, delta=None, rel_del
         standardMsg = '%s != %s within %r places' % (str(first),
                                                      str(second),
                                                      places)
-    print standardMsg
+    print(standardMsg)
     return False
diff --git a/Testing/SystemTests/tests/analysis/ISISDirectInelastic.py b/Testing/SystemTests/tests/analysis/ISISDirectInelastic.py
index be3b522cb919f0106534f85b2e880df7fc80c6c1..c7f573bea9b6bb01a1824cc3455a149ca3adcb0b 100644
--- a/Testing/SystemTests/tests/analysis/ISISDirectInelastic.py
+++ b/Testing/SystemTests/tests/analysis/ISISDirectInelastic.py
@@ -1,4 +1,5 @@
 #pylint: disable=no-init
+from __future__ import (absolute_import, division, print_function)
 import stresstesting
 from mantid.simpleapi import *
 from mantid.api import Workspace
@@ -7,10 +8,11 @@ import shutil
 
 from abc import ABCMeta, abstractmethod
 from Direct.PropertyManager  import PropertyManager
+from six import with_metaclass
 
 
 #----------------------------------------------------------------------
-class ISISDirectInelasticReduction(stresstesting.MantidStressTest):
+class ISISDirectInelasticReduction(with_metaclass(ABCMeta, stresstesting.MantidStressTest)):
     """A base class for the ISIS direct inelastic tests
 
     The workflow is defined in the runTest() method, simply
@@ -27,7 +29,6 @@ class ISISDirectInelasticReduction(stresstesting.MantidStressTest):
         - sample_rmm: A float value for the sample rmm or None
         - hard_mask: An hard mask file or None
     """
-    __metaclass__ = ABCMeta # Mark as an abstract class
     tolerance=0.
     tolerance_is_reller=True
 
diff --git a/Testing/SystemTests/tests/analysis/ISISDirectReductionComponents.py b/Testing/SystemTests/tests/analysis/ISISDirectReductionComponents.py
index de92eb1094d7588bef30721ee164bfbc43e17e52..442e62aaa04dc0b42bbd1f011a4882fd2b68db29 100644
--- a/Testing/SystemTests/tests/analysis/ISISDirectReductionComponents.py
+++ b/Testing/SystemTests/tests/analysis/ISISDirectReductionComponents.py
@@ -1,4 +1,5 @@
 #pylint: disable=invalid-name
+from __future__ import (absolute_import, division, print_function)
 import os
 import sys
 import stresstesting
@@ -7,6 +8,10 @@ from mantid.api import Workspace,IEventWorkspace
 
 from Direct.PropertyManager import PropertyManager
 import ISIS_MariReduction as mr
+try:
+    from importlib import reload
+except ImportError:
+    pass
 
 #----------------------------------------------------------------------
 
@@ -112,12 +117,12 @@ class ISIS_ReductionWrapperValidate(stresstesting.MantidStressTest):
             rez,mess = rd.run_reduction()
             self.result=rez
             if not rez:
-                print "*** Validation failed: {0}".format(mess)
+                print("*** Validation failed: {0}".format(mess))
             if mess.find('Created')>-1: # validation still failed due to missing validation file
-                print "*** Validation failed: {0}".format(mess)
+                print("*** Validation failed: {0}".format(mess))
                 self.result=False
         except RuntimeError as err:
-            print "*** Validation failed with error: {0}".format(err.message)
+            print("*** Validation failed with error: {0}".format(err.message))
             self.result=False
         rd.reducer.prop_man.save_file_name = None
 
@@ -243,7 +248,7 @@ class ISISLoadFilesMER(stresstesting.MantidStressTest):
         self.assertTrue(isinstance(ei_ws,Workspace))
 
         en_peaks = ei_ws.readX(0)
-        self.assertAlmostEquals(len(en_peaks),1)
+        self.assertAlmostEqual(len(en_peaks),1)
         self.assertAlmostEqual(en_peaks[0],108.94,2)
 
         self.valid = True
diff --git a/Testing/SystemTests/tests/analysis/ISISIndirectBayesTest.py b/Testing/SystemTests/tests/analysis/ISISIndirectBayesTest.py
index d52af1e7e6c848fe212fefa8ce4bd47c11282b7e..23bbc3641272677f12024636d9c845740353d5c5 100644
--- a/Testing/SystemTests/tests/analysis/ISISIndirectBayesTest.py
+++ b/Testing/SystemTests/tests/analysis/ISISIndirectBayesTest.py
@@ -1,9 +1,11 @@
 #pylint: disable=no-init,attribute-defined-outside-init, too-few-public-methods
+from __future__ import (absolute_import, division, print_function)
 import stresstesting
 import os
 from abc import ABCMeta, abstractmethod
 from mantid.simpleapi import *
 import platform
+from six import with_metaclass
 
 #==============================================================================
 
@@ -316,9 +318,7 @@ class QLWidthTest(stresstesting.MantidStressTest):
 #==============================================================================
 
 
-class JumpFitFunctionTestBase(stresstesting.MantidStressTest):
-
-    __metaclass__ = ABCMeta
+class JumpFitFunctionTestBase(with_metaclass(ABCMeta, stresstesting.MantidStressTest)):
 
     def __init__(self):
         stresstesting.MantidStressTest.__init__(self)
diff --git a/Testing/SystemTests/tests/analysis/ISISIndirectInelastic.py b/Testing/SystemTests/tests/analysis/ISISIndirectInelastic.py
index cc1a1b8a10701da584db652c10dde60d30ff4e9a..4b74f53b4979b3ae88db0d16ffad0bf213e5e34e 100644
--- a/Testing/SystemTests/tests/analysis/ISISIndirectInelastic.py
+++ b/Testing/SystemTests/tests/analysis/ISISIndirectInelastic.py
@@ -67,6 +67,7 @@ stresstesting.MantidStressTest
      |
 '''
 
+from __future__ import (absolute_import, division, print_function)
 import stresstesting
 import os
 from abc import ABCMeta, abstractmethod
@@ -75,15 +76,14 @@ from mantid.simpleapi import *
 
 # For debugging only.
 from mantid.api import FileFinder
+from six import with_metaclass
 
 
-class ISISIndirectInelasticBase(stresstesting.MantidStressTest):
+class ISISIndirectInelasticBase(with_metaclass(ABCMeta, stresstesting.MantidStressTest)):
     '''
     A common base class for the ISISIndirectInelastic* base classes.
     '''
 
-    __metaclass__ = ABCMeta  # Mark as an abstract class
-
     @abstractmethod
     def get_reference_files(self):
         '''Returns the name of the reference files to compare against.'''
@@ -138,7 +138,7 @@ class ISISIndirectInelasticBase(stresstesting.MantidStressTest):
                                    reference_file)
 
             if not self.validateWorkspaces([result, wsName]):
-                print str([reference_file, result]) + " do not match."
+                print(str([reference_file, result]) + " do not match.")
                 return False
 
         return True
@@ -151,7 +151,7 @@ class ISISIndirectInelasticBase(stresstesting.MantidStressTest):
 #==============================================================================
 
 
-class ISISIndirectInelasticReduction(ISISIndirectInelasticBase):
+class ISISIndirectInelasticReduction(with_metaclass(ABCMeta, ISISIndirectInelasticBase)):
     '''A base class for the ISIS indirect inelastic reduction tests
 
     The workflow is defined in the _run() method, simply
@@ -165,8 +165,6 @@ class ISISIndirectInelasticReduction(ISISIndirectInelasticBase):
         - save_formats: A list containing the file extensions of the formats
                         to save to.
     '''
-
-    __metaclass__ = ABCMeta  # Mark as an abstract class
     sum_files = False
 
     def _run(self):
@@ -337,7 +335,7 @@ class IRISMultiFileSummedReduction(ISISIndirectInelasticReduction):
 #==============================================================================
 
 
-class ISISIndirectInelasticCalibration(ISISIndirectInelasticBase):
+class ISISIndirectInelasticCalibration(with_metaclass(ABCMeta, ISISIndirectInelasticBase)):
     '''A base class for the ISIS indirect inelastic calibration tests
 
     The workflow is defined in the _run() method, simply
@@ -351,8 +349,6 @@ class ISISIndirectInelasticCalibration(ISISIndirectInelasticBase):
         - self.reflection: a string giving the reflection to use
     '''
 
-    __metaclass__ = ABCMeta  # Mark as an abstract class
-
     def _run(self):
         '''Defines the workflow for the test'''
         self.tolerance = 1e-7
@@ -410,7 +406,7 @@ class IRISCalibration(ISISIndirectInelasticCalibration):
 #==============================================================================
 
 
-class ISISIndirectInelasticResolution(ISISIndirectInelasticBase):
+class ISISIndirectInelasticResolution(with_metaclass(ABCMeta, ISISIndirectInelasticBase)):
     '''A base class for the ISIS indirect inelastic resolution tests
 
     The workflow is defined in the _run() method, simply
@@ -425,8 +421,6 @@ class ISISIndirectInelasticResolution(ISISIndirectInelasticBase):
         - self.files: a list of strings containing filenames
     '''
 
-    __metaclass__ = ABCMeta  # Mark as an abstract class
-
     def _run(self):
         '''Defines the workflow for the test'''
         self.tolerance = 1e-7
@@ -500,7 +494,7 @@ class IRISResolution(ISISIndirectInelasticResolution):
 #==============================================================================
 
 
-class ISISIndirectInelasticDiagnostics(ISISIndirectInelasticBase):
+class ISISIndirectInelasticDiagnostics(with_metaclass(ABCMeta, ISISIndirectInelasticBase)):
     '''A base class for the ISIS indirect inelastic diagnostic tests
 
     The workflow is defined in the _run() method, simply
@@ -508,8 +502,6 @@ class ISISIndirectInelasticDiagnostics(ISISIndirectInelasticBase):
     on the object
     '''
 
-    __metaclass__ = ABCMeta  # Mark as an abstract class
-
     def _run(self):
         '''Defines the workflow for the test'''
 
@@ -576,14 +568,12 @@ class OSIRISDiagnostics(ISISIndirectInelasticDiagnostics):
 #==============================================================================
 
 
-class ISISIndirectInelasticMoments(ISISIndirectInelasticBase):
+class ISISIndirectInelasticMoments(with_metaclass(ABCMeta, ISISIndirectInelasticBase)):
     '''A base class for the ISIS indirect inelastic TransformToIqt/TransformToIqtFit tests
 
     The output of Elwin is usually used with MSDFit and so we plug one into
     the other in this test.
     '''
-    # Mark as an abstract class
-    __metaclass__ = ABCMeta
 
     def _run(self):
         '''Defines the workflow for the test'''
@@ -642,15 +632,13 @@ class IRISMoments(ISISIndirectInelasticMoments):
 #==============================================================================
 
 
-class ISISIndirectInelasticElwinAndMSDFit(ISISIndirectInelasticBase):
+class ISISIndirectInelasticElwinAndMSDFit(with_metaclass(ABCMeta, ISISIndirectInelasticBase)):
     '''A base class for the ISIS indirect inelastic Elwin/MSD Fit tests
 
     The output of Elwin is usually used with MSDFit and so we plug one into
     the other in this test.
     '''
 
-    __metaclass__ = ABCMeta  # Mark as an abstract class
-
     def _run(self):
         '''Defines the workflow for the test'''
         self.tolerance = 1e-7
@@ -743,7 +731,7 @@ class IRISElwinAndMSDFit(ISISIndirectInelasticElwinAndMSDFit):
 #==============================================================================
 
 
-class ISISIndirectInelasticIqtAndIqtFit(ISISIndirectInelasticBase):
+class ISISIndirectInelasticIqtAndIqtFit(with_metaclass(ABCMeta, ISISIndirectInelasticBase)):
     '''
     A base class for the ISIS indirect inelastic Iqt/IqtFit tests
 
@@ -751,8 +739,6 @@ class ISISIndirectInelasticIqtAndIqtFit(ISISIndirectInelasticBase):
     the other in this test.
     '''
 
-    __metaclass__ = ABCMeta  # Mark as an abstract class
-
     def _run(self):
         '''Defines the workflow for the test'''
         self.tolerance = 1e-7
@@ -871,15 +857,13 @@ class IRISIqtAndIqtFit(ISISIndirectInelasticIqtAndIqtFit):
 #==============================================================================
 
 
-class ISISIndirectInelasticIqtAndIqtFitMulti(ISISIndirectInelasticBase):
+class ISISIndirectInelasticIqtAndIqtFitMulti(with_metaclass(ABCMeta, ISISIndirectInelasticBase)):
     '''A base class for the ISIS indirect inelastic Iqt/IqtFit tests
 
     The output of Elwin is usually used with MSDFit and so we plug one into
     the other in this test.
     '''
 
-    __metaclass__ = ABCMeta  # Mark as an abstract class
-
     def _run(self):
         '''Defines the workflow for the test'''
         self.tolerance = 1e-6
@@ -1000,15 +984,13 @@ class IRISIqtAndIqtFitMulti(ISISIndirectInelasticIqtAndIqtFitMulti):
 #==============================================================================
 
 
-class ISISIndirectInelasticConvFit(ISISIndirectInelasticBase):
+class ISISIndirectInelasticConvFit(with_metaclass(ABCMeta, ISISIndirectInelasticBase)):
     '''A base class for the ISIS indirect inelastic ConvFit tests
 
     The workflow is defined in the _run() method, simply
     define an __init__ method and set the following properties
     on the object
     '''
-    # Mark as an abstract class
-    __metaclass__ = ABCMeta
 
     def _run(self):
         '''Defines the workflow for the test'''
@@ -1019,6 +1001,7 @@ class ISISIndirectInelasticConvFit(ISISIndirectInelasticBase):
         ConvolutionFitSequential(
             InputWorkspace=self.sample,
             Function=self.func,
+            PassWSIndexToFunction=self.passWSIndexToFunction,
             StartX=self.startx,
             EndX=self.endx,
             BackgroundType=self.bg,
@@ -1062,6 +1045,7 @@ class OSIRISConvFit(ISISIndirectInelasticConvFit):
         self.func = 'name=LinearBackground,A0=0,A1=0;(composite=Convolution,FixResolution=true,NumDeriv=true;'\
                     'name=Resolution,Workspace=\"%s\";name=Lorentzian,Amplitude=2,FWHM=0.002,ties=(PeakCentre=0)'\
                     ',constraints=(FWHM>0.002))' % self.resolution
+        self.passWSIndexToFunction = False  # osi97935_graphite002_res is single histogram
         self.startx = -0.2
         self.endx = 0.2
         self.bg = 'Fit Linear'
@@ -1089,7 +1073,7 @@ class IRISConvFit(ISISIndirectInelasticConvFit):
                     '(composite=Convolution,FixResolution=true,NumDeriv=true;' \
                     'name=Resolution,Workspace="%s";name=Lorentzian,Amplitude=1.033150,FWHM=0.001576,'\
                     'ties=(PeakCentre=0.0),constraints=(FWHM>0.001))' % self.resolution
-
+        self.passWSIndexToFunction = False  # irs53664_graphite002_res is single histogram
         self.startx = -0.2
         self.endx = 0.2
         self.bg = 'Fit Linear'
@@ -1107,10 +1091,8 @@ class IRISConvFit(ISISIndirectInelasticConvFit):
 # Transmission Monitor Test
 
 
-class ISISIndirectInelasticTransmissionMonitor(ISISIndirectInelasticBase):
+class ISISIndirectInelasticTransmissionMonitor(with_metaclass(ABCMeta, ISISIndirectInelasticBase)):
     # Mark as an abstract class
-    __metaclass__ = ABCMeta
-
     def _run(self):
         '''Defines the workflow for the test'''
 
diff --git a/Testing/SystemTests/tests/analysis/ISISIndirectLoadAsciiTest.py b/Testing/SystemTests/tests/analysis/ISISIndirectLoadAsciiTest.py
index 8c0a7d58c4d1eae17adcfdb9a8627fae1efc3325..94819aaddeb581991d68db2ac7ef8da1c604a62b 100644
--- a/Testing/SystemTests/tests/analysis/ISISIndirectLoadAsciiTest.py
+++ b/Testing/SystemTests/tests/analysis/ISISIndirectLoadAsciiTest.py
@@ -1,4 +1,5 @@
 #pylint: disable=no-init,attribute-defined-outside-init
+from __future__ import (absolute_import, division, print_function)
 import stresstesting
 import mantid.simpleapi as ms
 
@@ -70,7 +71,7 @@ class IN13CaFTest(stresstesting.MantidStressTest):
         checker.execute()
 
         if not checker.getProperty("Result"):
-            print self.__class__.__name__
+            print(self.__class__.__name__)
             ms.SaveNexus(InputWorkspace=ws2,Filename=self.__class__.__name__+'-mismatch.nxs')
             return False
 
diff --git a/Testing/SystemTests/tests/analysis/ISISIndirectSimulationTest.py b/Testing/SystemTests/tests/analysis/ISISIndirectSimulationTest.py
index 42abb848d014f707ced58374e680ab5695e5a2e4..a434e39adce4f90c8cf907d93383c118599ce3a0 100644
--- a/Testing/SystemTests/tests/analysis/ISISIndirectSimulationTest.py
+++ b/Testing/SystemTests/tests/analysis/ISISIndirectSimulationTest.py
@@ -1,4 +1,5 @@
 #pylint: disable=no-init,attribute-defined-outside-init
+from __future__ import (absolute_import, division, print_function)
 import stresstesting
 import mantid.simpleapi as ms
 
@@ -43,7 +44,7 @@ class MolDynCdlTest(stresstesting.MantidStressTest):
         checker.execute()
 
         if not checker.getProperty("Result"):
-            print self.__class__.__name__
+            print(self.__class__.__name__)
             ms.SaveNexus(InputWorkspace=ws2,Filename=self.__class__.__name__+'-mismatch.nxs')
             return False
 
diff --git a/Testing/SystemTests/tests/analysis/ISISMuonAnalysis.py b/Testing/SystemTests/tests/analysis/ISISMuonAnalysis.py
index 098cb1749781a4114e1a9bd821a3f859033abdbb..24892a5d36efc360af6f32e3de100a82df8b37be 100644
--- a/Testing/SystemTests/tests/analysis/ISISMuonAnalysis.py
+++ b/Testing/SystemTests/tests/analysis/ISISMuonAnalysis.py
@@ -1,14 +1,16 @@
 #pylint: disable=no-init,invalid-name,attribute-defined-outside-init,too-many-instance-attributes,too-few-public-methods
+from __future__ import (absolute_import, division, print_function)
 import math
 import stresstesting
 from mantid.simpleapi import *
 
 from abc import ABCMeta, abstractmethod
+from six import with_metaclass
 
 #----------------------------------------------------------------------
 
 
-class ISISMuonAnalysis(stresstesting.MantidStressTest):
+class ISISMuonAnalysis(with_metaclass(ABCMeta, stresstesting.MantidStressTest)):
     """A base class for the ISIS Muon Analysis tests
 
     The workflow is defined in the runTest() method, simply
@@ -26,7 +28,6 @@ class ISISMuonAnalysis(stresstesting.MantidStressTest):
         - rebin_fixed: Optional boolean to tell if the rebinning is in fixed steps.
         - rebin_params: A string containing the rebin parameters. See wiki rebin for more info.
     """
-    __metaclass__ = ABCMeta # Mark as an abstract class
 
     @abstractmethod
     def get_reference_file(self):
diff --git a/Testing/SystemTests/tests/analysis/ISISMuonAnalysisGrouping.py b/Testing/SystemTests/tests/analysis/ISISMuonAnalysisGrouping.py
index 5cd48d7c1f91c7b48980234c42b69620664e02ed..ff003fb298a75fca881ae763372f5b86903581fc 100644
--- a/Testing/SystemTests/tests/analysis/ISISMuonAnalysisGrouping.py
+++ b/Testing/SystemTests/tests/analysis/ISISMuonAnalysisGrouping.py
@@ -1,13 +1,15 @@
 #pylint: disable=no-init,attribute-defined-outside-init,too-many-instance-attributes,too-few-public-methods
+from __future__ import (absolute_import, division, print_function)
 import stresstesting
 from mantid.simpleapi import *
 
 from abc import ABCMeta, abstractmethod
+from six import with_metaclass
 
 #----------------------------------------------------------------------
 
 
-class ISISMuonAnalysisGrouping(stresstesting.MantidStressTest):
+class ISISMuonAnalysisGrouping(with_metaclass(ABCMeta, stresstesting.MantidStressTest)):
     """A base class for the ISIS Muon Analysis tests
 
     The workflow is defined in the runTest() method, simply
@@ -23,7 +25,6 @@ class ISISMuonAnalysisGrouping(stresstesting.MantidStressTest):
         - x_min: Float value of the minimum x.
         - x_max: Float value of the maximum x.
     """
-    __metaclass__ = ABCMeta # Mark as an abstract class
 
     @abstractmethod
     def get_reference_file(self):
diff --git a/Testing/SystemTests/tests/analysis/ISISReflInstrumentIDFTest.py b/Testing/SystemTests/tests/analysis/ISISReflInstrumentIDFTest.py
index 507b008c4802c43402da6810fb4096e5c8c7cecf..93531a2f562ea120bf356e9b94a666040afc411f 100644
--- a/Testing/SystemTests/tests/analysis/ISISReflInstrumentIDFTest.py
+++ b/Testing/SystemTests/tests/analysis/ISISReflInstrumentIDFTest.py
@@ -3,15 +3,15 @@
 These system tests are to verify that the IDF and parameter files for POLREF, CRISP, INTER and SURF are read properly
 """
 
+from __future__ import (absolute_import, division, print_function)
 import stresstesting
 from mantid.simpleapi import *
 import os
 from abc import ABCMeta, abstractmethod
+from six import with_metaclass
 
 
-class ISISReflInstrumentIDFTest(stresstesting.MantidStressTest):
-
-    __metaclass__ = ABCMeta # Mark as an abstract class
+class ISISReflInstrumentIDFTest(with_metaclass(ABCMeta, stresstesting.MantidStressTest)):
 
     @abstractmethod
     def get_IDF_name(self):
diff --git a/Testing/SystemTests/tests/analysis/ISIS_WISHDiffractionFocussing.py b/Testing/SystemTests/tests/analysis/ISIS_WISHDiffractionFocussing.py
index 6450cb739820fd2110371db960bcb63fd1f96692..6dedc1da52022203de0467ff997bf0470e5848f1 100644
--- a/Testing/SystemTests/tests/analysis/ISIS_WISHDiffractionFocussing.py
+++ b/Testing/SystemTests/tests/analysis/ISIS_WISHDiffractionFocussing.py
@@ -1,3 +1,4 @@
+from __future__ import (absolute_import, division, print_function)
 from mantid.simpleapi import *
 import stresstesting
 import os.path
@@ -31,8 +32,8 @@ class WISHDiffractionFocussingReductionTest(stresstesting.MantidStressTest):
 
         run_numbers = [35991]
 
-        min_run = min(map(lambda x: x if type(x) == int else min(x), run_numbers))
-        max_run = max(map(lambda x: x if type(x) == int else max(x), run_numbers))
+        min_run = min([x if type(x) == int else min(x) for x in run_numbers])
+        max_run = max([x if type(x) == int else max(x) for x in run_numbers])
         group_name = str(min_run) + '-' + str(max_run) + focused_suffix
 
         self._focused_workspaces = []
@@ -88,9 +89,6 @@ class WISHDiffractionFocussingAnalysisTest(stresstesting.MantidStressTest):
                 "35993-foc-h00.nxs",
                 "WISHDiffractionFocussingResult.nxs"]
 
-    def requiredMemoryMB(self):
-        pass
-
     def cleanup(self):
         pass
 
@@ -104,10 +102,8 @@ class WISHDiffractionFocussingAnalysisTest(stresstesting.MantidStressTest):
         suffix = "-foc-h00"
         integrate_suffix = "-int"
 
-        min_run = min(map(lambda x: x if type(x) == int else min(x),
-                          run_numbers))
-        max_run = max(map(lambda x: x if type(x) == int else max(x),
-                          run_numbers))
+        min_run = min([x if type(x) == int else min(x) for x in run_numbers])
+        max_run = max([x if type(x) == int else max(x) for x in run_numbers])
 
         group_name = str(min_run) + '-' + str(max_run)
         group_name += suffix + integrate_suffix
@@ -117,7 +113,7 @@ class WISHDiffractionFocussingAnalysisTest(stresstesting.MantidStressTest):
         integration_range = {"RangeLower": 16.2, "RangeUpper": 17.2}
 
         table = create_table(table_name, log_names, len(run_numbers))
-        run_names = map(lambda x: convert_run_to_name(x, suffix), run_numbers)
+        run_names = [convert_run_to_name(x, suffix) for x in run_numbers]
 
         output_names = []
         for i, run in enumerate(run_names):
@@ -143,7 +139,7 @@ class WISHDiffractionFocussingAnalysisTest(stresstesting.MantidStressTest):
             # add to table
             row = [get_log(w1, name) for name in log_names]
             row.extend([w1.readY(0), w1.readE(0) ])
-            row = map(float, row)
+            row = list(map(float, row))
             table.addRow(row)
 
             # add to workspace group
diff --git a/Testing/SystemTests/tests/analysis/IndirectDiffractionTests.py b/Testing/SystemTests/tests/analysis/IndirectDiffractionTests.py
index 075edc1ad26259d61f5866966c6d40ddd320140f..f080bf13ca71e9c28e443eb8203a5f1ee6f16c72 100644
--- a/Testing/SystemTests/tests/analysis/IndirectDiffractionTests.py
+++ b/Testing/SystemTests/tests/analysis/IndirectDiffractionTests.py
@@ -1,18 +1,18 @@
 #pylint: disable=no-init,non-parent-init-called,too-few-public-methods
 # non-parent-init-called is disabled to remove false positives from a bug in pyLint < 1.4
+from __future__ import (absolute_import, division, print_function)
 
 from abc import ABCMeta, abstractmethod
 import stresstesting
 import mantid.simpleapi as ms
 from mantid import mtd
+from six import with_metaclass
 
 
-class ISISIndirectDiffractionReduction(stresstesting.MantidStressTest):
+class ISISIndirectDiffractionReduction(with_metaclass(ABCMeta, stresstesting.MantidStressTest)):
     """
     Base class for tests that use the ISISIndirectDiffractionReduction algorithm.
     """
-
-    __metaclass__ = ABCMeta
     _output_workspace = None
 
     @abstractmethod
diff --git a/Testing/SystemTests/tests/analysis/LoadAndCheckBase.py b/Testing/SystemTests/tests/analysis/LoadAndCheckBase.py
index 6b4205b65547c913dbde8075911feee3aca9ef51..601f627e980681431a5c777002eb9adce3141aa5 100644
--- a/Testing/SystemTests/tests/analysis/LoadAndCheckBase.py
+++ b/Testing/SystemTests/tests/analysis/LoadAndCheckBase.py
@@ -3,16 +3,16 @@
 These system tests are to verify the behaviour of the ISIS reflectometry reduction scripts
 """
 
+from __future__ import (absolute_import, division, print_function)
 import stresstesting
 from mantid.simpleapi import *
 import mantid.api
 
 from abc import ABCMeta, abstractmethod
+from six import with_metaclass
 
 
-class LoadAndCheckBase(stresstesting.MantidStressTest):
-
-    __metaclass__ = ABCMeta # Mark as an abstract class
+class LoadAndCheckBase(with_metaclass(ABCMeta, stresstesting.MantidStressTest)):
 
     __comparison_out_workspace_name = 'a_integrated'
 
diff --git a/Testing/SystemTests/tests/analysis/LoadLotsOfInstruments.py b/Testing/SystemTests/tests/analysis/LoadLotsOfInstruments.py
index a3723d811463d38944141464fd7c8482e7da4a4f..9ab922ac695dd65f13fdb35cf20e8507d15e1a63 100644
--- a/Testing/SystemTests/tests/analysis/LoadLotsOfInstruments.py
+++ b/Testing/SystemTests/tests/analysis/LoadLotsOfInstruments.py
@@ -1,4 +1,5 @@
 #pylint: disable=no-init,invalid-name,too-few-public-methods
+from __future__ import (absolute_import, division, print_function)
 from mantid.simpleapi import *
 from mantid.api import FrameworkManager
 import os
@@ -12,7 +13,7 @@ class LoadLotsOfInstruments(stresstesting.MantidStressTest):
     def __getDataFileList__(self):
         # get a list of directories to look in
         direc = config['instrumentDefinition.directory']
-        print "Looking for instrument definition files in: %s" % direc
+        print("Looking for instrument definition files in: %s" % direc)
         cwd = os.getcwd()
         os.chdir(direc)
         myFiles = glob.glob("*Definition*.xml")
@@ -27,8 +28,8 @@ class LoadLotsOfInstruments(stresstesting.MantidStressTest):
 
     def __loadAndTest__(self, filename):
         """Do all of the real work of loading and testing the file"""
-        print "----------------------------------------"
-        print "Loading '%s'" % filename
+        print("----------------------------------------")
+        print("Loading '%s'" % filename)
         wksp = LoadEmptyInstrument(filename)
         if wksp is None:
             return False
@@ -38,7 +39,7 @@ class LoadLotsOfInstruments(stresstesting.MantidStressTest):
             del wksp
             return False
         if wksp.getMemorySize() <= 0:
-            print "Workspace takes no memory: Memory used=" + str(wksp.getMemorySize())
+            print("Workspace takes no memory: Memory used=" + str(wksp.getMemorySize()))
             del wksp
             return False
 
@@ -55,25 +56,25 @@ class LoadLotsOfInstruments(stresstesting.MantidStressTest):
         for filename in files:
             try:
                 if not self.__loadAndTest__(filename):
-                    print "FAILED TO LOAD '%s'" % filename
+                    print("FAILED TO LOAD '%s'" % filename)
                     failed.append(filename)
             #pylint: disable=broad-except
-            except Exception, e:
-                print "FAILED TO LOAD '%s' WITH ERROR:" % filename
-                print e
+            except Exception as e:
+                print("FAILED TO LOAD '%s' WITH ERROR:" % filename)
+                print(e)
                 failed.append(filename)
             finally:
                 # Clear everything for the next test
                 FrameworkManager.Instance().clear()
 
         # final say on whether or not it 'worked'
-        print "----------------------------------------"
+        print("----------------------------------------")
         if len(failed) != 0:
-            print "SUMMARY OF FAILED FILES"
+            print("SUMMARY OF FAILED FILES")
             for filename in failed:
-                print filename
+                print(filename)
             raise RuntimeError("Failed to load %d of %d files"
                                % (len(failed), len(files)))
         else:
-            print "Successfully loaded %d files" % len(files)
-        print files
+            print("Successfully loaded %d files" % len(files))
+        print(files)
diff --git a/Testing/SystemTests/tests/analysis/LoadVesuvioTest.py b/Testing/SystemTests/tests/analysis/LoadVesuvioTest.py
index 79b760a18f905555e4dc8df4064fc58142143207..37d313f3b3fbbff3f6391a0d12e13ba749464602 100644
--- a/Testing/SystemTests/tests/analysis/LoadVesuvioTest.py
+++ b/Testing/SystemTests/tests/analysis/LoadVesuvioTest.py
@@ -1,4 +1,5 @@
 #pylint: disable=invalid-name,no-init,too-many-public-methods,too-many-arguments
+from __future__ import (absolute_import, division, print_function)
 import stresstesting
 
 from mantid.api import FileFinder, MatrixWorkspace, mtd
@@ -51,19 +52,19 @@ class VesuvioTests(unittest.TestCase):
         rawfile = FileFinder.getFullPath("EVS14188.raw")
         self._run_load(rawfile, "3", diff_mode)
         self.assertTrue(mtd.doesExist('evs_raw'))
-        self.assertEquals(mtd['evs_raw'].getNumberHistograms(), 1)
+        self.assertEqual(mtd['evs_raw'].getNumberHistograms(), 1)
 
     def test_filename_accepts_filename_no_path(self):
         diff_mode = "FoilOut"
         self._run_load("EVS14188.raw", "3", diff_mode)
         self.assertTrue(mtd.doesExist('evs_raw'))
-        self.assertEquals(mtd['evs_raw'].getNumberHistograms(), 1)
+        self.assertEqual(mtd['evs_raw'].getNumberHistograms(), 1)
 
     def test_filename_accepts_run_and_ext(self):
         diff_mode = "FoilOut"
         self._run_load("14188.raw", "3", diff_mode)
         self.assertTrue(mtd.doesExist('evs_raw'))
-        self.assertEquals(mtd['evs_raw'].getNumberHistograms(), 1)
+        self.assertEqual(mtd['evs_raw'].getNumberHistograms(), 1)
 
     def test_load_with_back_scattering_spectra_produces_correct_workspace_using_double_difference(self):
         diff_mode = "DoubleDifference"
@@ -126,7 +127,7 @@ class VesuvioTests(unittest.TestCase):
         diff_mode = "FoilOut"
         self._run_load("14188", "1-198", diff_mode, load_mon=True)
         self.assertTrue(mtd.doesExist('evs_raw'))
-        self.assertEquals(mtd['evs_raw'].getNumberHistograms(), 198)
+        self.assertEqual(mtd['evs_raw'].getNumberHistograms(), 198)
         self.assertFalse(mtd.doesExist('evs_raw_monitors'))
 
     def test_load_with_back_scattering_spectra_produces_correct_workspace_using_single_difference(self):
@@ -226,7 +227,7 @@ class VesuvioTests(unittest.TestCase):
         evs_raw = mtd[self.ws_name]
 
         # Verify
-        self.assertEquals(1, evs_raw.getNumberHistograms())
+        self.assertEqual(1, evs_raw.getNumberHistograms())
         self.assertAlmostEqual(5.0, evs_raw.readX(0)[0], places=DIFF_PLACES)
         self.assertAlmostEqual(599.5, evs_raw.readX(0)[-1], places=DIFF_PLACES)
         self.assertAlmostEqual(-1.5288171762918328, evs_raw.readY(0)[0], places=DIFF_PLACES)
@@ -239,7 +240,7 @@ class VesuvioTests(unittest.TestCase):
         evs_raw = mtd[self.ws_name]
 
         # Verify
-        self.assertEquals(2, evs_raw.getNumberHistograms())
+        self.assertEqual(2, evs_raw.getNumberHistograms())
         self.assertAlmostEqual(5.0, evs_raw.readX(0)[0], places=DIFF_PLACES)
         self.assertAlmostEqual(5.0, evs_raw.readX(1)[0], places=DIFF_PLACES)
         self.assertAlmostEqual(599.5, evs_raw.readX(0)[-1], places=DIFF_PLACES)
@@ -260,7 +261,7 @@ class VesuvioTests(unittest.TestCase):
         evs_raw = mtd[self.ws_name]
 
         # Verify
-        self.assertEquals(1, evs_raw.getNumberHistograms())
+        self.assertEqual(1, evs_raw.getNumberHistograms())
         self.assertAlmostEqual(5.0, evs_raw.readX(0)[0], places=DIFF_PLACES)
         self.assertAlmostEqual(19990.0, evs_raw.readX(0)[-1], places=DIFF_PLACES)
         self.assertAlmostEqual(497722.0, evs_raw.readY(0)[0], places=DIFF_PLACES)
@@ -276,7 +277,7 @@ class VesuvioTests(unittest.TestCase):
         evs_raw = mtd[self.ws_name]
 
         # Verify
-        self.assertEquals(2, evs_raw.getNumberHistograms())
+        self.assertEqual(2, evs_raw.getNumberHistograms())
         self.assertAlmostEqual(5.0, evs_raw.readX(0)[0], places=DIFF_PLACES)
         self.assertAlmostEqual(5.0, evs_raw.readX(1)[0], places=DIFF_PLACES)
         self.assertAlmostEqual(19990.0, evs_raw.readX(0)[-1], places=DIFF_PLACES)
@@ -289,10 +290,10 @@ class VesuvioTests(unittest.TestCase):
         self._verify_spectra_numbering(evs_raw.getSpectrum(0), 3,
                                        range(2101,2114))
         self._verify_spectra_numbering(evs_raw.getSpectrum(1), 30,
-                                       range(2128,2145) + range(2201,2205))
+                                       list(range(2128,2145)) + list(range(2201,2205)))
 
     def _verify_spectra_numbering(self, spectrum, expected_no, expected_ids):
-        self.assertEquals(expected_no, spectrum.getSpectrumNo())
+        self.assertEqual(expected_no, spectrum.getSpectrumNo())
         det_ids = spectrum.getDetectorIDs()
         for expected_id, det_id in zip(expected_ids, det_ids):
             self.assertEqual(expected_id, det_id)
@@ -370,7 +371,7 @@ class VesuvioTests(unittest.TestCase):
 
     def _do_size_check(self,name, expected_nhist):
         loaded_data = mtd[name]
-        self.assertEquals(expected_nhist, loaded_data.getNumberHistograms())
+        self.assertEqual(expected_nhist, loaded_data.getNumberHistograms())
 
     #================== Failure cases ================================
 
diff --git a/Testing/SystemTests/tests/analysis/MDWorkspaceTests.py b/Testing/SystemTests/tests/analysis/MDWorkspaceTests.py
index bb6fa5bfac196b1c36614af11a5ceedbec9548d1..74b8a172997f722f2e88feba7f2b3ad42a1a3fdd 100644
--- a/Testing/SystemTests/tests/analysis/MDWorkspaceTests.py
+++ b/Testing/SystemTests/tests/analysis/MDWorkspaceTests.py
@@ -4,11 +4,13 @@ Test some features of MDWorkspaces, such as
 file-backed MDWorkspaces.
 """
 
+from __future__ import (absolute_import, division, print_function)
 import stresstesting
 import os
 from mantid.simpleapi import *
 from mantid.api import *
 from mantid.kernel import *
+from six.moves import range
 
 ###############################################################################
 
@@ -25,7 +27,7 @@ class PlusMDTest(stresstesting.MantidStressTest):
         ws = mtd["test_binned"]
         EqualToMD(LHSWorkspace=ws, RHSWorkspace=self.original_binned, OutputWorkspace='comparison')
         comparison = mtd['comparison']
-        for i in xrange(comparison.getNPoints()):
+        for i in range(comparison.getNPoints()):
             if not comparison.signalAt(i):
                 raise Exception("Difference in workspace %s vs original_binned at index %d" % (wsname, i))
 
@@ -152,8 +154,8 @@ class MergeMDTest(stresstesting.MantidStressTest):
         LoadEventNexus(Filename='CNCS_7860_event.nxs',
                        OutputWorkspace='CNCS_7860_event_NXS',CompressTolerance=0.1)
 
-        for omega in xrange(0, 5):
-            print "Starting omega %03d degrees" % omega
+        for omega in range(0, 5):
+            print("Starting omega %03d degrees" % omega)
             CreateMDWorkspace(Dimensions='3',Extents='-5,5,-5,5,-5,5',Names='Q_sample_x,Q_sample_y,Q__sample_z',
                               Units='A,A,A',SplitInto='3',SplitThreshold='200',MaxRecursionDepth='3',
                               MinRecursionDepth='3', OutputWorkspace='CNCS_7860_event_MD')
diff --git a/Testing/SystemTests/tests/analysis/POLDICreatePeaksFromCellTest.py b/Testing/SystemTests/tests/analysis/POLDICreatePeaksFromCellTest.py
index ab91209754ddbabaa4a6eca419c9bec2875285ff..822102cb388db97b63c12f5698f11b3cda984469 100644
--- a/Testing/SystemTests/tests/analysis/POLDICreatePeaksFromCellTest.py
+++ b/Testing/SystemTests/tests/analysis/POLDICreatePeaksFromCellTest.py
@@ -1,4 +1,5 @@
 # pylint: disable=no-init,invalid-name,too-many-locals,too-few-public-methods
+from __future__ import (absolute_import, division, print_function)
 import stresstesting
 from mantid.simpleapi import *
 
@@ -41,11 +42,11 @@ class ReflectionCheckingTest(stresstesting.MantidStressTest):
 
             currentPeak = peakTable.row(idx)
 
-            self.assertEquals([int(x) for x in currentPeak['HKL'].split()], reference[0])
+            self.assertEqual([int(x) for x in currentPeak['HKL'].split()], reference[0])
             self.assertDelta(float(currentPeak['d']), reference[1], 1e-4)
 
             fSquaredReference = reference[2] ** 2 * reference[3]
-            print reference[0], fSquaredReference, float(currentPeak['Intensity'])
+            print(reference[0], fSquaredReference, float(currentPeak['Intensity']))
             self.assertDelta(float(currentPeak['Intensity']) / fSquaredReference, 1.0, structureFactorPrecision)
 
 
@@ -67,7 +68,7 @@ class POLDICreatePeaksFromCellTestSiO2(ReflectionCheckingTest):
             Atoms="Si 0.4723 0.0 2/3 1.0 0.0075; O 0.416 0.2658 0.7881 1.0 0.0175",
             a=4.91427, c=5.4058, LatticeSpacingMin=0.885)
 
-        self.assertEquals(peaks_SiO2.rowCount(), 118)
+        self.assertEqual(peaks_SiO2.rowCount(), 118)
 
         self.checkReflections(peaks_SiO2, self.data)
 
@@ -89,7 +90,7 @@ class POLDICreatePeaksFromCellTestAl2O3(ReflectionCheckingTest):
             Atoms="Al 0 0 0.35216 1.0 0.009; O 0.30668 0 1/4 1.0 0.0125",
             a=4.7605, c=12.9956, LatticeSpacingMin=0.885)
 
-        self.assertEquals(peaks_Al2O3.rowCount(), 44)
+        self.assertEqual(peaks_Al2O3.rowCount(), 44)
 
         self.checkReflections(peaks_Al2O3, self.data)
 
@@ -113,7 +114,7 @@ class POLDICreatePeaksFromCellTestFeTiO3(ReflectionCheckingTest):
             Atoms="Fe 0 0 0.35543 1.0 0.005; Zr 0 0 0.14643 1.0 0.004; O 0.31717 0.02351 0.24498 1.0 0.006",
             a=5.0881, c=14.091, LatticeSpacingMin=0.885)
 
-        self.assertEquals(peaks_FeTiO3.rowCount(), 108)
+        self.assertEqual(peaks_FeTiO3.rowCount(), 108)
 
         self.checkReflections(peaks_FeTiO3, self.data, 6e-5)
 
@@ -137,7 +138,7 @@ class POLDICreatePeaksFromCellTestCO(ReflectionCheckingTest):
             Atoms="C -0.042 -0.042 -0.042 1.0 0.0125; O 0.067 0.067 0.067 1.0 0.0125",
             a=5.63, LatticeSpacingMin=0.885)
 
-        self.assertEquals(peaks_CO.rowCount(), 91)
+        self.assertEqual(peaks_CO.rowCount(), 91)
 
         self.checkReflections(peaks_CO, self.data, 1e-5)
 
@@ -161,6 +162,6 @@ class POLDICreatePeaksFromCellTestBetaQuartz(ReflectionCheckingTest):
             Atoms="Si 1/2 0 0 1.0 0.025; O 0.41570 0.20785 1/6 1.0 0.058",
             a=4.9965, c=5.4546, LatticeSpacingMin=0.885)
 
-        self.assertEquals(peaks_betaSiO2.rowCount(), 65)
+        self.assertEqual(peaks_betaSiO2.rowCount(), 65)
 
         self.checkReflections(peaks_betaSiO2, self.data, 1e-5)
diff --git a/Testing/SystemTests/tests/analysis/POLDIFitPeaks1DTest.py b/Testing/SystemTests/tests/analysis/POLDIFitPeaks1DTest.py
index 3185b4eef9c3c12c51d646b135ad4b722dc1f928..0ae7306158d0e368ff990fa971fab01c448a2e5f 100644
--- a/Testing/SystemTests/tests/analysis/POLDIFitPeaks1DTest.py
+++ b/Testing/SystemTests/tests/analysis/POLDIFitPeaks1DTest.py
@@ -1,4 +1,5 @@
 #pylint: disable=no-init
+from __future__ import (absolute_import, division, print_function)
 import stresstesting
 from mantid.simpleapi import *
 import numpy as np
@@ -78,7 +79,7 @@ class POLDIFitPeaks1DTest(stresstesting.MantidStressTest):
                 position = [positions[i], positionErrors[i]]
                 fwhm = [fwhms[i], fwhmErrors[i]]
 
-                print position, fwhm, referencePositions
+                print(position, fwhm, referencePositions)
 
                 self.assertTrue(self.positionAcceptable(position))
                 self.assertTrue(self.fwhmAcceptable(fwhm))
diff --git a/Testing/SystemTests/tests/analysis/POLDIFitPeaks2DTest.py b/Testing/SystemTests/tests/analysis/POLDIFitPeaks2DTest.py
index 9d06bff33006837004d948d7c2d9b85fe651b37b..d410f025e66840dac231515d020c46c1ba49c990 100644
--- a/Testing/SystemTests/tests/analysis/POLDIFitPeaks2DTest.py
+++ b/Testing/SystemTests/tests/analysis/POLDIFitPeaks2DTest.py
@@ -1,4 +1,5 @@
 # pylint: disable=no-init,invalid-name,too-many-locals,too-few-public-methods
+from __future__ import (absolute_import, division, print_function)
 import stresstesting
 from mantid.simpleapi import *
 import numpy as np
@@ -57,7 +58,7 @@ class POLDIFitPeaks2DTest(stresstesting.MantidStressTest):
 
             columns = ["d", "Intensity"]
 
-            print fittedPeaks.rowCount(), referencePeaks.rowCount()
+            print(fittedPeaks.rowCount(), referencePeaks.rowCount())
 
             for i in range(referencePeaks.rowCount()):
                 referenceRow = referencePeaks.row(i)
@@ -104,7 +105,7 @@ class POLDIFitPeaks2DPawleyTest(stresstesting.MantidStressTest):
                                                            MaximumIterations=100)
 
         # parameters a and ZeroShift
-        self.assertEquals(cell.rowCount(), 2)
+        self.assertEqual(cell.rowCount(), 2)
 
         cell_a = cell.cell(0, 1)
         cell_a_err = cell.cell(0, 2)
@@ -139,7 +140,7 @@ class POLDIFitPeaks2DIntegratedIntensities(stresstesting.MantidStressTest):
                                                                 OutputIntegratedIntensities=True,
                                                                 MaximumIterations=100)
 
-        self.assertEquals(peaks_ref_2d.rowCount(), peaks_ref_2d_integrated.rowCount())
+        self.assertEqual(peaks_ref_2d.rowCount(), peaks_ref_2d_integrated.rowCount())
 
         for i in range(peaks_ref_2d.rowCount()):
             rowHeight = peaks_ref_2d.row(i)
diff --git a/Testing/SystemTests/tests/analysis/Peak2ConvCell_Test.py b/Testing/SystemTests/tests/analysis/Peak2ConvCell_Test.py
index 7e7ab7cea60cc85c6ead2b3ff59c244e11df5e18..6ae9aadd202d880bead36959f73e10b397746487 100644
--- a/Testing/SystemTests/tests/analysis/Peak2ConvCell_Test.py
+++ b/Testing/SystemTests/tests/analysis/Peak2ConvCell_Test.py
@@ -9,6 +9,7 @@
 
 
 # import stresstesting
+from __future__ import (absolute_import, division, print_function)
 import numpy
 from numpy import matrix
 import math
@@ -396,13 +397,13 @@ class Peak2ConvCell_Test(object):  # (stresstesting.MantidStressTest):
 
     def FixUB(self, UB, tolerance):
         done = 1
-        print "A"
+        print("A")
         while done == 1:
             done = 0
             X = UB.T * UB
             #X.I
 
-            print "B1", X
+            print("B1", X)
             if X[0, 0] > X[1, 1] or (math.fabs(X[0, 0] - X[1, 1]) < tolerance / 10 and math.fabs(X[1, 2]) > math.fabs(
                     X[0, 2]) + tolerance / 10):
                 done = 1
@@ -410,10 +411,10 @@ class Peak2ConvCell_Test(object):  # (stresstesting.MantidStressTest):
                     sav = UB[i, 0]
                     UB[i, 0] = UB[i, 1]
                     UB[i, 1] = sav
-                print "B"
+                print("B")
                 continue
 
-            print "B2"
+            print("B2")
             if X[1, 1] > X[2, 2] or (math.fabs(X[1, 1] - X[2, 2]) < tolerance and math.fabs(X[1, 0]) < math.fabs(
                     X[2, 0]) - tolerance / 10):
                 done = 1
@@ -422,18 +423,18 @@ class Peak2ConvCell_Test(object):  # (stresstesting.MantidStressTest):
                     UB[i, 1] = UB[i, 2]
                     UB[i, 2] = sav
 
-                print "C"
+                print("C")
                 continue
 
-            print "B3"
+            print("B3")
             if numpy.linalg.det(UB) < 0:
                 for i in range(0, 3):
                     UB[i, 0] = -1 * UB[i, 0]
 
-                print "D"
+                print("D")
                 done = 1
                 continue
-            print "E"
+            print("E")
             L = [X[0, 1], X[0, 2], X[1, 2]]
 
             nneg = 0
@@ -467,12 +468,12 @@ class Peak2ConvCell_Test(object):  # (stresstesting.MantidStressTest):
             odd = 2 - odd
             i1 = (odd + 1) % 3
             i2 = (odd + 2) % 3
-            print ["L=", L, odd, i1, i2, is90, tolerance]
-            print UB
+            print(["L=", L, odd, i1, i2, is90, tolerance])
+            print(UB)
             for i in range(0, 3):
                 UB[i, i1] = -1 * UB[i, i1]
                 UB[i, i2] = -1 * UB[i, i2]
-            print UB
+            print(UB)
             done = 1
         return UB
 
@@ -770,7 +771,7 @@ class Peak2ConvCell_Test(object):  # (stresstesting.MantidStressTest):
                     OrLat = mtd["Temp"].sample().getOrientedLattice()
                     Lat1 = [OrLat.a(), OrLat.b(), OrLat.c(), OrLat.alpha(), OrLat.beta(), OrLat.gamma()]
                     Lat1 = self.FixLatParams(Lat1)
-                    print ["Formnum,Lat1,Lat0", FormXtal[i1], Lat1, Lat0]
+                    print(["Formnum,Lat1,Lat0", FormXtal[i1], Lat1, Lat0])
                     if math.fabs(Lat0[0] - Lat1[0]) < tolerance and math.fabs(Lat0[1] - Lat1[1]) < tolerance \
                             and math.fabs(Lat0[2] - Lat1[2]) < tolerance:
 
@@ -828,10 +829,10 @@ class Peak2ConvCell_Test(object):  # (stresstesting.MantidStressTest):
                                 for i1 in range(3):
                                     for i2a in range(1, 3):
                                         if self.newSetting(side1, side2, Xtal, Center, ang, i1, i2a):
-                                            print "============================================================="
+                                            print("=============================================================")
                                             Sides = [startA, startA * side1Ratios[side1], startA * side1Ratios[side2]]
                                             Sides = self.MonoClinicRearrange(Sides, Xtal, Center, i1, i2a)
-                                            print [Sides, Error, Xtal, Center, ang, i1, i2a]
+                                            print([Sides, Error, Xtal, Center, ang, i1, i2a])
 
                                             UBconv = self.CalcConventionalUB(Sides[0], Sides[1], Sides[2], ang, ang,
                                                                              ang, Xtal)
@@ -853,7 +854,7 @@ class Peak2ConvCell_Test(object):  # (stresstesting.MantidStressTest):
                                             Lat0 = self.getLat(UBnig)
 
                                             Lat0 = self.FixLatParams(Lat0)
-                                            print ["UBnig", UBnig, Lat0]
+                                            print(["UBnig", UBnig, Lat0])
 
                                             Peaks = self.getPeaks(Inst, UBnig, Error, Npeaks + Error * 300)
 
@@ -893,8 +894,8 @@ class Peak2ConvCell_Test(object):  # (stresstesting.MantidStressTest):
                                             Lat1 = self.FixLatParams(Lat1)
 
                                             MatchXtalTol = .03 * (1 + 4 * Error) * (side1Ratios[side2])
-                                            print Lat0
-                                            print Lat1
+                                            print(Lat0)
+                                            print(Lat1)
                                             self.MatchXtlparams(Lat1, Lat0, MatchXtalTol, "Niggli values do not match")
 
                                             # Now see if the conventional cell is in list
diff --git a/Testing/SystemTests/tests/analysis/PowderDiffProfileCalibrateTest.py b/Testing/SystemTests/tests/analysis/PowderDiffProfileCalibrateTest.py
index cba9eb3f6674084e91af4e02dd99032cad80e4c4..094a4cc4694faf3e1ea1fee270e05a2bf655f189 100644
--- a/Testing/SystemTests/tests/analysis/PowderDiffProfileCalibrateTest.py
+++ b/Testing/SystemTests/tests/analysis/PowderDiffProfileCalibrateTest.py
@@ -8,6 +8,7 @@
 # for powder diffractometers.
 #
 ########################################################################
+from __future__ import (absolute_import, division, print_function)
 import stresstesting
 import mantid.simpleapi as api
 from mantid.simpleapi import *
@@ -85,7 +86,7 @@ class VulcanSeqRefineProfileFromScratch(stresstesting.MantidStressTest):
         ws = mtd[bkgdtablewsname]
         ws.addColumn("str", "Name")
         ws.addColumn("double", "Value")
-        for i in xrange(len(paramnames)):
+        for i in range(len(paramnames)):
             ws.addRow([paramnames[i], paramvalues[i]])
 
         # Examine profile
diff --git a/Testing/SystemTests/tests/analysis/ReflectometryISIS.py b/Testing/SystemTests/tests/analysis/ReflectometryISIS.py
index 4a6787a0eb4ed975c964540c8ee6d50d4cc351ef..15128ce306e3d1c42c3755940630835bf3d23af6 100644
--- a/Testing/SystemTests/tests/analysis/ReflectometryISIS.py
+++ b/Testing/SystemTests/tests/analysis/ReflectometryISIS.py
@@ -3,15 +3,15 @@
 These system tests are to verify the behaviour of the ISIS reflectometry reduction scripts
 """
 
+from __future__ import (absolute_import, division, print_function)
 import stresstesting
 from mantid.simpleapi import *
 
 from abc import ABCMeta, abstractmethod
+from six import with_metaclass
 
 
-class ReflectometryISIS(stresstesting.MantidStressTest):
-
-    __metaclass__ = ABCMeta # Mark as an abstract class
+class ReflectometryISIS(with_metaclass(ABCMeta, stresstesting.MantidStressTest)):
 
     @abstractmethod
     def get_workspace_name(self):
diff --git a/Testing/SystemTests/tests/analysis/ReuseExistingCalibration.py b/Testing/SystemTests/tests/analysis/ReuseExistingCalibration.py
index 2bdde8924ee15b4ee3c52ead40350c4a69d30018..0607db21febf6cd2b7deb78eea0d6f4165bd39c8 100644
--- a/Testing/SystemTests/tests/analysis/ReuseExistingCalibration.py
+++ b/Testing/SystemTests/tests/analysis/ReuseExistingCalibration.py
@@ -3,6 +3,7 @@
     Verifies that a calibration file can be loaded once and reused to apply, using CopyInstrumentParameters, the same calibration
     in successive reductions.
 """
+from __future__ import (absolute_import, division, print_function)
 import stresstesting
 
 
@@ -36,5 +37,5 @@ class ReuseExistingCalibration(stresstesting.MantidStressTest):
         if self.det_pos_second_run == self.det_pos_first_run:
             return True
         else:
-            print "Error: Detector position is not the same after the second reduction!"
+            print("Error: Detector position is not the same after the second reduction!")
             return False
diff --git a/Testing/SystemTests/tests/analysis/SANS2DMultiPeriodAddFilesTest_V2.py b/Testing/SystemTests/tests/analysis/SANS2DMultiPeriodAddFilesTest_V2.py
index 3a614906d754483382f0926da2d4272fc9a1043f..edec299b7308638723910e6ec8e6bc89e889d11c 100644
--- a/Testing/SystemTests/tests/analysis/SANS2DMultiPeriodAddFilesTest_V2.py
+++ b/Testing/SystemTests/tests/analysis/SANS2DMultiPeriodAddFilesTest_V2.py
@@ -1,5 +1,6 @@
-#pylint: disable=no-init
+#pylint: disable=no-init
 
+from __future__ import (absolute_import, division, print_function)
 from __future__ import (absolute_import, division, print_function)
 import stresstesting
 import os
diff --git a/Testing/SystemTests/tests/analysis/SANSMoveTest.py b/Testing/SystemTests/tests/analysis/SANSMoveTest.py
index 13ef1cb85da06e6b905326b4de1bd839753e8441..0592d97700c9bb57c2e99460ee394179144af7f3 100644
--- a/Testing/SystemTests/tests/analysis/SANSMoveTest.py
+++ b/Testing/SystemTests/tests/analysis/SANSMoveTest.py
@@ -58,6 +58,10 @@ class SANSMoveFactoryTest(unittest.TestCase):
         mover_type = SANSMoveLARMOROldStyle
         self._do_test(file_name, mover_type)
 
+    def test_that_ZOOM_strategy_is_selected(self):
+        # TODO when test data becomes available
+        pass
+
 
 class SANSMoveTest(unittest.TestCase):
     @staticmethod
@@ -341,6 +345,10 @@ class SANSMoveTest(unittest.TestCase):
         # Act + Assert for setting to zero position for all
         self.check_that_sets_to_zero(workspace, move_alg, state.move, comp_name=None)
 
+    def test_that_ZOOM_can_be_moved(self):
+        # TODO when test data becomes available
+        pass
+
     def test_that_missing_beam_centre_is_taken_from_move_state(self):
         # Arrange
         file_name = "SANS2D00028784"
diff --git a/Testing/SystemTests/tests/analysis/SEQUOIAreduction.py b/Testing/SystemTests/tests/analysis/SEQUOIAreduction.py
index 9938da56bcda3ddf1c565b48f7f18dccbcebf5d5..618f003fc05dfa93f506970000857be8342ce171 100644
--- a/Testing/SystemTests/tests/analysis/SEQUOIAreduction.py
+++ b/Testing/SystemTests/tests/analysis/SEQUOIAreduction.py
@@ -3,6 +3,7 @@
 Test the SNS inelatic reduction scripts.
 """
 
+from __future__ import (absolute_import, division, print_function)
 import stresstesting
 import os
 import shutil
@@ -68,19 +69,19 @@ class DirectInelaticSNSTest(stresstesting.MantidStressTest):
                 ang_list.append(ang)
         # file with grouping information
         f = open(os.path.join(self.customDataDir,"group.map"),'w')
-        print >>f,len(ang_list)
+        print(len(ang_list), file=f)
         for i in range(len(ang_list)):
-            print >>f,i
-            print >>f,len(detIDlist[i])
+            print(i, file=f)
+            print(len(detIDlist[i]), file=f)
             mystring=str(detIDlist[i]).strip(']').strip('[')
             mystring=mystring.replace(',','')
-            print >>f,mystring
+            print(mystring, file=f)
         f.close()
         # par file
         f = open(os.path.join(self.customDataDir,"group.par"),'w')
-        print >>f,len(ang_list)
+        print(len(ang_list), file=f)
         for angi in ang_list:
-            print >>f,5.5,angi,0.0,1.0,1.0,1
+            print(5.5,angi,0.0,1.0,1.0,1, file=f)
         f.close()
         return [ang_list,detIDlist]
 
@@ -244,7 +245,7 @@ class DirectInelaticSNSTest(stresstesting.MantidStressTest):
         #find the nxspe filename: it should be only one, but the name might depend on the rounding of phi
         nxspelist=glob.glob(os.path.join(self.customDataDir,'*.nxspe'))
         if len(nxspelist)>1 or len(nxspelist) == 0:
-            print "Error: Expected single nxspe file in %s. Found %d" % (self.customDataDir, len(nxspelist))
+            print("Error: Expected single nxspe file in %s. Found %d" % (self.customDataDir, len(nxspelist)))
             return False
 
         # Name encodes rotation
diff --git a/Testing/SystemTests/tests/analysis/SNSConvertToMDTest.py b/Testing/SystemTests/tests/analysis/SNSConvertToMDTest.py
index f34b6f17ad29501f830393ff7c6ce085f27c6730..1e5e546227b39ec0d91b10d75064b30d76e45376 100644
--- a/Testing/SystemTests/tests/analysis/SNSConvertToMDTest.py
+++ b/Testing/SystemTests/tests/analysis/SNSConvertToMDTest.py
@@ -1,4 +1,5 @@
 #pylint: disable=invalid-name,no-init
+from __future__ import (absolute_import, division, print_function)
 import stresstesting
 from mantid.simpleapi import *
 
@@ -98,8 +99,8 @@ def validateMD(result,reference,tol=1.e-5,class_name='dummy',mismatchName=None):
 
     checker.execute()
     if checker.getPropertyValue("Equals") != "1":
-        print " Workspaces do not match, result: ",checker.getPropertyValue("Result")
-        print " Test {0} fails".format(class_name)
+        print(" Workspaces do not match, result: ",checker.getPropertyValue("Result"))
+        print(" Test {0} fails".format(class_name))
         if mismatchName:
             targetFilename = class_name+mismatchName+'-mismatch.nxs'
         else:
diff --git a/Testing/SystemTests/tests/analysis/SXDAnalysis.py b/Testing/SystemTests/tests/analysis/SXDAnalysis.py
index b4ef6ec64c25b58d33d7ed33ae56fe2e78356774..c44058a458df6ec4159eab516e1476633e0ca8c3 100644
--- a/Testing/SystemTests/tests/analysis/SXDAnalysis.py
+++ b/Testing/SystemTests/tests/analysis/SXDAnalysis.py
@@ -1,4 +1,5 @@
 #pylint: disable=no-init,invalid-name
+from __future__ import (absolute_import, division, print_function)
 import stresstesting
 from mantid.simpleapi import *
 
@@ -19,7 +20,7 @@ class SXDAnalysis(stresstesting.MantidStressTest):
         QLab = ConvertToDiffractionMDWorkspace(InputWorkspace=ws, OutputDimensions='Q (lab frame)',
                                                SplitThreshold=50, LorentzCorrection='1',MaxRecursionDepth='13',
                                                Extents='-15,15,-15,15,-15,15',OneEventPerBin='0')
-        print " ConvertToMD runs for: ",clock()-start,' sec'
+        print(" ConvertToMD runs for: ",clock()-start,' sec')
 
         #  NaCl has a relatively small unit cell, so the distance between peaks is relatively large.  Setting the PeakDistanceThreshold
         #  higher avoids finding high count regions on the sides of strong peaks as separate peaks.
diff --git a/Testing/SystemTests/tests/analysis/SortHKLTest.py b/Testing/SystemTests/tests/analysis/SortHKLTest.py
index 1791db2de5d615bd92e6e73c2eee4322e2f47724..31618635e17605442fd5c7eaa82794f4b55dc03d 100644
--- a/Testing/SystemTests/tests/analysis/SortHKLTest.py
+++ b/Testing/SystemTests/tests/analysis/SortHKLTest.py
@@ -1,8 +1,10 @@
 # pylint: disable=no-init,attribute-defined-outside-init
+from __future__ import (absolute_import, division, print_function)
 import stresstesting
 import json
 from mantid.simpleapi import *
 from mantid.geometry import PointGroupFactory
+from six import iteritems
 
 
 class HKLStatisticsTestMixin(object):
@@ -35,7 +37,7 @@ class HKLStatisticsTestMixin(object):
             ub_parameters.update(
                 dict(
                     [(str(x), y if isinstance(y, float) else str(y))
-                     for x, y in raw_ub_parameters.iteritems()]
+                     for x, y in iteritems(raw_ub_parameters)]
                 ))
 
         return ub_parameters
@@ -69,7 +71,7 @@ class HKLStatisticsTestMixin(object):
         keys = lines[0].split()
         values = [float(x) for x in lines[2].split()[2:]]
 
-        overall_statistics = dict(zip(keys, values))
+        overall_statistics = dict(list(zip(keys, values)))
 
         completentess = float(lines[3].split()[-1].replace('%', ''))
         overall_statistics['Completeness'] = completentess
@@ -121,9 +123,9 @@ class SortHKLTest(HKLStatisticsTestMixin, stresstesting.MantidStressTest):
         return statistics.row(0), sorted_hkls
 
     def _compare_statistics(self, statistics, reference_statistics):
-        self.assertEquals(round(statistics['Multiplicity'], 1), round(reference_statistics['<N>'], 1))
-        self.assertEquals(round(statistics['Rpim'], 2), round(100.0 * reference_statistics['Rm'], 2))
-        self.assertEquals(statistics['No. of Unique Reflections'], int(reference_statistics['Nunique']))
+        self.assertEqual(round(statistics['Multiplicity'], 1), round(reference_statistics['<N>'], 1))
+        self.assertEqual(round(statistics['Rpim'], 2), round(100.0 * reference_statistics['Rm'], 2))
+        self.assertEqual(statistics['No. of Unique Reflections'], int(reference_statistics['Nunique']))
         self.assertDelta(round(statistics['Data Completeness'], 1), round(reference_statistics['Completeness'], 1),
                          0.5)
 
@@ -141,9 +143,9 @@ class SortHKLTest(HKLStatisticsTestMixin, stresstesting.MantidStressTest):
                 unique_map[unique].append(peak)
 
         # pylint: disable=unused-variable
-        for unique_hkl, equivalents in unique_map.iteritems():
+        for unique_hkl, equivalents in iteritems(unique_map):
             if len(equivalents) > 1:
                 reference_peak = equivalents[0]
                 for peak in equivalents[1:]:
-                    self.assertEquals(peak.getIntensity(), reference_peak.getIntensity())
-                    self.assertEquals(peak.getSigmaIntensity(), reference_peak.getSigmaIntensity())
+                    self.assertEqual(peak.getIntensity(), reference_peak.getIntensity())
+                    self.assertEqual(peak.getSigmaIntensity(), reference_peak.getSigmaIntensity())
diff --git a/Testing/SystemTests/tests/analysis/SpaceGroupFactoryTest.py b/Testing/SystemTests/tests/analysis/SpaceGroupFactoryTest.py
index 76887caca0c4bdfd6ef7c490668aafdfe2d2e155..b988bfdb59c8e2a035d1a4d273ddb8da22def432 100644
--- a/Testing/SystemTests/tests/analysis/SpaceGroupFactoryTest.py
+++ b/Testing/SystemTests/tests/analysis/SpaceGroupFactoryTest.py
@@ -1,4 +1,5 @@
 # pylint: disable=no-init
+from __future__ import (absolute_import, division, print_function)
 import stresstesting
 import re
 from mantid.simpleapi import *
@@ -81,7 +82,7 @@ class SpaceGroupFactoryTest(stresstesting.MantidStressTest):
             if matchedSeparator is not None:
                 currentGroup = matchedSeparator.group(1)
 
-                print currentGroup
+                print(currentGroup)
 
                 spaceGroups[currentGroup] = set()
             else:
diff --git a/Testing/SystemTests/tests/analysis/SpaceGroupReflectionConditionsTest.py b/Testing/SystemTests/tests/analysis/SpaceGroupReflectionConditionsTest.py
index 1003b139ec020e87fb911cb79822ab7e08276ca6..5deddf31ff2a3e040310140261d70582c277bda8 100644
--- a/Testing/SystemTests/tests/analysis/SpaceGroupReflectionConditionsTest.py
+++ b/Testing/SystemTests/tests/analysis/SpaceGroupReflectionConditionsTest.py
@@ -1,7 +1,9 @@
 # pylint: disable=no-init,invalid-name
+from __future__ import (absolute_import, division, print_function)
 import stresstesting
 from mantid.simpleapi import *
 from mantid.geometry import *
+from six import iteritems
 
 
 class SpaceGroupReflectionConditionsTest(stresstesting.MantidStressTest):
@@ -18,7 +20,7 @@ class SpaceGroupReflectionConditionsTest(stresstesting.MantidStressTest):
     def runTest(self):
         sgTestDict = self.generateReflectionLists()
 
-        for sgName, hkls in sgTestDict.iteritems():
+        for sgName, hkls in iteritems(sgTestDict):
             sg = SpaceGroupFactory.createSpaceGroup(sgName)
 
             for hkl in hkls:
@@ -47,6 +49,6 @@ class SpaceGroupReflectionConditionsTest(stresstesting.MantidStressTest):
                 hkls = [[int(m) for m in x.split()] for x in reflectionsWs.column(0)]
                 sgDict[sg] = hkls
             except ValueError:
-                print sg
+                print(sg)
 
         return sgDict
diff --git a/Testing/SystemTests/tests/analysis/SpaceGroupUnitCellTest.py b/Testing/SystemTests/tests/analysis/SpaceGroupUnitCellTest.py
index 9eef21ac44ebf98a316fa04e54314c17f8f0f869..911809824454810d1b299c8b3cf92ef9455ff568 100644
--- a/Testing/SystemTests/tests/analysis/SpaceGroupUnitCellTest.py
+++ b/Testing/SystemTests/tests/analysis/SpaceGroupUnitCellTest.py
@@ -1,6 +1,8 @@
 # pylint: disable=no-init,invalid-name
+from __future__ import (absolute_import, division, print_function)
 import stresstesting
 from mantid.geometry import *
+from six import iteritems
 
 
 class SpaceGroupUnitCellTest(stresstesting.MantidStressTest):
@@ -32,7 +34,7 @@ class SpaceGroupUnitCellTest(stresstesting.MantidStressTest):
                 self._check_spacegroup(sg, monoclinic_c_cells, monoclinic_c_compatiblity[lattice_system])
 
     def _check_spacegroup(self, sg, cells, compatible_metrics):
-        for system, cell in cells.iteritems():
+        for system, cell in iteritems(cells):
             is_allowed = sg.isAllowedUnitCell(cell)
             should_be_allowed = system in compatible_metrics
 
@@ -56,7 +58,7 @@ class SpaceGroupUnitCellTest(stresstesting.MantidStressTest):
         # This map specifies which metrics are compatible. A cell with cubic metric is for example compatible
         # with triclinic symmetry, but the opposite is not true.
         return {
-            PointGroup.LatticeSystem.Triclinic: cells.keys(),
+            PointGroup.LatticeSystem.Triclinic: list(cells.keys()),
             PointGroup.LatticeSystem.Monoclinic: [PointGroup.LatticeSystem.Monoclinic,
                                                   PointGroup.LatticeSystem.Orthorhombic,
                                                   PointGroup.LatticeSystem.Tetragonal,
diff --git a/Testing/SystemTests/tests/analysis/SphinxWarnings.py b/Testing/SystemTests/tests/analysis/SphinxWarnings.py
index b31e535a9cb43930336aed6f56678d4a55cbf4b8..1f2e55cacdd78accf132f2f880a8b84ea2979518 100644
--- a/Testing/SystemTests/tests/analysis/SphinxWarnings.py
+++ b/Testing/SystemTests/tests/analysis/SphinxWarnings.py
@@ -4,9 +4,11 @@ Some of the sphinx warnings come from the C++ code, from the properties of the a
 This test tries to detect the most common such errors.
 It also detects if a new category is created (i.e. someone uses Utilities instead of Utility)
 """
+from __future__ import (absolute_import, division, print_function)
 import stresstesting
 import mantid
 import re
+from six import iteritems
 
 
 class SphinxWarnings(stresstesting.MantidStressTest):
@@ -80,7 +82,7 @@ class SphinxWarnings(stresstesting.MantidStressTest):
 
     def runTest(self):
         algs = mantid.AlgorithmFactory.getRegisteredAlgorithms(True)
-        for (name, versions) in algs.iteritems():
+        for (name, versions) in iteritems(algs):
             for version in versions:
                 if mantid.api.DeprecatedAlgorithmChecker(name,version).isDeprecated()=='':
                     # get an instance
@@ -106,7 +108,7 @@ class SphinxWarnings(stresstesting.MantidStressTest):
 
     def validate(self):
         if self.errorMessage!="":
-            print "Found the following errors:\n",self.errorMessage
+            print("Found the following errors:\n",self.errorMessage)
             return False
 
         return True
diff --git a/Testing/SystemTests/tests/analysis/SurfLoadingTest.py b/Testing/SystemTests/tests/analysis/SurfLoadingTest.py
index f30fbc8275483922bac1351a9d4354243939c65c..6ebd641b0f57ee279b59dcb7a98a696d21a3dd63 100644
--- a/Testing/SystemTests/tests/analysis/SurfLoadingTest.py
+++ b/Testing/SystemTests/tests/analysis/SurfLoadingTest.py
@@ -1,4 +1,5 @@
 #pylint: disable=no-init
+from __future__ import (absolute_import, division, print_function)
 from LoadAndCheckBase import *
 
 
diff --git a/Testing/SystemTests/tests/analysis/TOPAZPeakFinding.py b/Testing/SystemTests/tests/analysis/TOPAZPeakFinding.py
index 7e69865f5d4c41d16832fc84cf1b62a1ee7c55f9..73cdf6b3df952b6a063df7190da90a0347319ca4 100644
--- a/Testing/SystemTests/tests/analysis/TOPAZPeakFinding.py
+++ b/Testing/SystemTests/tests/analysis/TOPAZPeakFinding.py
@@ -4,6 +4,7 @@ System test that loads TOPAZ single-crystal data,
 converts to Q space, finds peaks and indexes
 them.
 """
+from __future__ import (absolute_import, division, print_function)
 import stresstesting
 import numpy
 from mantid.simpleapi import *
@@ -91,7 +92,7 @@ class TOPAZPeakFinding(stresstesting.MantidStressTest):
         newUB = numpy.array(mtd["topaz_3132"].sample().getOrientedLattice().getUB())
         # UB Matrices are not necessarily the same, some of the H,K and/or L sign can be reversed
         diff = abs(newUB) - abs(originalUB) < 0.001
-        for c in xrange(3):
+        for c in range(3):
             # This compares each column, allowing old == new OR old == -new
             if not numpy.all(diff[:,c]) :
                 raise Exception("More than 0.001 difference between UB matrices: Q (lab frame):\n"
diff --git a/Testing/SystemTests/tests/analysis/ValidateFacilitiesFile.py b/Testing/SystemTests/tests/analysis/ValidateFacilitiesFile.py
index 9220c37a17b9e78f06f3eaba1c67637dd3b5d47e..0164a32b2b770a20c08151151e68b43870054459 100644
--- a/Testing/SystemTests/tests/analysis/ValidateFacilitiesFile.py
+++ b/Testing/SystemTests/tests/analysis/ValidateFacilitiesFile.py
@@ -1,4 +1,5 @@
 #pylint: disable=no-init,invalid-name
+from __future__ import (absolute_import, division, print_function)
 from mantid import config
 import os
 import stresstesting
@@ -26,18 +27,18 @@ class ValidateFacilitiesFile(stresstesting.MantidStressTest):
         # run the tests
         failed = []
         try:
-            print "----------------------------------------"
-            print "Validating Facilities.xml"
+            print("----------------------------------------")
+            print("Validating Facilities.xml")
             pyxsval.parseAndValidateXmlInput(filename, xsdFile=xsdFile, validateSchema=0)
-        except Exception, e:
-            print "VALIDATION OF Facilities.xml FAILED WITH ERROR:"
-            print e
+        except Exception as e:
+            print("VALIDATION OF Facilities.xml FAILED WITH ERROR:")
+            print(e)
             failed.append(filename)
 
         # final say on whether or not it 'worked'
-        print "----------------------------------------"
+        print("----------------------------------------")
         if len(failed) != 0:
-            print "SUMMARY OF FAILED FILES"
+            print("SUMMARY OF FAILED FILES")
             raise RuntimeError("Failed Validation of Facilities.xml")
         else:
-            print "Succesfully Validated Facilities.xml"
+            print("Succesfully Validated Facilities.xml")
diff --git a/Testing/SystemTests/tests/analysis/ValidateGroupingFiles.py b/Testing/SystemTests/tests/analysis/ValidateGroupingFiles.py
index 70de8fc3845747d75296ee1a9d81e8bf47399f0a..6f6259b260a7e4d36c45e9b344a09fac0505a13d 100644
--- a/Testing/SystemTests/tests/analysis/ValidateGroupingFiles.py
+++ b/Testing/SystemTests/tests/analysis/ValidateGroupingFiles.py
@@ -1,4 +1,5 @@
 #pylint: disable=no-init
+from __future__ import (absolute_import, division, print_function)
 from mantid import config
 import os
 import stresstesting
@@ -22,7 +23,7 @@ class ValidateGroupingFiles(stresstesting.MantidStressTest):
         # get a list of directories to look in
         direc = config['instrumentDefinition.directory']
         direc =  os.path.join(direc,'Grouping')
-        print "Looking for Grouping files in: %s" % direc
+        print("Looking for Grouping files in: %s" % direc)
         cwd = os.getcwd()
         os.chdir(direc)
         myFiles = glob.glob("*Grouping*.xml")
@@ -43,21 +44,21 @@ class ValidateGroupingFiles(stresstesting.MantidStressTest):
         failed = []
         for filename in files:
             try:
-                print "----------------------------------------"
-                print "Validating '%s'" % filename
+                print("----------------------------------------")
+                print("Validating '%s'" % filename)
                 pyxsval.parseAndValidateXmlInput(filename, xsdFile=self.xsdFile, validateSchema=0)
-            except Exception, err:
-                print "VALIDATION OF '%s' FAILED WITH ERROR:" % filename
-                print err
+            except Exception as err:
+                print("VALIDATION OF '%s' FAILED WITH ERROR:" % filename)
+                print(err)
                 failed.append(filename)
 
         # final say on whether or not it 'worked'
-        print "----------------------------------------"
+        print("----------------------------------------")
         if len(failed) != 0:
-            print "SUMMARY OF FAILED FILES"
+            print("SUMMARY OF FAILED FILES")
             for filename in failed:
-                print filename
+                print(filename)
             raise RuntimeError("Failed Validation for %d of %d files"
                                % (len(failed), len(files)))
         else:
-            print "Succesfully Validated %d files" % len(files)
+            print("Succesfully Validated %d files" % len(files))
diff --git a/Testing/SystemTests/tests/analysis/ValidateInstrumentDefinitionFiles.py b/Testing/SystemTests/tests/analysis/ValidateInstrumentDefinitionFiles.py
index ba4704aa4338846255cebc41ac66990c184132f0..eca88a957be63904f3a04cc63cc93a29556277da 100644
--- a/Testing/SystemTests/tests/analysis/ValidateInstrumentDefinitionFiles.py
+++ b/Testing/SystemTests/tests/analysis/ValidateInstrumentDefinitionFiles.py
@@ -1,5 +1,6 @@
 #pylint: disable=invalid-name
 #pylint: disable=no-init
+from __future__ import (absolute_import, division, print_function)
 from mantid import config
 import os
 import stresstesting
@@ -26,7 +27,7 @@ class ValidateInstrumentDefinitionFiles(stresstesting.MantidStressTest):
     def __getDataFileList__(self):
         # get a list of directories to look in
         direc = config['instrumentDefinition.directory']
-        print "Looking for instrument definition files in: %s" % direc
+        print("Looking for instrument definition files in: %s" % direc)
         cwd = os.getcwd()
         os.chdir(direc)
         myFiles = glob.glob("*Definition*.xml")
@@ -78,24 +79,24 @@ class ValidateInstrumentDefinitionFiles(stresstesting.MantidStressTest):
         failed = []
         for filename in files:
             try:
-                print "----------------------------------------"
-                print "Validating '%s'" % filename
+                print("----------------------------------------")
+                print("Validating '%s'" % filename)
                 parseAndValidateXmlInputForceReadFile(filename, xsdFile=self.xsdFile)
-            except Exception, e:
-                print "VALIDATION OF '%s' FAILED WITH ERROR:" % filename
-                print e
+            except Exception as e:
+                print("VALIDATION OF '%s' FAILED WITH ERROR:" % filename)
+                print(e)
                 failed.append(filename)
 
         # final say on whether or not it 'worked'
-        print "----------------------------------------"
+        print("----------------------------------------")
         if len(failed) != 0:
-            print "SUMMARY OF FAILED FILES"
+            print("SUMMARY OF FAILED FILES")
             for filename in failed:
-                print filename
+                print(filename)
             raise RuntimeError("Failed Validation for %d of %d files"
                                % (len(failed), len(files)))
         else:
-            print "Succesfully Validated %d files" % len(files)
+            print("Succesfully Validated %d files" % len(files))
 
 if __name__ == '__main__':
 
diff --git a/Testing/SystemTests/tests/analysis/ValidateParameterFiles.py b/Testing/SystemTests/tests/analysis/ValidateParameterFiles.py
index 084e52746e735fcc744290a1ea074c6d4bbcccb3..d2d0060d4506b5d6b3526cfa834fd7bd9c1480e0 100644
--- a/Testing/SystemTests/tests/analysis/ValidateParameterFiles.py
+++ b/Testing/SystemTests/tests/analysis/ValidateParameterFiles.py
@@ -1,4 +1,5 @@
 #pylint: disable=no-init,invalid-name
+from __future__ import (absolute_import, division, print_function)
 from mantid import config
 import os
 import stresstesting
@@ -22,7 +23,7 @@ class ValidateParameterFiles(stresstesting.MantidStressTest):
     def __getDataFileList__(self):
         # get a list of directories to look in
         direc = config['instrumentDefinition.directory']
-        print "Looking for instrument definition files in: %s" % direc
+        print("Looking for instrument definition files in: %s" % direc)
         cwd = os.getcwd()
         os.chdir(direc)
         myFiles = glob.glob("*Parameters*.xml")
@@ -36,7 +37,7 @@ class ValidateParameterFiles(stresstesting.MantidStressTest):
         """Main entry point for the test suite"""
         from minixsv import pyxsval # noqa
         direc = config['instrumentDefinition.directory']
-        print direc
+        print(direc)
         self.xsdFile =  os.path.join(direc,'Schema/ParameterFile/1.0/','ParameterFileSchema.xsd')
         files = self.__getDataFileList__()
 
@@ -44,24 +45,24 @@ class ValidateParameterFiles(stresstesting.MantidStressTest):
         failed = []
         for filename in files:
             try:
-                print "----------------------------------------"
-                print "Validating '%s'" % filename
+                print("----------------------------------------")
+                print("Validating '%s'" % filename)
                 pyxsval.parseAndValidateXmlInput(filename, xsdFile=self.xsdFile, validateSchema=0)
-            except Exception, e:
-                print "VALIDATION OF '%s' FAILED WITH ERROR:" % filename
-                print e
+            except Exception as e:
+                print("VALIDATION OF '%s' FAILED WITH ERROR:" % filename)
+                print(e)
                 failed.append(filename)
 
         # final say on whether or not it 'worked'
-        print "----------------------------------------"
+        print("----------------------------------------")
         if len(failed) != 0:
-            print "SUMMARY OF FAILED FILES"
+            print("SUMMARY OF FAILED FILES")
             for filename in failed:
-                print filename
+                print(filename)
             raise RuntimeError("Failed Validation for %d of %d files"
                                % (len(failed), len(files)))
         else:
-            print "Succesfully Validated %d files" % len(files)
+            print("Succesfully Validated %d files" % len(files))
 
 if __name__ == '__main__':
     valid = ValidateParameterFiles()
diff --git a/Testing/SystemTests/tests/analysis/VesuvioCorrectionsTest.py b/Testing/SystemTests/tests/analysis/VesuvioCorrectionsTest.py
index 56bd3a6e61ffc1360e813417f45ae79d180bb679..daf0f22b7739e62ff29c2546c7b88f74e73ad108 100644
--- a/Testing/SystemTests/tests/analysis/VesuvioCorrectionsTest.py
+++ b/Testing/SystemTests/tests/analysis/VesuvioCorrectionsTest.py
@@ -6,7 +6,7 @@ Unit test for Vesuvio corrections steps
 Assumes that mantid can be imported and the data paths
 are configured to find the Vesuvio data
 """
-
+from __future__ import (absolute_import, division, print_function)
 import stresstesting
 import numpy as np
 import platform
@@ -15,6 +15,7 @@ import platform
 from mantid.api import *
 import mantid.simpleapi as ms
 from mantid import *
+from six import iteritems
 
 #====================================Helper Functions=======================================
 
@@ -57,7 +58,7 @@ def _create_algorithm(**kwargs):
     alg.setProperty("CorrectionWorkspaces", "__Correction")
     alg.setProperty("CorrectedWorkspaces", "__Corrected")
     alg.setProperty("LinearFitResult", "__LinearFit")
-    for key, value in kwargs.iteritems():
+    for key, value in iteritems(kwargs):
         alg.setProperty(key, value)
     return alg
 
diff --git a/Testing/SystemTests/tests/analysis/WishCalibrate.py b/Testing/SystemTests/tests/analysis/WishCalibrate.py
index 2ae2fb2e584ab27f34b744106013c4033b579f0b..bbafc219e0c8c19ee17a43166656ee7088787da3 100644
--- a/Testing/SystemTests/tests/analysis/WishCalibrate.py
+++ b/Testing/SystemTests/tests/analysis/WishCalibrate.py
@@ -1,3 +1,4 @@
+from __future__ import (absolute_import, division, print_function)
 import filecmp
 import numpy as np
 import os
diff --git a/Testing/SystemTests/tests/analysis/WishMasking.py b/Testing/SystemTests/tests/analysis/WishMasking.py
index 59bd853d66371bfc28cab183bcf9017fa35d2b0f..6b0707231e1929e5db183b1b9c29b638365ba355 100644
--- a/Testing/SystemTests/tests/analysis/WishMasking.py
+++ b/Testing/SystemTests/tests/analysis/WishMasking.py
@@ -4,6 +4,7 @@ Tests masking functionality specific to WISH. Working masking behaviour is criti
 - Email Pascal Manuel @ ISIS if things break here and let him know how his scripts may need to be modified.
 """
 
+from __future__ import (absolute_import, division, print_function)
 import stresstesting
 import os
 from mantid.simpleapi import *
@@ -44,7 +45,7 @@ class WishMasking(stresstesting.MantidStressTest):
             self.assertTrue(mask_boundary_inside == expected_masking_identifier)
             self.assertTrue(mask_boundary_outside == expected_not_masking_identifier)
         except LookupError:
-            print "Could not find the requested index"
+            print("Could not find the requested index")
             self.assertTrue(False)
         finally:
             cfile.close()
diff --git a/buildconfig/CMake/CppCheckSetup.cmake b/buildconfig/CMake/CppCheckSetup.cmake
index ec4bf0419583e932514ab7b9f0a94087dd397632..61a2fc2d268adc7acad8b09035802bdbb2dde48a 100644
--- a/buildconfig/CMake/CppCheckSetup.cmake
+++ b/buildconfig/CMake/CppCheckSetup.cmake
@@ -4,8 +4,7 @@ if ( CPPCHECK_EXECUTABLE )
   set ( CPPCHECK_SOURCE_DIRS
         Framework
         MantidPlot
-        MantidQt
-        Vates
+        qt
       )
 
   set ( CPPCHECK_USE_INCLUDE_DIRS OFF CACHE BOOL "Use specified include directories. WARNING: cppcheck will run significantly slower." )
@@ -28,17 +27,18 @@ if ( CPPCHECK_EXECUTABLE )
         Framework/TestHelpers/inc
         Framework/Crystal/inc
         Framework/Kernel/inc
-        Vates/VatesAPI/inc
-        Vates/VatesSimpleGui/ViewWidgets/inc
-        Vates/VatesSimpleGui/StandAloneExec/inc
-        Vates/VatesSimpleGui/QtWidgets/inc
-        MantidQt/MantidWidgets/inc
-        MantidQt/CustomDialogs/inc
-        MantidQt/DesignerPlugins/inc
-        MantidQt/CustomInterfaces/inc
-        MantidQt/API/inc
-        MantidQt/Factory/inc
-        MantidQt/SliceViewer/inc
+        qt/paraview_ext/VatesAPI/inc
+        qt/paraview_ext/VatesSimpleGui/ViewWidgets/inc
+        qt/paraview_ext/VatesSimpleGui/QtWidgets/inc
+        qt/widgets/common/inc
+        qt/widgets/factory/inc
+        qt/widgets/instrumentview/inc
+        qt/widgets/refdetectrview/inc
+        qt/widgets/sliceviewer/inc
+        qt/widgets/spectrumviewer/inc
+        qt/widgets/plugins/algorithm_dialogs/inc
+        qt/widgets/plugins/designer/inc
+        qt/scientific_interfaces
       )
 
   set ( CPPCHECK_EXCLUDES
@@ -61,6 +61,8 @@ if ( CPPCHECK_EXECUTABLE )
         MantidPlot/src/origin/OPJFile.cpp
         MantidPlot/src/zlib123/minigzip.c
         Framework/SINQ/src/PoldiPeakFit.cpp
+        qt/widgets/common/src/QtPropertyBrowser/
+        qt/widgets/common/inc/MantidQtWidgets/Common/QtPropertyBrowser/
       )
 
   # Header files to be ignored require different handling
diff --git a/buildconfig/CMake/GNUSetup.cmake b/buildconfig/CMake/GNUSetup.cmake
index 2606443aa4e527a21a32a445fb672a622b328dd9..eaecf99104b01d1d3903d5d256f5d269be63bad2 100644
--- a/buildconfig/CMake/GNUSetup.cmake
+++ b/buildconfig/CMake/GNUSetup.cmake
@@ -32,6 +32,8 @@ endif()
 
 # Global warning flags.
 set( GNUFLAGS "-Wall -Wextra -Wconversion -Winit-self -Wpointer-arith -Wcast-qual -Wcast-align -fno-common" )
+# C++-specific flags
+set( GNUFLAGS_CXX "-Woverloaded-virtual -fno-operator-names")
 # Disable some warnings about deprecated headers and type conversions that
 # we can't do anything about
 # -Wno-deprecated: Do not warn about use of deprecated headers.
@@ -43,7 +45,7 @@ set( GNUFLAGS "${GNUFLAGS} -Wno-deprecated -Wno-write-strings -Wno-unused-result
 if ( CMAKE_COMPILER_IS_GNUCXX )
   set (GNUFLAGS "${GNUFLAGS} -Wpedantic")
   if (NOT (GCC_COMPILER_VERSION VERSION_LESS "5.1"))
-    set(GNUFLAGS "${GNUFLAGS} -Wsuggest-override")
+    set(GNUFLAGS_CXX "${GNUFLAGS_CXX} -Wsuggest-override")
   endif()
   if (NOT (GCC_COMPILER_VERSION VERSION_LESS "7.1"))
     # Consider enabling once [[fallthrough]] is available on all platforms.
@@ -74,7 +76,7 @@ if(WITH_UBSAN)
   if ( CMAKE_COMPILER_IS_GNUCXX AND GCC_COMPILER_VERSION VERSION_LESS "5.1.0")
     set( UBSAN_NO_RECOVER "")
   endif()
-  # vptr check is generating a lot of false positives, hiding other more serious warnings.  
+  # vptr check is generating a lot of false positives, hiding other more serious warnings.
   set(SAN_FLAGS "-fno-omit-frame-pointer -fno-common -fsanitize=undefined -fno-sanitize=vptr ${UBSAN_NO_RECOVER}")
   add_compile_options(-fno-omit-frame-pointer -fno-common -fsanitize=undefined -fno-sanitize=vptr ${UBSAN_NO_RECOVER})
   set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${SAN_FLAGS}" )
@@ -84,8 +86,7 @@ endif()
 
 # Set the options for gcc and g++
 set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${GNUFLAGS}" )
-# -Wno-overloaded-virtual is down here because it's not applicable to the C_FLAGS
-set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GNUFLAGS} -Woverloaded-virtual -fno-operator-names" )
+set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GNUFLAGS} ${GNUFLAGS_CXX}" )
 
 set(CMAKE_CXX_STANDARD 14)
 set(CMAKE_CXX_STANDARD_REQUIRED 11)
diff --git a/buildconfig/Jenkins/check_for_changes b/buildconfig/Jenkins/check_for_changes
index c003fbf583442e0d184315c9229997d4c59bdf81..f46e26b59c1d6c09069e7f36cef989e77e8639ef 100755
--- a/buildconfig/Jenkins/check_for_changes
+++ b/buildconfig/Jenkins/check_for_changes
@@ -40,7 +40,7 @@ case "$TYPE" in
 	# FOUND=1 iff changes are limited to docs or GUI only
 	# Find all changed files and grep for required type. -v inverts match so grep=0 means
 	# there are other changes besides this
-	if git diff --name-only ${BRANCH_TIP} ${BRANCH_BASE} -- | grep -q -E -v '^docs/|^MantidQt/|^MantidPlot/'; then
+	if git diff --name-only ${BRANCH_TIP} ${BRANCH_BASE} -- | grep -q -E -v '^docs/|^qt/|^MantidPlot/'; then
 	    exit $FOUND
 	else
 	    exit $NOTFOUND
diff --git a/docs/source/algorithms/ConvolutionFitSequential-v1.rst b/docs/source/algorithms/ConvolutionFitSequential-v1.rst
index 321c9b65e93902e669b9638144acc6dde19f1b42..df1d4afc7319f0d50d05b22674bb44ce0d54fa03 100644
--- a/docs/source/algorithms/ConvolutionFitSequential-v1.rst
+++ b/docs/source/algorithms/ConvolutionFitSequential-v1.rst
@@ -27,42 +27,45 @@ Usage
 
 .. testcode:: ConvolutionFitSequentialExample
 
-  # Create a host workspace
+  from __future__ import print_function
+
+  # Load sample and resolution files
   sample = Load('irs26176_graphite002_red.nxs')
   resolution = Load('irs26173_graphite002_red.nxs')
 
   # Set up algorithm parameters
-  function = "name=LinearBackground,A0=0,A1=0,ties=(A0=0.000000,A1=0.0);(composite=Convolution,FixResolution=true,NumDeriv=true;name=Resolution,Workspace=__ConvFit_Resolution,WorkspaceIndex=0;((composite=ProductFunction,NumDeriv=false;name=Lorentzian,Amplitude=1,PeakCentre=0,FWHM=0.0175)))"
+  function = """name=LinearBackground,A0=0,A1=0,ties=(A0=0.000000,A1=0.0);
+  (composite=Convolution,FixResolution=true,NumDeriv=true;
+  name=Resolution,Workspace=resolution,WorkspaceIndex=0;
+  name=Lorentzian,Amplitude=1,PeakCentre=0,FWHM=0.0175)"""
   bgType = "Fixed Flat"
   startX = -0.547608
   endX = 0.543217
   specMin = 0
   specMax = sample.getNumberHistograms() - 1
-  convolve = True
+  convolve = True  # Convolve the fitted model components with the resolution
   minimizer = "Levenberg-Marquardt"
   maxIt = 500
-  
-  # Build resolution workspace (normally done by the Convfit tab when files load)
-  AppendSpectra(InputWorkspace1=resolution.name(), InputWorkspace2=resolution.name(), OutputWorkspace="__ConvFit_Resolution")
-  for i in range(1, sample.getNumberHistograms()):
-    AppendSpectra(InputWorkspace1="__ConvFit_Resolution", InputWorkspace2=resolution.name(), OutputWorkspace="__ConvFit_Resolution")  
-  
+
   # Run algorithm
-  result_ws = ConvolutionFitSequential(InputWorkspace=sample, Function=function ,BackgroundType=bgType, StartX=startX, EndX=endX, SpecMin=specMin, SpecMax=specMax, Convolve=convolve, Minimizer=minimizer, MaxIterations=maxIt)
+  result_ws = ConvolutionFitSequential(InputWorkspace=sample,
+      Function=function, PassWSIndexToFunction=True, BackgroundType=bgType,
+      StartX=startX, EndX=endX, SpecMin=specMin, SpecMax=specMax,
+      Convolve=convolve, Minimizer=minimizer, MaxIterations=maxIt)
   
-  print "Result has %i Spectra" %result_ws.getNumberHistograms()
+  print("Result has %i Spectra" %result_ws.getNumberHistograms())
   
-  print "Amplitude 0: %.3f" %(result_ws.readY(0)[0])
-  print "Amplitude 1: %.3f" %(result_ws.readY(0)[1])
-  print "Amplitude 2: %.3f" %(result_ws.readY(0)[2])
+  print("Amplitude 0: %.3f" %(result_ws.readY(0)[0]))
+  print("Amplitude 1: %.3f" %(result_ws.readY(0)[1]))
+  print("Amplitude 2: %.3f" %(result_ws.readY(0)[2]))
   
-  print "X axis at 0: %.5f" %(result_ws.readX(0)[0])
-  print "X axis at 1: %.5f" %(result_ws.readX(0)[1])
-  print "X axis at 2: %.5f" %(result_ws.readX(0)[2])
+  print("X axis at 0: %.5f" %(result_ws.readX(0)[0]))
+  print("X axis at 1: %.5f" %(result_ws.readX(0)[1]))
+  print("X axis at 2: %.5f" %(result_ws.readX(0)[2]))
   
-  print "Amplitude Err 0: %.5f" %(result_ws.readE(0)[0])
-  print "Amplitude Err 1: %.5f" %(result_ws.readE(0)[1])
-  print "Amplitude Err 2: %.5f" %(result_ws.readE(0)[2])
+  print("Amplitude Err 0: %.5f" %(result_ws.readE(0)[0]))
+  print("Amplitude Err 1: %.5f" %(result_ws.readE(0)[1]))
+  print("Amplitude Err 2: %.5f" %(result_ws.readE(0)[2]))
 
 Output:  
   
@@ -72,17 +75,17 @@ Output:
   Result has 2 Spectra
   
   Amplitude 0: 4.314
-  Amplitude 1: 4.179
-  Amplitude 2: 3.979
+  Amplitude 1: 4.213
+  Amplitude 2: 4.555
 
   X axis at 0: 0.52531
   X axis at 1: 0.72917
   X axis at 2: 0.92340
   
   Amplitude Err 0: 0.00460
-  Amplitude Err 1: 0.00464
-  Amplitude Err 2: 0.00504
-  
+  Amplitude Err 1: 0.00468
+  Amplitude Err 2: 0.00577
+
 .. categories::
 
 .. sourcelink::
diff --git a/docs/source/algorithms/MDNormSCD-v1.rst b/docs/source/algorithms/MDNormSCD-v1.rst
index 4883b5b22dbf8aa4406bbaec4345c9feb0a581db..c54e1efe10ca7662f4993ed4a7daedfda3e37720 100644
--- a/docs/source/algorithms/MDNormSCD-v1.rst
+++ b/docs/source/algorithms/MDNormSCD-v1.rst
@@ -14,6 +14,9 @@ The algorithm calculates a normalization MD workspace for single crystal diffrac
 Trajectories of each detector in reciprocal space are calculated, and the flux is integrated between intersections with each
 MDBox. A brief introduction to the multi-dimensional data normalization can be found :ref:`here <MDNorm>`.
 
+The algorithm :ref:`MDNormSCDPreprocessIncoherent
+<algm-MDNormSCDPreprocessIncoherent>` can be used to process Vanadium
+data for the Solid Angle and Flux workspaces.
 
 Usage
 -----
diff --git a/docs/source/algorithms/MDNormSCDPreprocessIncoherent-v1.rst b/docs/source/algorithms/MDNormSCDPreprocessIncoherent-v1.rst
new file mode 100644
index 0000000000000000000000000000000000000000..221ddcfbb61381e7774e830f049ac35f36515b93
--- /dev/null
+++ b/docs/source/algorithms/MDNormSCDPreprocessIncoherent-v1.rst
@@ -0,0 +1,86 @@
+.. algorithm::
+
+.. summary::
+
+.. alias::
+
+.. properties::
+
+Description
+-----------
+
+This algorithm preprocesses an incoherent scattering sample (usually
+Vanadium) for use with :ref:`MDNormSCD <algm-MDNormSCD>`. The input
+filename follows the syntax from :py:obj:`MultipleFileProperty
+<mantid.api.MultipleFileProperty>`. The resulting workspaces can be
+saved with :ref:`SaveNexus <algm-SaveNexus>`.
+
+Usage
+-----
+
+**Corelli example using multiple files with masking**
+
+.. code-block:: python
+
+   # Create a simple mask file
+   MaskFilename=mantid.config.getString("defaultsave.directory")+"MDNormSCDPreprocessIncoherent_mask.xml"
+   LoadEmptyInstrument(InstrumentName='CORELLI', OutputWorkspace='CORELLI')
+   # Missing banks
+   MaskBTP('CORELLI', Bank='1-6,29,30,62,63-68,91')
+   # End of tubes
+   MaskBTP('CORELLI', Pixel='1-15,242-256')
+   SaveMask('CORELLI', MaskFilename)
+
+   SA, Flux = MDNormSCDPreprocessIncoherent(Filename='CORELLI_28119-28123',
+                                            MomentumMin=2.5,
+                                            MomentumMax=10,
+                                            MaskFile=MaskFilename)
+
+Solid Angle instrument view:
+
+.. figure:: /images/MDNormSCDPreprocessIncoherent_SA.png
+
+Flux spectrum plot:
+
+.. figure:: /images/MDNormSCDPreprocessIncoherent_Flux.png
+
+**TOPAZ example with backgound subtraction, grouping, masking and Spherical Absorption Correction**
+
+.. code-block:: python
+
+   SA, Flux = MDNormSCDPreprocessIncoherent(Filename='TOPAZ_15670',
+                                            Background='TOPAZ_15671',
+                                            FilterByTofMin=500,
+                                            FilterByTofMax=16000,
+                                            MomentumMin=1.8,
+                                            MomentumMax=12.5,
+                                            GroupingFile='/SNS/TOPAZ/IPTS-15376/shared/calibration/TOPAZ_grouping_2016A.xml',
+                                            DetCal='/SNS/TOPAZ/IPTS-15376/shared/calibration/TOPAZ_2016A.DetCal',
+                                            MaskFile='/SNS/TOPAZ/IPTS-15376/shared/calibration/TOPAZ_masking_2016A.xml',
+                                            SphericalAbsorptionCorrection=True,
+                                            LinearScatteringCoef=0.367,
+                                            LinearAbsorptionCoef=0.366,
+                                            Radius=0.2)
+   print(SA.getNumberHistograms())
+   print(SA.blocksize())
+   print(Flux.getNumberHistograms())
+   print(Flux.blocksize())
+
+Output:
+
+.. code-block:: none
+
+   1507328
+   1
+   23
+   10000
+
+
+Related Algorithms
+------------------
+
+:ref:`MDNormSCD <algm-MDNormSCD>` uses the output of this algorithm
+
+.. categories::
+
+.. sourcelink::
diff --git a/docs/source/algorithms/SingleCrystalDiffuseReduction-v1.rst b/docs/source/algorithms/SingleCrystalDiffuseReduction-v1.rst
index 5111b18a3e70cf001a1d302ca8b41e99ed7f0cf9..9644ae6de49b9c9296fca7f8a4183b9bfedc8834 100644
--- a/docs/source/algorithms/SingleCrystalDiffuseReduction-v1.rst
+++ b/docs/source/algorithms/SingleCrystalDiffuseReduction-v1.rst
@@ -22,7 +22,9 @@ This workflow makes use of :ref:`ConvertToMD <algm-ConvertToMD>` and
 :ref:`MDNormSCD <algm-MDNormSCD>` so these should be reviewed to
 better understand all the options. An example of creating the Solid
 Angle and Flux workspaces are included in :ref:`MDNormSCD
-<algm-MDNormSCD>`.
+<algm-MDNormSCD>`. :ref:`MDNormSCDPreprocessIncoherent
+<algm-MDNormSCDPreprocessIncoherent>` can be used to process Vanadium
+data for the Solid Angle and Flux workspaces.
 
 The resulting workspaces can be saved and loaded with :ref:`SaveMD
 <algm-SaveMD>` and :ref:`LoadMD <algm-LoadMD>` respectively.
diff --git a/docs/source/algorithms/SplineInterpolation-v1.rst b/docs/source/algorithms/SplineInterpolation-v1.rst
index 42a6834fd9c5947404eed835621c0d704946170b..0eafdfb4828a9b03c3101619a7a1f49233bbb3c4 100644
--- a/docs/source/algorithms/SplineInterpolation-v1.rst
+++ b/docs/source/algorithms/SplineInterpolation-v1.rst
@@ -23,12 +23,18 @@ derivatives of each of the interpolated points as a side product.
 Setting the DerivOrder property to zero will force the algorithm to
 calculate no derivatives.
 
+For the points outside the x-axis range covered by the WorkspaceToInterpolate, flat extrapolation will be performed.
+
+The algorithm can also perform linear interpolation by enabling `Linear2Points` if the WorkspaceToInterpolate has only 2 bins.
+Only 1st order derivative can be computed in this case. X-axis of the workspace to match must be sorted in ascending order.
+
 For Histogram Workspaces
 ########################
 
 If the input workspace contains histograms, rather than data points,
 then SplineInterpolation will automatically convert the input to point
-data. The output returned with be in the same format as the input.
+data for interpolation. The original inputs however will not be modified.
+The output returned will be in the same format as the input.
 
 Histogram workspaces being interpolated will show a warning when the
 range of the data is equal to the size of the workspace to match, but
@@ -78,6 +84,30 @@ Usage
     #interpolate using the reference workspace and output a group workspace of derivatives for each spectrum
     interpolated_ws = SplineInterpolation(WorkspaceToMatch=spline_ws, WorkspaceToInterpolate=ws, DerivOrder=2, OutputWorkspaceDeriv='derivs')
 
+**Example - linear interpolation:**
+
+.. testcode:: ExSplineInterpolationLinear
+
+    iws = CreateSampleWorkspace(NumBanks = 1, XMin = 7, XMax = 29, BinWidth = 11)
+    mws = CreateSampleWorkspace(NumBanks = 1, XMin = 6, XMax = 30, BinWidth = 3)
+    ows = SplineInterpolation(WorkspaceToMatch = mws, WorkspaceToInterpolate = iws, Linear2Points = True, DerivOrder = 0)
+
+    import numpy
+
+    for y in numpy.nditer(ows.readY(0)):
+        print("%0.2f"% y)
+
+.. testoutput:: ExSplineInterpolationLinear
+
+    10.30
+    10.30
+    9.39
+    6.66
+    3.94
+    1.21
+    0.30
+    0.30
+
 .. categories::
 
 .. sourcelink::
diff --git a/docs/source/concepts/IndexProperty.rst b/docs/source/concepts/IndexProperty.rst
new file mode 100644
index 0000000000000000000000000000000000000000..d06729582d201f97cb12186a3e436e1a2032e176
--- /dev/null
+++ b/docs/source/concepts/IndexProperty.rst
@@ -0,0 +1,109 @@
+.. _IndexProperty:
+
+Index Property
+==============
+
+.. contents::
+  :local:
+
+Why IndexProperty?
+------------------
+
+In many cases, indices are captured from the user with the ``ArrayProperty<int>`` property type. However, this lacks a few key behaviours which
+a property collecting workspace index information should have. Firstly, there is no automatic validation of the indices with respect to
+the workspace itself. Therefore users could enter invalid input e.g negative numbers, or numbers outside of
+the range of spectra held by the workspace, unless bounded validators or used. Additionally, the ``ArrayProperty<int>`` 
+does not lend itself to a distributed method for accessing workspace data, this would require manual conversion 
+of global indices to local indices on each mpi rank. Finally, any conversion between "index types" i.e. conversion from
+spectrum numbers to workspace indices (also known as spectrum indices) must be managed by the algorithm developer. This style
+of development is very error prone, particularly in the MPI case, and could lead to inconsitencies across algorithms as
+each developer may have a different approach to addressing the aforementioned issues.
+
+The ``IndexProperty`` in Mantid provides a consistent interface for algorithms 
+which need to access a subset of the workspace spectra for processing.The ``IndexProperty`` facilitates 
+the retrieval of a set of workspace indices, called a ``SpectrumIndexSet``, once provided with a set of workspace indices or 
+spectrum numbers [#]_. Therefore algorithm developers do not need to perform any conversions manually.  In situations where data is 
+distributed across several clusters (distributed processing) [#]_, the underlying ``IndexInfo`` object, which is used to 
+obtain a ``SpectrumIndexSet``, hides these mpi-specific details by automatically selecting the correct indices for
+a specific mpi rank. Therefore access to the workspace data remains unchanged for developers.
+
+.. [#] Not specifying any indices/spectrum numbers results in the processing of the entire workspace. Or all indices on a given MPI rank.
+.. [#] See :ref:`AlgorithmMPISupport` for more information on MPI support.
+
+How to use the IndexProperty
+----------------------------
+
+Unlike other property types in Mantid, the ``IndexProperty`` is designed to be used in conjunction with other properties
+which define the workspace and the input type of the indices which represent
+the subset of the data. However, developers do not need to concern themselves
+with maintaining these properties on their own. There are few special methods in
+``Algorithm`` which handle this. Namely, ``Algorithm::declareWorkspaceInputProperties``,
+``Algorithm::setWorkspaceInputProperties`` and ``Algorithm::getWorkspaceAndIndices`` [#]_. 
+
+Property declaration is as shown below: 
+
+.. code-block:: cpp
+
+  //Declare property with default settings
+  // IndexType::WorkspaceIndex is default
+  declareWorkspaceInputProperties<MatrixWorkspace>("InputWorkspace");
+  
+  //Declare all arguments
+  declareWorkspaceInputProperties<MatrixWorkspace>("InputWorkspace", 
+    IndexType::SpectrumNum|IndexType::WorkspaceIndex, PropertyMode::Type::Mandatory, 
+    LockMode::Type::Lock, "This is an input workspace with associated index handling")
+
+Internally, a ``WorkspaceProperty`` is created along with an ``IndexTypeProperty`` for
+managing the workspace and the type of user-defined input index list respectively. Their names are
+automatically generated based on the property name in the declaration. 
+A toy example algorithm dialog in the GUI would have the following inputs defined:
+
+.. image:: ../images/IndexPropertyDialogExample.png
+   :height: 300px
+   :alt: Toy Example of an Algorithm Dialog using IndexProperty
+
+After properties have been set, client code can retrieve the values of interest from
+within the algorithm as follows:
+
+.. code-block:: cpp
+
+  //Declare workspace and index set
+  MatrixWorkspace_sptr inputWs;
+  SpectrumIndexSet indexSet;
+  
+  //Method returns a tuple of the workspace
+  //and index set simultaneously
+  std::tie(inputWs, indexSet) = 
+        getWorkspaceAndIndices<MatrixWorkspace>("InputWorkspace");
+        
+  for(auto index: indexSet){
+    auto &spec = inputWs->getSpectrum(index);
+    //do something with spectrum.
+  }
+
+For setting the property values, there are 4 valid options:
+
+.. code-block:: cpp
+
+   //Set Property with workspace_sptr and string of indices
+   setWorkspaceInputProperties<MatrixWorkspace, std::string>(
+      "InputWorkspace", ws, IndexType::WorkspaceIndex, "1:5")
+      
+   //Set Property with workspace name and string of indices
+   setWorkspaceInputProperties<MatrixWorkspace, std::string>(
+      "InputWorkspace", "ws", IndexType::WorkspaceIndex, "1:5")
+      
+   //Set Property with workspace_sptr and vector of indices
+   setWorkspaceInputProperties<MatrixWorkspace, std::vector<int>>(
+      "InputWorkspace", ws, IndexType::WorkspaceIndex, 
+       std::vector<int>{1, 2, 3, 4, 5})
+       
+   //Set Property with workspace name and vector of indices
+   setWorkspaceInputProperties<MatrixWorkspace, std::vector<int>>(
+      "InputWorkspace", "ws", IndexType::WorkspaceIndex, 
+       std::vector<int>{1, 2, 3, 4, 5})
+
+.. categories:: Concepts
+
+.. [#] It is important to note that any attempt to access the ``IndexProperty`` or the ``WorkspaceProperty`` in isolation will fail. Once defined using the ``Algorithm::declareWorkspaceInputProperties`` method, all access must be via the three methods mentioned above.
+
diff --git a/docs/source/concepts/ORNL_SANS_Reduction.rst b/docs/source/concepts/ORNL_SANS_Reduction.rst
index fc15b958a541e396e8ea5b9bec715ac4b01706fc..fd8107861b0c95add4ee50c49fb1d8cc30ffad05 100644
--- a/docs/source/concepts/ORNL_SANS_Reduction.rst
+++ b/docs/source/concepts/ORNL_SANS_Reduction.rst
@@ -10,7 +10,7 @@ Reduction for ORNL SANS
 This document explains how to use Mantid to perform reduction of ORNL SANS data.
 Information about the underlying Mantid algorithms involved can be found in the 
 :ref:`SANSReduction <algm-SANSReduction>` algorithm documentation.
-For HFIR reduction specefically, you can also see the :ref:`HFIRSANSReduction <algm-HFIRSANSReduction>` algorithm documentation.
+For HFIR reduction specifically, you can also see the :ref:`HFIRSANSReduction <algm-HFIRSANSReduction>` algorithm documentation.
 
 
 Contents
diff --git a/docs/source/fitfunctions/ProductFunction.rst b/docs/source/fitfunctions/ProductFunction.rst
index c35d4ca70f7b2f768cbbac3b464aeda9af1c0948..aac3d84f1aaa4bcf518986fc6b811b1b83e0a4ce 100644
--- a/docs/source/fitfunctions/ProductFunction.rst
+++ b/docs/source/fitfunctions/ProductFunction.rst
@@ -22,3 +22,4 @@ a ProductFunction can be a composite function itself.
 .. categories::
 
 .. sourcelink::
+     :cpp: Framework/CurveFitting/src/Functions/ProductFunction.cpp
diff --git a/docs/source/images/IndexPropertyDialogExample.png b/docs/source/images/IndexPropertyDialogExample.png
new file mode 100644
index 0000000000000000000000000000000000000000..04f2406b5648e331a3feb9fe938c5ce292bfee59
Binary files /dev/null and b/docs/source/images/IndexPropertyDialogExample.png differ
diff --git a/docs/source/images/LaNaF4_3D_Slices.png b/docs/source/images/LaNaF4_3D_Slices.png
new file mode 100644
index 0000000000000000000000000000000000000000..e93c43693840acef4c513be4534c080a01cad502
Binary files /dev/null and b/docs/source/images/LaNaF4_3D_Slices.png differ
diff --git a/docs/source/images/MDNormSCDPreprocessIncoherent_Flux.png b/docs/source/images/MDNormSCDPreprocessIncoherent_Flux.png
new file mode 100644
index 0000000000000000000000000000000000000000..18628df308a43d5a1d11df36ecb38293cee0ea2e
Binary files /dev/null and b/docs/source/images/MDNormSCDPreprocessIncoherent_Flux.png differ
diff --git a/docs/source/images/MDNormSCDPreprocessIncoherent_SA.png b/docs/source/images/MDNormSCDPreprocessIncoherent_SA.png
new file mode 100644
index 0000000000000000000000000000000000000000..70f71c2a3b0e65a9231b72ef6e790a754c1a3f5d
Binary files /dev/null and b/docs/source/images/MDNormSCDPreprocessIncoherent_SA.png differ
diff --git a/docs/source/release/v3.11.0/diffraction.rst b/docs/source/release/v3.11.0/diffraction.rst
index 602261078940566fa4c7e08558d6379ea9464cec..3bd30339ef17998c433e9410ed1cb45a874d428f 100644
--- a/docs/source/release/v3.11.0/diffraction.rst
+++ b/docs/source/release/v3.11.0/diffraction.rst
@@ -22,6 +22,7 @@ Powder Diffraction
 - :ref:`LoadILLDiffraction <algm-LoadILLDiffraction>` now supports loading D2B data with detector scans. The D2B IDF has been updated, as previously it contained some errors in the positions of the tubes and size of the pixels.
 - :ref:`AlignAndFocusPowder <algm-AlignAndFocusPowder>` now correctly supports overloading the grouping file in the presence of a masking workspace.
 - :ref:`PDCalibration <algm-PDCalibration>` has changed how it calculates constants from peak positions to use a simplex optimization rather than Gauss-Markov method.
+- The powder diffraction GUI has had numerous bugfixes and now has an option to override the detector grouping.
 
 
 Single Crystal Diffraction
@@ -30,6 +31,14 @@ Single Crystal Diffraction
 - New algorithm :ref:`SingleCrystalDiffuseReduction <algm-SingleCrystalDiffuseReduction>` which performs the most common reductions done on Corelli (and elsewhere) for single crystal diffuse scattering.
 - New algorithm :ref:`ConvertMultipleRunsToSingleCrystalMD <algm-ConvertMultipleRunsToSingleCrystalMD>` which loads, converts to single crystal MDWorkspace and combines a series of runs.
 - :ref:`FindPeaksMD <algm-FindPeaksMD>` has been modified to only add peaks to runs that contributed to that peak. This is a lot faster when multiple runs are in the same MDworkspace.
+- New algorithm :ref:`MDNormSCDPreprocessIncoherent <algm-MDNormSCDPreprocessIncoherent>` creates the Solid Angle and Flux workspace from Vanadium data for MDNormSCD
+
+
+Imaging
+-------
+
+- The IMAT IDF has been improved to more accurately represent the instrument.
+
 
 Full list of `diffraction <http://github.com/mantidproject/mantid/pulls?q=is%3Apr+milestone%3A%22Release+3.11%22+is%3Amerged+label%3A%22Component%3A+Diffraction%22>`_
 and
diff --git a/docs/source/release/v3.11.0/framework.rst b/docs/source/release/v3.11.0/framework.rst
index 2985f143ba62fb0a8e365a19a5367e358b02ee71..6e433f0aa60a0514e055953622babde9ef3b6bd8 100644
--- a/docs/source/release/v3.11.0/framework.rst
+++ b/docs/source/release/v3.11.0/framework.rst
@@ -9,6 +9,11 @@ Concepts
 --------
 - The reference frame in :ref:`IDF <InstrumentDefinitionFile>` can now be customized in terms of setting the axis defining the 2theta sign.
 
+Properties
+----------
+
+- The :ref:`IndexProperty` has been added to the list of property types.
+
 Algorithms
 ----------
 
@@ -25,14 +30,15 @@ Improved
 - :ref:`FilterEvents <algm-FilterEvents-v1>` now copies units for the logs in the filtered workspaces
 - :ref:`GroupDetectors <algm-GroupDetectors-v2>` now supports workspaces with detector scans.
 - :ref:`FindPeaksMD <algm-FindPeaksMD-v1>` allows now to normalize by the number of events. This can improve results for data that was originally based on histogram data which has been converted to event-mode.
-- :ref:`FindSXPeaks <algm-FindSXPeaks-v1>` now finds all peaks in each spectrum. It also allows for setting more fine-grained resolutions.
+- :ref:`FindSXPeaks <algm-FindSXPeaks-v1>` now finds all peaks in each spectrum. It also allows for setting more fine-grained resolutions and takes into account any goniometer set on the workspace.
+- :ref:`SimpleShapeMonteCarloAbsorption <algm-SimpleShapeMonteCarloAbsorption>` has been added to simplify sample environment inputs for MonteCarloAbsorption
 - :ref:`IntegreatePeaksMD <algm-IntegratePeaksMD-v2>` makes the culling of the top one percent of the background events optional.
 - :ref:`IntegrateEllipsoids <algm-IntegrateEllipsoids-v1>` has the culling of the top one percent of the background events now as an optional input.
 - :ref:`IntegrateEllipsoidsTwoStep <algm-IntegrateEllipsoidsTwoStep-v1>` has the culling of the top one percent of the background events now as an optional input.
 - :ref:`IntegreatePeaksMD <algm-IntegratePeaksMD-v2>` makes the culling of the top one percent of the background events optional.
 - :ref:`Load <algm-Load-v1>` now supports use of tilde in file paths in Python, for example Load(Filename="~/data/test.nxs", ...)
 - :ref:`LoadBBY <algm-LoadBBY-v1>` is now better at handling sample information.
-- :ref:`algm-MonteCarloAbsorption` now supports approximating the input instrument with a sparse grid of detectors enabling quick simulation of huge pixel arrays
+- :ref:`algm-MonteCarloAbsorption` now supports approximating the input instrument with a sparse grid of detectors enabling quick simulation of huge pixel arrays. Also, the NumberOfWavelengthPoints input property is now validated more rigorously.
 - :ref:`SaveGSS <algm-SaveGSS-v1>` now supports saving in the legacy GSAS ALT format. This is useful for older tools however the default format FXYE should be used whenever possible.
 - :ref:`SaveMDWorkspaceToVTK <algm-SaveMDWorkspaceToVTK-v1>` and :ref:`LoadVTK <algm-LoadVTK-v1>` algorithms are now accessible from python.
 - :ref:`SetUncertainties <algm-SetUncertainties-v1>` now provides a "custom" mode, which lets the user specify both an arbitrary error value whose occurences are to be replaced in the input workspace, as well as the value to replace it with.
@@ -66,6 +72,7 @@ New
 
 - :ref:`PrimStretchedExpFT <func-PrimStretchedExpFT>` Provides the Fourier Transform of the Symmetrized Stretched Exponential Function integrated over each energy bin. Use in place of :ref:`StretchedExpFT <func-StretchedExpFT>` for fitting sample data featuring relaxation times longer than the resolution of the instrument.
 - :ref:`GramCharlier <func-GramCharlier>` is a new fit function primarily for use in neutron compton scattering.
+- :ref:`SplineInterpolation <algm-SplineInterpolation>` is extended to support also linear interpolation, if only 2 points are given.
 
 Bug fixes
 #########
diff --git a/docs/source/release/v3.11.0/indirect_inelastic.rst b/docs/source/release/v3.11.0/indirect_inelastic.rst
index 74de82b3e1f41ee3883efabffc4c5edcc1b6b60f..21c38c7715b15dfe6c8476078cdd93fd3d53183f 100644
--- a/docs/source/release/v3.11.0/indirect_inelastic.rst
+++ b/docs/source/release/v3.11.0/indirect_inelastic.rst
@@ -13,24 +13,37 @@ Algorithms
 
 Bayes
 #####
-
 - Removed fit option from plot options drop-down menu.
 - :ref:`SimpleShapeMonteCarloAbsorption <algm-SimpleShapeMonteCarloAbsorption>` has been added to simplify sample environment inputs for MonteCarloAbsorption
 
 Data Analysis
 #############
-
 - Added 'ExtractMembers' property to ConvolutionFitSequential algorithm - this allows for extracting the members of the
   convolution fitting into their own workspaces.
 
+Elwin
+~~~~~
+
+Bugfixes
+--------
+- Save Result now writes to file the temperature-dependent elastic intensity normalized to the lowest temperature.
+
+ConvFit
+~~~~~~~
+
+Bugfixes
+--------
+- Correct treatment of the resolution function: convolve sample and resolution spectra with same momentum transfer.
+- Property to pass the workspace index added to :ref:`algm-ConvolutionFitSequential`.
+
 Jump Fit
 ~~~~~~~~
 
 Improvements
 ------------
+- Added a flag 'ms_enabled' (default: True) for enabling/disabling multiple scattering in vesuvio user scripts.
 - The *S(Q, W)* interface now automatically replaces NaN values with 0.
 - EISF is now generated when performing a Single Fit, with a delta function, in the ConvFit interface.
-
 - :ref:`FlatPlatePaalmanPingsCorrection <algm-FlatPlatePaalmanPingsCorrection>` now supports `Direct` and `Indirect` modes.
 
 Bugfixes
diff --git a/docs/source/release/v3.11.0/sans.rst b/docs/source/release/v3.11.0/sans.rst
index d3057f7a9ebc3625bc4b7c0d46e630f2d5e1f37a..cdcd6e4947a919860b66b08a427bca65a05aaafd 100644
--- a/docs/source/release/v3.11.0/sans.rst
+++ b/docs/source/release/v3.11.0/sans.rst
@@ -5,9 +5,17 @@ SANS Changes
 .. contents:: Table of Contents
    :local:
 
+Interfaces
+----------
+
+- SANS > ISIS SANS v2 experimental interface has become available. It has basic reduction functionalities and makes use of the new reduction backend.
+
+
 Bug Fixes
 ---------
 
+- Displaying the masked workspace in the mask tab now makes sure that the masks are displayed in a grey color.
+
 |
 
 `Full list of changes on github <http://github.com/mantidproject/mantid/pulls?q=is%3Apr+milestone%3A%22Release+3.11%22+is%3Amerged+label%3A%22Component%3A+SANS%22>`__
diff --git a/docs/source/release/v3.11.0/ui.rst b/docs/source/release/v3.11.0/ui.rst
index 1a6881176d6367fb5cde390127e7800fc1986fbf..2a8eb0ffef96847e0287792019145a7861eeb9e5 100644
--- a/docs/source/release/v3.11.0/ui.rst
+++ b/docs/source/release/v3.11.0/ui.rst
@@ -45,7 +45,7 @@ Custom Interfaces
 #################
 
 - General > Multi dataset fitting interface and the general fitting dock now display the status string returned by the `Fit` algorithm. If an error occured during fitting it will be reported in this string.
-
+- SANS > ISIS SANS v2 experimental interface has become available. It has basic reduction functionalities and makes use of the new reduction backend.
 
 Bugs Resolved
 -------------
@@ -55,10 +55,17 @@ SliceViewer Improvements
 
 - SliceViewer input of number of bins, thickness, and slice point now waits until the editing is finished to rebin or changing slice point instead of changing with each digit entered.
 
-VSI Improvments
----------------
+VSI Improvements
+----------------
 - ParaView has been updated to to `v5.4.0 <https://blog.kitware.com/paraview-5-4-0-release-notes/>`_.
 
+.. figure:: ../../images/LaNaF4_3D_Slices.png
+   :class: screenshot
+   :align: right
+
+- Multislice view uses a custom `representation <https://www.paraview.org/ParaView/index.php/Views_And_Representations>`_ to speed up slicing by taking advantage of the consistent bin 
+  sizes in a MDHistoWorkspace. Smooth interaction with typical data sizes (< 10 million cells) is now possible.
+
 |
 
 Full list of
diff --git a/instrument/Facilities.xml b/instrument/Facilities.xml
index 07f56a06d26007208e94d7bb4b7db8ed19c7a3c7..626db9ec6ac762edfe5ea0aa9eba2ce7b40ff876 100644
--- a/instrument/Facilities.xml
+++ b/instrument/Facilities.xml
@@ -807,7 +807,7 @@
       <connection name="fake" address="127.0.0.1:0" listener="FakeEventDataListener" />
     </livedata>
   </instrument>
-  
+
   <instrument name="ISIS_Kafka_Event">
     <technique>Test Listener</technique>
     <livedata>
@@ -815,6 +815,11 @@
     </livedata>
   </instrument>
 
+  <instrument name="ZOOM">
+    <technique>Small Angle Scattering</technique>
+    <zeropadding size="8"/>
+  </instrument>
+
 </facility>
 
 </facilities>
diff --git a/instrument/IMAT_Definition.xml b/instrument/IMAT_Definition.xml
index c91f4705ea83cbf6f282918cbbf9a37a8211d9d7..5085339def2f3cbd16d7d780639b91dac4f7b764 100644
--- a/instrument/IMAT_Definition.xml
+++ b/instrument/IMAT_Definition.xml
@@ -3,10 +3,10 @@
 see http://www.mantidproject.org/IDF -->
 <instrument xmlns="http://www.mantidproject.org/IDF/1.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-            xsi:schemaLocation="http://www.mantidproject.org/IDF/1.0 Schema/IDFSchema.xsd"
-            name="IMAT" valid-from ="2017-02-25 00:00:00"
-            valid-to ="2100-01-01 23:59:59"
-            last-modified="2017-03-03 22:00:00">
+            xsi:schemaLocation="http://www.mantidproject.org/IDF/1.0 http://schema.mantidproject.org/IDF/1.0/IDFSchema.xsd"
+            name="IMAT" valid-from="2017-02-24 23:59:59"
+            valid-to="2018-08-25 23:59:59"
+            last-modified="2017-08-01 18:46:01">
   <defaults>
     <length unit="meter"/>
     <angle unit="degree"/>
@@ -19,320 +19,139 @@ see http://www.mantidproject.org/IDF -->
     </reference-frame>
     <default-view axis-view="z"/>
   </defaults>
-
   <!-- BRIEF DESCRIPTION OF IMAT INSTRUMENT:
        IMAT (Imaging and Materials Science & Engineering)
-       This IDF is for the 2 prototype banks, each with 200 detectors.
-       
-       The sample is considered Origin (0.0, 0.0, 0.0).
-       The source is at location z = -56.0, because it is 56 meters away from the sample.
-
-       The way the instrument is built in the IDF is by:
-         - First we define the monitors, as distance FROM the sample, hence the negative
-         - Second we define both North and South bank, both of them being the same type object -> detector-bank.
-              This means we can reuse the definition of a detector-bank for both.
-              This also means that WE MUST rotate one of the banks otherwise they would face the same way.
-         - 
   -->
-<!-- First, the source, sample and monitors -->
-<component type="some source type">
-  <location z="-56.0" />
-</component>
-<component type="sample position">
-  <location x="0.0" y="0.0" z="0.0" />
-</component>
-<type name="some source type" is="Source">
-  <properties />
-</type>
-<type name="sample position" is="SamplePos">
-  <properties />
-</type>
 
-<!-- Monitor locations are approximate guesses for now! -->
+  <!-- LIST OF PHYSICAL COMPONENTS (which the instrument consists of) -->
 
-<!-- Monitors -->
-<component type="monitors" idlist="monitors">
-  <location />
-</component>
+  <!-- source and sample-position components -->
 
-
-<type name="monitors">
-  <component type="monitor-cylinder">
-     <!--Example, first monitor is at 11.6534 m from the source, in the direction 
-     towards the sample => z = 11.6534 - 56 = -44.3466 (from the sample, which is at z=0)-->
-
-    <!--11.6534 - 56 -->
-    <location z="-44.3466" name="monitor1a"/>  
-    <location z="-44.3466" name="monitor1b"/>
-
-    <!--19.8144 - 56 -->
-    <location z="-36.1856" name="monitor2a"/>  
-    <location z="-36.1856" name="monitor2b"/>
-    
-    <!--20.8944 - 56 -->
-    <location z="-35.1056" name="monitor3a"/>  
-    <location z="-35.1056" name="monitor3b"/>
-    
-    <!--46.1774 - 56 -->
-    <location z="-9.8226" name="monitor4a"/>  
-    <location z="-9.8226" name="monitor4b"/>
-    
-    <!--49.0 - 56 -->
-    <location z="-7" name="monitor5a"/>  
-    <location z="-7" name="monitor5b"/>
+  <component type="source">
+    <location z="-56.0"/>
   </component>
+  <type name="source" is="Source" />
 
-  <!-- 
-       Define the monitor shapes, they are not completely accurately defined,
-       because the shape is only used for visualisation.
-  -->
-  <component type="dummy-monitor">
-    <!--56 - 56-->
-    <location z="0.0" name="CalMon"/>   
-    <!--60 - 56-->
-    <location z="4.0" name="He_in"/>   
-    <location z="4.0" name="He_out"/>
-    <!--dummy monitor (off) -->
-    <location z="0"/>  
+  <component type="default-sample-holder">
+    <location />
   </component>
-</type>
-
-<!-- Shape of the monitors -->
-<type name="dummy-monitor" is="monitor">
-<!-- empty definition of dummy monitor -->
-</type>
-<type name="monitor-cylinder" is="monitor">
-  <properties>
-    Copied from monitor.dat:
-
-    name:: box
-    rank:: 2
-    dimensions:: 2 4
-    values:: -45.00  -2.00
-    45.00  -2.00
-    135.00  -2.00
-    225.00  -2.00
-  </properties>
-
-  <cylinder id="cylinder-shape">
-    <centre-of-bottom-base r="0.0" t="0.0" p="0.0" />
-    <axis x="0.0" y="0.0" z="1.0" />
-    <radius val="0.01" />
-    <height val="0.03" />
-  </cylinder>
-</type>
-
-<!-- Spectrum IDs for the monitors -->
-<idlist idname="monitors">
-  <id start="0" end="13" />
-</idlist>
 
-<!-- There are two banks, North and South. 
-     Each bank contains five modules, stacked vertically above each other. 
-     The modules are of identical design, but the modules are not quite symmetrical in the horizontal direction.
-     Accordingly, the modules in the South bank are installed upside down relative to those in the North bank.
-     This ensures that the range of two-theta angles is the same for both banks. -->
-<component name="NorthBank" type="detector-bank" idlist="NorthBank">
-  <!-- The North bank is on the left, as viewed from the neutron source looking towards the sample.
-       In the coordinate system of the bank, X axis points in direction of increasing two theta (to the
-	   left as viewed from the sample position), Y axis points upwards, and the Z axis faces away from gauge volume. -->
-  <location x="+1.915" y="0" z="0" rot="90" axis-x="0" axis-y="1" axis-z="0"/>
-</component>
+  <!-- Place detector components (including monitors) -->
 
-<component name="SouthBank" type="detector-bank" idlist="SouthBank">
-  <!-- The South bank is on the right, so rotate 90 degrees the other way this time -->
-  <location x="-1.915" y="0" z="0" rot="-90" axis-x="0" axis-y="1" axis-z="0">
-    <!-- However, this would mean that the X axis is pointing towards the low end of the two theta range.
-	     The detector pixels are not symmetrically distributed around the centre of the module, and this
-		 would make the pixel distribution back to front. So, we rotate the entire bank around the (new)
-		 Z-axis, turning it upside down. The pixel two theta values will be correct, but the order of the
-		 modules is therefore top-to-bottom for the South bank, even though they are defined below from
-		 bottom to top. The new Y axis will also point downwards. -->
-    <rot val="180" axis-x="0" axis-y="0" axis-z="1" />
-  </location>
-</component>
-
-<type name="detector-bank">
-  <properties />
-  <component type="detector-module">
-    <location  x="0" y="0" z="0" rot="0" axis-x="1" axis-y="0" axis-z="0"/>
+  <!-- Monitors -->
+  <component type="monitors" idlist="monitors">
+    <location />
   </component>
-</type>
 
-<type name="detector-module">
-  <!-- Z axis faces away from gauge volume, so that we can use 'facing'.
-       Note that all components created so far (both the banks and the modules within
-       the banks) are located at 0,0,0 (the sample position) but with different orientations. -->
-  <!-- The modules are divided internally into 9 blocks of 25 pixels each, giving 225 pixels.
-       The pixel at the lowest two-theta and the two pixels at the highest two-theta are not used,
-	   giving 240 active pixels over the width of the module. The is a small gap of about 2.2 mm
-	   between the blocks, although the design is specified in terms of a 3 mm pixel pitch within
-	   the block, and 3.2 degree two-theta offset between the centre of neighbouring blocks.
-	   The blocks, and the pixels within each block, are specified in order from the lowest to the
-	   highest two-theta -->
-  <component type="detector-block">
-    <!-- 
-        Currently (May 2017) the detectors that IMAT uses have 200 elements each,
-        structured in 2 rows, with 100 pixels each. We simulate that by defining 100 pixels 
-        below, and adding two of them in separate rows.
+<!--
+Place both banks. We fill along the X axis first (the rows).
+-->
+  <!-- This places a prototype bank with 200 elements on the right of the sample -->
+  <component type="prototype-bank" idstart="15" idfillbyfirst="x" idstep="1" idstepbyrow="100">
+  	<location x="+1.915" rot="-90" axis-x="0.0" axis-y="1.0" axis-z="0.0" name="North Bank"/>
+  </component>
 
-        In 2018 new detectors are expected, if they are the full ones they will have more
-        rows per bank than these ones currently.
-    -->
-    <location r="0" t="0" p="0"> <facing x="0.0" y="0.0" z="0.0"/> </location>
-    <location r="0" t="-0" p="0"> <facing x="0.0" y="0.0" z="0.0"/> </location>
+  <!-- This places a prototype bank with 200 elements on the left of the sample -->
+  <component type="prototype-bank" idstart="250" idfillbyfirst="x" idstep="1" idstepbyrow="100">
+  	<location x="-1.915" rot="-90" axis-x="0.0" axis-y="1.0" axis-z="0.0" name="South Bank"/>
   </component>
-</type>
 
-<!-- Pixels inside a single detector block -->
-<type name="detector-block">
+  <!-- A cuboid sample holder -->
+  <!-- <type name="default-sample-holder" is="SamplePos" /> -->
+  <type name="default-sample-holder" is="SamplePos">
+    <cuboid id="shape">
+      <left-front-bottom-point  x="0.02"  y="-0.02" z="0.0"  />
+      <left-front-top-point     x="0.02"  y="-0.02" z="0.001" />
+      <left-back-bottom-point   x="-0.02" y="-0.02" z="0.0"  />
+      <right-front-bottom-point x="0.02"  y="0.02"  z="0.0"  />
+    </cuboid>
+    <algebra val="shape" />
+  </type>
+
+  <!-- Matrix structure of the "200 elements" detector
+  We start off the Y axis (ystart) at 0.05 so that the centre of the detector bank intersects
+  the line in the instrument view. This means the sample would be directly in front of the middle
+  of the detector, which is the case in IMAT
+   -->
+  <type name="prototype-bank" is="RectangularDetector" type="pixel-200-elements"
+  xpixels="100" xstart="-0.2" xstep="+0.004"
+  ypixels="2" ystart="+0.05" ystep="-0.1" >
+  </type>
+
   <!--
-      Currently we have 100 pixels per row with a 0.004 gap between each detector pixel.
-      I am not sure if the number of pixels will change with the new detectors in 2018,
-      but I believe that it should be changed here
+    Prototype pixel types, we seem to need those or Mantid crashes while parsing.
+    Pixel shape of current detectors is 
+    100mm height: from y=-0.05 on the bottom to y=0.05 on the top
+    4mm width: the x=0.004
+    Depth is 0.001, if we set it to 0.0 Mantid will crash
   -->
-  <component type="detector-pixel">
-    <location x="0.196" y="0" z="0" name="pixel1" /> 
-    <location x="0.192" y="0" z="0" name="pixel2" /> 
-    <location x="0.188" y="0" z="0" name="pixel3" /> 
-    <location x="0.184" y="0" z="0" name="pixel4" /> 
-    <location x="0.18" y="0" z="0" name="pixel5" /> 
-    <location x="0.176" y="0" z="0" name="pixel6" /> 
-    <location x="0.172" y="0" z="0" name="pixel7" /> 
-    <location x="0.168" y="0" z="0" name="pixel8" /> 
-    <location x="0.164" y="0" z="0" name="pixel9" /> 
-    <location x="0.16" y="0" z="0" name="pixel10" /> 
-    <location x="0.156" y="0" z="0" name="pixel11" /> 
-    <location x="0.152" y="0" z="0" name="pixel12" /> 
-    <location x="0.148" y="0" z="0" name="pixel13" /> 
-    <location x="0.144" y="0" z="0" name="pixel14" /> 
-    <location x="0.14" y="0" z="0" name="pixel15" /> 
-    <location x="0.136" y="0" z="0" name="pixel16" /> 
-    <location x="0.132" y="0" z="0" name="pixel17" /> 
-    <location x="0.128" y="0" z="0" name="pixel18" /> 
-    <location x="0.124" y="0" z="0" name="pixel19" /> 
-    <location x="0.12" y="0" z="0" name="pixel20" /> 
-    <location x="0.116" y="0" z="0" name="pixel21" /> 
-    <location x="0.112" y="0" z="0" name="pixel22" /> 
-    <location x="0.108" y="0" z="0" name="pixel23" /> 
-    <location x="0.104" y="0" z="0" name="pixel24" /> 
-    <location x="0.1" y="0" z="0" name="pixel25" /> 
-    <location x="0.096" y="0" z="0" name="pixel26" /> 
-    <location x="0.092" y="0" z="0" name="pixel27" /> 
-    <location x="0.088" y="0" z="0" name="pixel28" /> 
-    <location x="0.084" y="0" z="0" name="pixel29" /> 
-    <location x="0.08" y="0" z="0" name="pixel30" /> 
-    <location x="0.076" y="0" z="0" name="pixel31" /> 
-    <location x="0.072" y="0" z="0" name="pixel32" /> 
-    <location x="0.068" y="0" z="0" name="pixel33" /> 
-    <location x="0.064" y="0" z="0" name="pixel34" /> 
-    <location x="0.06" y="0" z="0" name="pixel35" /> 
-    <location x="0.056" y="0" z="0" name="pixel36" /> 
-    <location x="0.052" y="0" z="0" name="pixel37" /> 
-    <location x="0.048" y="0" z="0" name="pixel38" /> 
-    <location x="0.044" y="0" z="0" name="pixel39" /> 
-    <location x="0.04" y="0" z="0" name="pixel40" /> 
-    <location x="0.036" y="0" z="0" name="pixel41" /> 
-    <location x="0.032" y="0" z="0" name="pixel42" /> 
-    <location x="0.028" y="0" z="0" name="pixel43" /> 
-    <location x="0.024" y="0" z="0" name="pixel44" /> 
-    <location x="0.02" y="0" z="0" name="pixel45" /> 
-    <location x="0.016" y="0" z="0" name="pixel46" /> 
-    <location x="0.012" y="0" z="0" name="pixel47" /> 
-    <location x="0.008" y="0" z="0" name="pixel48" /> 
-    <location x="0.004" y="0" z="0" name="pixel49" /> 
-    <location x="0.000" y="0" z="0" name="pixel50" /> 
-    <location x="-0.004" y="0" z="0" name="pixel51" /> 
-    <location x="-0.008" y="0" z="0" name="pixel52" /> 
-    <location x="-0.012" y="0" z="0" name="pixel53" /> 
-    <location x="-0.016" y="0" z="0" name="pixel54" /> 
-    <location x="-0.02" y="0" z="0" name="pixel55" /> 
-    <location x="-0.024" y="0" z="0" name="pixel56" /> 
-    <location x="-0.028" y="0" z="0" name="pixel57" /> 
-    <location x="-0.032" y="0" z="0" name="pixel58" /> 
-    <location x="-0.036" y="0" z="0" name="pixel59" /> 
-    <location x="-0.04" y="0" z="0" name="pixel60" /> 
-    <location x="-0.044" y="0" z="0" name="pixel61" /> 
-    <location x="-0.048" y="0" z="0" name="pixel62" /> 
-    <location x="-0.052" y="0" z="0" name="pixel63" /> 
-    <location x="-0.056" y="0" z="0" name="pixel64" /> 
-    <location x="-0.06" y="0" z="0" name="pixel65" /> 
-    <location x="-0.064" y="0" z="0" name="pixel66" /> 
-    <location x="-0.068" y="0" z="0" name="pixel67" /> 
-    <location x="-0.072" y="0" z="0" name="pixel68" /> 
-    <location x="-0.076" y="0" z="0" name="pixel69" /> 
-    <location x="-0.08" y="0" z="0" name="pixel70" /> 
-    <location x="-0.084" y="0" z="0" name="pixel71" /> 
-    <location x="-0.088" y="0" z="0" name="pixel72" /> 
-    <location x="-0.092" y="0" z="0" name="pixel73" /> 
-    <location x="-0.096" y="0" z="0" name="pixel74" /> 
-    <location x="-0.1" y="0" z="0" name="pixel75" /> 
-    <location x="-0.104" y="0" z="0" name="pixel76" /> 
-    <location x="-0.108" y="0" z="0" name="pixel77" /> 
-    <location x="-0.112" y="0" z="0" name="pixel78" /> 
-    <location x="-0.116" y="0" z="0" name="pixel79" /> 
-    <location x="-0.12" y="0" z="0" name="pixel80" /> 
-    <location x="-0.124" y="0" z="0" name="pixel81" /> 
-    <location x="-0.128" y="0" z="0" name="pixel82" /> 
-    <location x="-0.132" y="0" z="0" name="pixel83" /> 
-    <location x="-0.136" y="0" z="0" name="pixel84" /> 
-    <location x="-0.14" y="0" z="0" name="pixel85" /> 
-    <location x="-0.144" y="0" z="0" name="pixel86" /> 
-    <location x="-0.148" y="0" z="0" name="pixel87" /> 
-    <location x="-0.152" y="0" z="0" name="pixel88" /> 
-    <location x="-0.156" y="0" z="0" name="pixel89" /> 
-    <location x="-0.16" y="0" z="0" name="pixel90" /> 
-    <location x="-0.164" y="0" z="0" name="pixel91" /> 
-    <location x="-0.168" y="0" z="0" name="pixel92" /> 
-    <location x="-0.172" y="0" z="0" name="pixel93" /> 
-    <location x="-0.176" y="0" z="0" name="pixel94" /> 
-    <location x="-0.18" y="0" z="0" name="pixel95" /> 
-    <location x="-0.184" y="0" z="0" name="pixel96" /> 
-    <location x="-0.188" y="0" z="0" name="pixel97" /> 
-    <location x="-0.192" y="0" z="0" name="pixel98" /> 
-    <location x="-0.196" y="0" z="0" name="pixel99" /> 
-    <location x="-0.2" y="0" z="0" name="pixel100" /> 
-  </component>
-</type>
-
-<type name="detector-pixel" is="detector">
+  <!-- <type name="pixel-200-elements" is="detector">
+   <cuboid id="pixel-shape">
+     <left-front-bottom-point x="0.0" y="-0.05" z="0.0" />
+     <left-front-top-point   x="0.0" y="0.05" z="0.0" />
+     <right-front-bottom-point  x="0.004" y="-0.05" z="0.001" />
+   </cuboid>
+  <algebra val="pixel-shape"/>
+  </type> -->
+
+  <type name="pixel-200-elements" is="detector">
   <cuboid id="shape">
-    <left-front-bottom-point x="-0.0015" y="-0.092" z="0.0"  />
-    <left-front-top-point  x="-0.0015" y="0.092" z="0.0"  />
-    <left-back-bottom-point  x="-0.0015" y="-0.092" z="0.001"  />
-    <right-front-bottom-point  x="0.0015" y="-0.092" z="0.0"  />
+    <left-front-bottom-point x="-0.002" y="-0.05" z="0.0"  />
+    <left-front-top-point  x="-0.002" y="0.05" z="0.0"  />
+    <left-back-bottom-point  x="-0.002" y="-0.05" z="0.001"  />
+    <right-front-bottom-point  x="0.002" y="-0.05" z="0.0"  />
   </cuboid>
   <algebra val="shape" />
 </type>
 
-<!-- 
-    Here we define the spectra number for each detector. Each detector gets one spectra.
-    The current structure leaves spectra 13 and 14 empty, so they are excluded.
-    Excluded spectra:
-      - 13 and 14: left empty
-      - 215 to 249 are excluded
-      - 449 to the end are excluded
-
-    The current structure of the spectra is:
-        We have 2 banks with 2 rows, and 100 detectors per row
-        
-        This means we have 400 detectors in total.
-
-        15-214 is 200 detectors - the range is [15,214] (last index not excluded)
-        250-449 is 200 detectors - same for the range [250,449]
-
-        I have tried with 15-215, and 250-450, but Mantid fails to parse and the error
-        is that we have more spectra than detectors. The [15,214], [250,449] range works.
-
-    In the future we will still have 2 banks, but they will have more detector-blocks and maybe more pixels
-    inside each detector-blocks
-  -->
-<idlist idname="NorthBank">
-  <id start="15" end="214"/>
-</idlist>
-
-<idlist idname="SouthBank">
-  <id start="250" end="449"/>
-</idlist>
-
-</instrument>
+  <!-- DEFINITION OF MONITOR TYPES -->
+  <type name="monitors">
+    <component type="monitor-cylinder">
+      <!-- Example, first monitor is at 11.6534 m from the source, in the direction towards the sample => z = 11.6534 - 56 = -44.3466 (from the sample, which is at z=0)-->
+      <location z="-44.3466" name="monitor1a"/> <!-- 11.6534 - 56 -->
+      <location z="-44.3466" name="monitor1b"/>
+      <location z="-36.1856" name="monitor2a"/> <!-- 19.8144 - 56 -->
+      <location z="-36.1856" name="monitor2b"/>
+      <location z="-35.1056" name="monitor3a"/> <!-- 20.8944 - 56 -->
+      <location z="-35.1056" name="monitor3b"/>
+      <location z="-9.8226" name="monitor4a"/> <!-- 46.1774 - 56 -->
+      <location z="-9.8226" name="monitor4b"/>
+      <location z="-7" name="monitor5a"/> <!-- 49.0 - 56 -->
+      <location z="-7" name="monitor5b"/>
+      <location z="0.0" name="CalMon"/> <!-- 56 - 56 -->
+      <location z="4.0" name="He_in"/>  <!-- 60 - 56-->
+      <location z="4.0" name="He_out"/>
+	  <location z="0"/> <!-- dummy monitor (off) -->
+    </component>
+  </type>
+
+  <!-- shape for monitors, borrowed from GEM -->
+  <type name="monitor-cylinder" is="monitor">
+    <properties>
+      Copied from monitor.dat:
+
+      name:: box
+      rank:: 2
+      dimensions:: 2 4
+      values:: -45.00  -2.00
+      45.00  -2.00
+      135.00  -2.00
+      225.00  -2.00
+    </properties>
+
+    <cylinder id="cylinder-shape">
+      <centre-of-bottom-base r="0.0" t="0.0" p="0.0" />
+      <axis x="0.0" y="0.0" z="1.0" />
+      <radius val="0.01" />
+      <height val="0.03" />
+    </cylinder>
+  </type>
+
+  <!-- DETECTOR and MONITOR ID LISTS -->
+  <idlist idname="monitors">
+    <id start="0" end="13" />
+  </idlist>
+
+  <!-- do not use idlist for the rectangular detectors, they're ignored! -->
+
+</instrument>
\ No newline at end of file
diff --git a/instrument/IN16B_Parameters.xml b/instrument/IN16B_Parameters.xml
index 83f7b6390cfc4fb01cdcd0c5fb635d2b837ad40a..801ecb4ce407382991309ac6b76439a927fb5001 100644
--- a/instrument/IN16B_Parameters.xml
+++ b/instrument/IN16B_Parameters.xml
@@ -27,10 +27,10 @@
 <parameter name="sample_logs_warn_tolerances" type="string">
 </parameter>
 <parameter name="sample_logs_fail" type="string">
-    <value val="Doppler.mirror_sense, acquisition_mode, Doppler.velocity_profile, Doppler.maximum_delta_energy" />
+    <value val="Doppler.mirror_sense, acquisition_mode, Doppler.maximum_delta_energy" />
 </parameter>
 <parameter name="sample_logs_fail_tolerances" type="string">
-    <value val="0, 0, 0, 0.001" />
+    <value val="0, 0, 0.001" />
 </parameter>
 
 <!-- Reduction workflow parameters under this line -->
diff --git a/instrument/REF_M_Definition.xml b/instrument/REF_M_Definition.xml
index 0428e5728c833343f3d836c5e78007b1c7e1be45..88fed6001ea8a7f7408077c29fb4241e61f935dc 100644
--- a/instrument/REF_M_Definition.xml
+++ b/instrument/REF_M_Definition.xml
@@ -49,7 +49,11 @@
 
   <type name="DetectorArm">
     <component type="panel" idstart="0" idfillbyfirst="y">
-        <location name="detector1" x="0" y="0" z="2.5505"/>
+      <location name="detector1">
+        <parameter name="z">
+          <logfile eq="0.001*value" id="SampleDetDis"/>
+        </parameter>
+      </location>
     </component>
   </type>
   
diff --git a/instrument/ZOOM_Definition.xml b/instrument/ZOOM_Definition.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d130deaf75c0486249d755609063d83a81d0ea88
--- /dev/null
+++ b/instrument/ZOOM_Definition.xml
@@ -0,0 +1,379 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- For help on the notation used to specify an Instrument Definition File 
+     see http://www.mantidproject.org/IDF -->
+<instrument xmlns="http://www.mantidproject.org/IDF/1.0" 
+            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+            xsi:schemaLocation="http://www.mantidproject.org/IDF/1.0 http://schema.mantidproject.org/IDF/1.0/IDFSchema.xsd"
+ name="ZOOM" valid-from   ="2016-10-26 23:59:59"
+                          valid-to     ="2100-01-31 23:59:59"
+		          last-modified="2016-10-26 00:00:00">
+
+  <defaults>
+    <length unit="meter"/>
+    <angle unit="degree"/>  
+    <reference-frame>
+      <!-- The z-axis is set parallel to and in the direction of the beam. the 
+           y-axis points up and the coordinate system is right handed. -->
+      <along-beam axis="z"/>
+      <pointing-up axis="y"/>
+      <handedness val="right"/>
+    </reference-frame>
+    <default-view axis-view="z-"/>
+  </defaults>
+
+  
+  <!-- BRIEF DESCRIPTION OF ZOOM INSTRUMENT: 
+  
+      Data gathered by Diego Alba Venero from the ZOOM instrument drawings
+	  This is a hack from the SANS2D_Definition_Tubes.xml
+	  all this chagnes are from the SANS2D IDF
+      12/06/09 this version has X & Y coords detector swapped so orientation
+      is correct for temporary wiring table.
+      18/06/09 better distances for detectors and both at L2=4m, front at X=-1.1m
+      26/06/09 swap front & rear as names wrong, translate front in opposite direction
+	  21/07/09 remove the 150mm sideways shift (i.e. back to symmetrical detector coords)
+	  to simplify manipulations in Mantid and help allow for detector mapping not quite 
+	  as expected.
+	  01/02/10 very small change to pixel size 191*5.1=974.2=2*487.05 (was 487.4)
+	  - note have to swap x= and y= in Anders output list !
+      02/04/12 Put in 'no shape monitors' for possible in the future monitors
+      with ID 5-8
+	  04/02/14 start again with gas tube arrays
+	  14/03/14 correct the active tube length to 1041.4mm, zigzag offset 3mm 
+  -->
+  
+  
+  <!-- LIST OF PHYSICAL COMPONENTS (which the instrument consists of) -->
+  
+  <!-- source and sample-position components -->
+
+  <component type="source">
+    <location />
+  </component>
+  <type name="source" is="Source" />
+  
+  
+  <!-- This is the position of the centre of rotation of the sample stack out of the drawings. I think that it would be more interesting to 
+  have it at the position of the sample changer -->
+  <component type="some-sample-holder">
+    <location z="17.3635"/>
+  </component>
+  <type name="some-sample-holder" is="SamplePos" />
+  
+  
+  <!-- detector components (including monitors) -->
+  
+  <component type="monitors" idlist="monitors">
+    <location />
+  </component>
+  
+  <type name="monitors">
+    <component type="monitor-tbd">
+      <!-- better positions and shapes will be defined later -->
+      <location z="8.310" name="monitor1"/>
+      <location z="13.532" name="monitor2"/>
+    </component>
+    <component type="Moderator-Monitor3">
+      <!-- transmisssion detector, either in or out of beam -->
+      <location z="15.887" name="monitor3"/>
+    </component>
+    <component type="monitor-tbd">
+      <!-- better positions and shapes will be defined later -->
+      <location z="17.405" name="monitor4"/>
+    </component>
+	<component type="monitor-tbd">
+      <!-- better positions and shapes will be defined later, at the moment is defined to be 20mm in front of the detector  -->
+      <location z="20.77208" name="monitor5"/>
+    </component>        
+    
+    <!-- Putting in monitors, which are defined in raw/nexus
+         files, and have detector IDs, but currently not physically present 
+         on the instrument. Defined with no geometric shape, as they do not 
+         physically exist, and with a dummy position -->
+    <component type="no shape monitor">
+      <location z="0" name="placeholder monitor"/>
+      <location z="0" name="placeholder monitor"/>
+      <location z="0" name="placeholder monitor"/>
+      <location z="0" name="placeholder monitor"/>      
+	  <location z="0" name="placeholder monitor"/>   
+    </component>  
+    
+  </type>
+  
+  <type name="monitor-tbd" is="monitor">
+    <cylinder id="some-shape">
+      <centre-of-bottom-base r="0.0" t="0.0" p="0.0" />
+      <axis x="0.0" y="0.0" z="1.0" /> 
+      <radius val="0.01" />
+      <height val="0.03" />
+    </cylinder>   
+  </type>
+  
+  <type name="Moderator-Monitor3" is="monitor">
+    <percent-transparency val="99.9" />
+    <cuboid id="shape">
+      <left-front-bottom-point x="0.0125" y="-0.0125" z="0.0"  />
+      <left-front-top-point  x="0.0125" y="-0.0125" z="0.005"  />
+      <left-back-bottom-point  x="-0.0125" y="-0.0125" z="0.0"  />
+      <right-front-bottom-point  x="0.0125" y="0.0125" z="0.0"  />
+    </cuboid>
+    <algebra val="shape" />
+  </type>  
+
+  <type name="no shape monitor" is="monitor" />   
+
+<!-- default position is at 3.4113m from the sample, waiting for Mo. Probably is more reasonable to put it at 4m away fromt the position of the sample changer -->
+
+   <component type="detector-bank" idlist="RearDetector" name="rear-detector">
+     <location z="20.77408" />
+   </component>   
+
+    
+ <type name="detector-bank">
+ <!-- the horizontal tubes are spaced vertically at 8.1mm intervals, with left and right sets ~3mm displaced -->
+ <!-- DAV: I'm not very happy with this. Doesn't it mean that the tubes are 16.2 mm thick??????? -->
+ <component type="SANSLeftTube">
+    <locations y="-0.7776" y-end="0.7695" n-elements="96" name="left" />
+ </component>
+
+<component type="SANSRightTube">
+    <locations y="-0.7695" y-end="0.7776" n-elements="96" name="right" />
+</component>
+ </type>
+ 
+ <type name="SANSLeftTube" outline="yes">
+ <component type="pixel">
+   <locations x="-0.5192" x-end="0.5222" n-elements="512" />
+ </component>
+ </type>
+ 
+ <type name="SANSRightTube" outline="yes">
+ <component type="pixel">
+   <locations x="-0.5222" x-end="0.5192" n-elements="512" />
+ </component>
+ </type>
+ 
+ <!-- the length of one pixel is assumed 1041.4/512 = 2.033984375mm, the internal radius is less then given here, more like 7.8mm/2 -->
+   <type name="pixel" is="detector">
+    <cylinder id="cyl-approx">
+      <centre-of-bottom-base r="0.0" t="0.0" p="0.0" />
+      <axis x="1.0" y="0.0" z="0.0" />
+      <radius val="0.00405" />
+      <height val="   0.002033984375" />
+    </cylinder>
+    <algebra val="cyl-approx" />
+  </type>
+ 
+
+  <!-- Monitor & Detector ID Lists, note the "left" tubes are followed by the "right" tubes, 
+          in the same order as the y locations list, starting at the bottom 
+		  they are numbered dgttppp  where d=1 for rear, 2 for front
+		                                   g= 1 to 5 for boards/cables 
+										   tt= 0 to 23 for tube number on that board
+										   ppp=0 to 512 for pixels 
+		There are 5 boards of 24 tubes,each 1m long, for each detector.
+		note that the spectrum mapping will normally reduce the number of pixels to 256 or 128 
+		[note also that the wiring table inverts the raw 0 to 511 pixel numbers to 511 to 0 so we get the correct direction] -->
+
+  <idlist idname="monitors">
+    <id start="1" end="10" />  
+  </idlist>   
+  
+  <idlist idname="RearDetector">
+   <id start="	1122000	   "  end="	1122511	" />
+   <id start="	1120000	   "  end="	1120511	" />
+   <id start="	1118000	   "  end="	1118511	" />
+   <id start="	1116000	   "  end="	1116511	" />
+   <id start="	1114000	   "  end="	1114511	" />
+   <id start="	1112000	   "  end="	1112511	" />
+   <id start="	1110000	   "  end="	1110511	" />
+   <id start="	1108000	   "  end="	1108511	" />
+   <id start="	1106000	   "  end="	1106511	" />
+   <id start="	1104000	   "  end="	1104511	" />
+   <id start="	1102000	   "  end="	1102511	" />
+   <id start="	1100000	   "  end="	1100511	" />
+   <id start="	1222000	   "  end="	1222511	" />
+   <id start="	1220000	   "  end="	1220511	" />
+   <id start="	1218000	   "  end="	1218511	" />
+   <id start="	1216000	   "  end="	1216511	" />
+   <id start="	1214000	   "  end="	1214511	" />
+   <id start="	1212000	   "  end="	1212511	" />
+   <id start="	1210000	   "  end="	1210511	" />
+   <id start="	1208000	   "  end="	1208511	" />
+   <id start="	1206000	   "  end="	1206511	" />
+   <id start="	1204000	   "  end="	1204511	" />
+   <id start="	1202000	   "  end="	1202511	" />
+   <id start="	1200000	   "  end="	1200511	" />
+   <id start="	1322000	   "  end="	1322511	" />
+   <id start="	1320000	   "  end="	1320511	" />
+   <id start="	1318000	   "  end="	1318511	" />
+   <id start="	1316000	   "  end="	1316511	" />
+   <id start="	1314000	   "  end="	1314511	" />
+   <id start="	1312000	   "  end="	1312511	" />
+   <id start="	1310000	   "  end="	1310511	" />
+   <id start="	1308000	   "  end="	1308511	" />
+   <id start="	1306000	   "  end="	1306511	" />
+   <id start="	1304000	   "  end="	1304511	" />
+   <id start="	1302000	   "  end="	1302511	" />
+   <id start="	1300000	   "  end="	1300511	" />
+   <id start="	1422000	   "  end="	1422511	" />
+   <id start="	1420000	   "  end="	1420511	" />
+   <id start="	1418000	   "  end="	1418511	" />
+   <id start="	1416000	   "  end="	1416511	" />
+   <id start="	1414000	   "  end="	1414511	" />
+   <id start="	1412000	   "  end="	1412511	" />
+   <id start="	1410000	   "  end="	1410511	" />
+   <id start="	1408000	   "  end="	1408511	" />
+   <id start="	1406000	   "  end="	1406511	" />
+   <id start="	1404000	   "  end="	1404511	" />
+   <id start="	1402000	   "  end="	1402511	" />
+   <id start="	1400000	   "  end="	1400511	" />
+   <id start="	1522000	   "  end="	1522511	" />
+   <id start="	1520000	   "  end="	1520511	" />
+   <id start="	1518000	   "  end="	1518511	" />
+   <id start="	1516000	   "  end="	1516511	" />
+   <id start="	1514000	   "  end="	1514511	" />
+   <id start="	1512000	   "  end="	1512511	" />
+   <id start="	1510000	   "  end="	1510511	" />
+   <id start="	1508000	   "  end="	1508511	" />
+   <id start="	1506000	   "  end="	1506511	" />
+   <id start="	1504000	   "  end="	1504511	" />
+   <id start="	1502000	   "  end="	1502511	" />
+   <id start="	1500000	   "  end="	1500511	" />
+   <id start="	1622000	   "  end="	1622511	" />
+   <id start="	1620000	   "  end="	1620511	" />
+   <id start="	1618000	   "  end="	1618511	" />
+   <id start="	1616000	   "  end="	1616511	" />
+   <id start="	1614000	   "  end="	1614511	" />
+   <id start="	1612000	   "  end="	1612511	" />
+   <id start="	1610000	   "  end="	1610511	" />
+   <id start="	1608000	   "  end="	1608511	" />
+   <id start="	1606000	   "  end="	1606511	" />
+   <id start="	1604000	   "  end="	1604511	" />
+   <id start="	1602000	   "  end="	1602511	" />
+   <id start="	1600000	   "  end="	1600511	" />
+   <id start="	1722000	   "  end="	1722511	" />
+   <id start="	1720000	   "  end="	1720511	" />
+   <id start="	1718000	   "  end="	1718511	" />
+   <id start="	1716000	   "  end="	1716511	" />
+   <id start="	1714000	   "  end="	1714511	" />
+   <id start="	1712000	   "  end="	1712511	" />
+   <id start="	1710000	   "  end="	1710511	" />
+   <id start="	1708000	   "  end="	1708511	" />
+   <id start="	1706000	   "  end="	1706511	" />
+   <id start="	1704000	   "  end="	1704511	" />
+   <id start="	1702000	   "  end="	1702511	" />
+   <id start="	1700000	   "  end="	1700511	" />
+   <id start="	1822000	   "  end="	1822511	" />
+   <id start="	1820000	   "  end="	1820511	" />
+   <id start="	1818000	   "  end="	1818511	" />
+   <id start="	1816000	   "  end="	1816511	" />
+   <id start="	1814000	   "  end="	1814511	" />
+   <id start="	1812000	   "  end="	1812511	" />
+   <id start="	1810000	   "  end="	1810511	" />
+   <id start="	1808000	   "  end="	1808511	" />
+   <id start="	1806000	   "  end="	1806511	" />
+   <id start="	1804000	   "  end="	1804511	" />
+   <id start="	1802000	   "  end="	1802511	" />
+   <id start="	1800000	   "  end="	1800511	" />			
+				
+   <id start="	1123000	   "  end="	1123511	" />
+   <id start="	1121000	   "  end="	1121511	" />
+   <id start="	1119000	   "  end="	1119511	" />
+   <id start="	1117000	   "  end="	1117511	" />
+   <id start="	1115000	   "  end="	1115511	" />
+   <id start="	1113000	   "  end="	1113511	" />
+   <id start="	1111000	   "  end="	1111511	" />
+   <id start="	1109000	   "  end="	1109511	" />
+   <id start="	1107000	   "  end="	1107511	" />
+   <id start="	1105000	   "  end="	1105511	" />
+   <id start="	1103000	   "  end="	1103511	" />
+   <id start="	1101000	   "  end="	1101511	" />
+   <id start="	1223000	   "  end="	1223511	" />
+   <id start="	1221000	   "  end="	1221511	" />
+   <id start="	1219000	   "  end="	1219511	" />
+   <id start="	1217000	   "  end="	1217511	" />
+   <id start="	1215000	   "  end="	1215511	" />
+   <id start="	1213000	   "  end="	1213511	" />
+   <id start="	1211000	   "  end="	1211511	" />
+   <id start="	1209000	   "  end="	1209511	" />
+   <id start="	1207000	   "  end="	1207511	" />
+   <id start="	1205000	   "  end="	1205511	" />
+   <id start="	1203000	   "  end="	1203511	" />
+   <id start="	1201000	   "  end="	1201511	" />
+   <id start="	1323000	   "  end="	1323511	" />
+   <id start="	1321000	   "  end="	1321511	" />
+   <id start="	1319000	   "  end="	1319511	" />
+   <id start="	1317000	   "  end="	1317511	" />
+   <id start="	1315000	   "  end="	1315511	" />
+   <id start="	1313000	   "  end="	1313511	" />
+   <id start="	1311000	   "  end="	1311511	" />
+   <id start="	1309000	   "  end="	1309511	" />
+   <id start="	1307000	   "  end="	1307511	" />
+   <id start="	1305000	   "  end="	1305511	" />
+   <id start="	1303000	   "  end="	1303511	" />
+   <id start="	1301000	   "  end="	1301511	" />
+   <id start="	1423000	   "  end="	1423511	" />
+   <id start="	1421000	   "  end="	1421511	" />
+   <id start="	1419000	   "  end="	1419511	" />
+   <id start="	1417000	   "  end="	1417511	" />
+   <id start="	1415000	   "  end="	1415511	" />
+   <id start="	1413000	   "  end="	1413511	" />
+   <id start="	1411000	   "  end="	1411511	" />
+   <id start="	1409000	   "  end="	1409511	" />
+   <id start="	1407000	   "  end="	1407511	" />
+   <id start="	1405000	   "  end="	1405511	" />
+   <id start="	1403000	   "  end="	1403511	" />
+   <id start="	1401000	   "  end="	1401511	" />
+   <id start="	1523000	   "  end="	1523511	" />
+   <id start="	1521000	   "  end="	1521511	" />
+   <id start="	1519000	   "  end="	1519511	" />
+   <id start="	1517000	   "  end="	1517511	" />
+   <id start="	1515000	   "  end="	1515511	" />
+   <id start="	1513000	   "  end="	1513511	" />
+   <id start="	1511000	   "  end="	1511511	" />
+   <id start="	1509000	   "  end="	1509511	" />
+   <id start="	1507000	   "  end="	1507511	" />
+   <id start="	1505000	   "  end="	1505511	" />
+   <id start="	1503000	   "  end="	1503511	" />
+   <id start="	1501000	   "  end="	1501511	" />
+   <id start="	1623000	   "  end="	1623511	" />
+   <id start="	1621000	   "  end="	1621511	" />
+   <id start="	1619000	   "  end="	1619511	" />
+   <id start="	1617000	   "  end="	1617511	" />
+   <id start="	1615000	   "  end="	1615511	" />
+   <id start="	1613000	   "  end="	1613511	" />
+   <id start="	1611000	   "  end="	1611511	" />
+   <id start="	1609000	   "  end="	1609511	" />
+   <id start="	1607000	   "  end="	1607511	" />
+   <id start="	1605000	   "  end="	1605511	" />
+   <id start="	1603000	   "  end="	1603511	" />
+   <id start="	1601000	   "  end="	1601511	" />
+   <id start="	1723000	   "  end="	1723511	" />
+   <id start="	1721000	   "  end="	1721511	" />
+   <id start="	1719000	   "  end="	1719511	" />
+   <id start="	1717000	   "  end="	1717511	" />
+   <id start="	1715000	   "  end="	1715511	" />
+   <id start="	1713000	   "  end="	1713511	" />
+   <id start="	1711000	   "  end="	1711511	" />
+   <id start="	1709000	   "  end="	1709511	" />
+   <id start="	1707000	   "  end="	1707511	" />
+   <id start="	1705000	   "  end="	1705511	" />
+   <id start="	1703000	   "  end="	1703511	" />
+   <id start="	1701000	   "  end="	1701511	" />
+   <id start="	1823000	   "  end="	1823511	" />
+   <id start="	1821000	   "  end="	1821511	" />
+   <id start="	1819000	   "  end="	1819511	" />
+   <id start="	1817000	   "  end="	1817511	" />
+   <id start="	1815000	   "  end="	1815511	" />
+   <id start="	1813000	   "  end="	1813511	" />
+   <id start="	1811000	   "  end="	1811511	" />
+   <id start="	1809000	   "  end="	1809511	" />
+   <id start="	1807000	   "  end="	1807511	" />
+   <id start="	1805000	   "  end="	1805511	" />
+   <id start="	1803000	   "  end="	1803511	" />
+   <id start="	1801000	   "  end="	1801511	" />
+  
+  </idlist>
+  
+</instrument>
diff --git a/instrument/ZOOM_Parameters.xml b/instrument/ZOOM_Parameters.xml
new file mode 100644
index 0000000000000000000000000000000000000000..2162ceb733aa367d3e570a2af47e5f1cb936de9f
--- /dev/null
+++ b/instrument/ZOOM_Parameters.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<parameter-file instrument = "ZOOM" valid-from = "2017-06-01 23:59:59" valid-to = "2100-01-31 23:59:59">
+
+<component-link name = "ZOOM">
+
+<parameter name="default-incident-monitor-spectrum">
+  <value val="3"/>
+</parameter>
+
+<parameter name="default-transmission-monitor-spectrum">
+  <value val="4"/>
+</parameter>
+
+<parameter name="low-angle-detector-name" type="string">
+  <value val="rear-detector"/>
+</parameter>
+
+<parameter name="low-angle-detector-short-name" type="string">
+  <value val="rear"/>
+</parameter>
+
+<parameter name="low-angle-detector-num-columns">
+<!--I don't know what is this-->
+  <value val="512"/>
+</parameter>
+
+<parameter name="low-angle-detector-num-rows">
+<!--I don't know what is this-->
+  <value val="120"/>
+</parameter>
+
+<parameter name="centre-finder-step-size">
+<!-- this is the initial step for the beam centre finder in metres -->
+  <value val="0.005"/>
+</parameter>
+
+<parameter name="collimation-length-correction">
+<!-- This is a correction length in meter for the L1 value to obtain the default collimation length-->
+  <value val="17.2765"/>
+</parameter>
+
+<parameter name="special-default-collimation-length-method" type="string">
+<!-- This method determines how the default collimation is to be calculated-->
+  <value val="guide"/>
+</parameter>
+
+<parameter name="guide-collimation-length-increment">
+<!-- This is a correction length increment in meter-->
+  <value val="2.0"/>
+</parameter>
+
+<parameter name="guide-cutoff">
+<!-- This is the cutoff value for the guides-->
+  <value val="130.0"/>
+</parameter>
+
+<parameter name="number-of-guides">
+<!-- This number of guides-->
+  <value val="5"/>
+</parameter>
+
+</component-link>
+
+</parameter-file>
diff --git a/qt/paraview_ext/PVPlugins/CMakeLists.txt b/qt/paraview_ext/PVPlugins/CMakeLists.txt
index 6a7aad5ff7752f33d19cd4db194cc3865ba480fe..ba41b35757e06aef9a592aaf4610385ab9949847 100644
--- a/qt/paraview_ext/PVPlugins/CMakeLists.txt
+++ b/qt/paraview_ext/PVPlugins/CMakeLists.txt
@@ -41,5 +41,6 @@ endif()
 
 add_subdirectory( Filters )
 add_subdirectory( Readers )
+add_subdirectory( Representations )
 add_subdirectory( Sources )
 add_subdirectory( Widgets )
diff --git a/qt/paraview_ext/PVPlugins/Representations/AlignedCutter.cxx b/qt/paraview_ext/PVPlugins/Representations/AlignedCutter.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..040c4ad4e8b66775562910685a2dad197d2384a8
--- /dev/null
+++ b/qt/paraview_ext/PVPlugins/Representations/AlignedCutter.cxx
@@ -0,0 +1,279 @@
+/*=========================================================================
+
+  Program:   Visualization Toolkit
+  Module:    AlignedCutter.cxx
+
+  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
+  All rights reserved.
+  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
+
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+     PURPOSE.  See the above copyright notice for more information.
+
+=========================================================================*/
+#include "AlignedCutter.h"
+
+#include "vtkCellData.h"
+#include "vtkDataSet.h"
+#include "vtkDoubleArray.h"
+#include "vtkIdList.h"
+#include "vtkImplicitFunction.h"
+#include "vtkInformation.h"
+#include "vtkInformationVector.h"
+#include "vtkNew.h"
+#include "vtkPolyData.h"
+#include "vtkRectilinearGrid.h"
+#include "vtkStructuredGrid.h"
+
+vtkStandardNewMacro(AlignedCutter);
+
+AlignedCutter::AlignedCutter(vtkImplicitFunction *cf) : vtkCutter(cf) {}
+
+//----------------------------------------------------------------------------
+AlignedCutter::~AlignedCutter() = default;
+
+//----------------------------------------------------------------------------
+void AlignedCutter::AlignedStructuredGridCutter(vtkDataSet *dataSetInput,
+                                                vtkPolyData *thisOutput) {
+  vtkStructuredGrid *input = vtkStructuredGrid::SafeDownCast(dataSetInput);
+  vtkNew<vtkPolyData> output;
+  output->Allocate();
+  vtkIdType numPts = input->GetNumberOfPoints();
+
+  if (numPts < 1)
+  {
+    return;
+  }
+
+  vtkNew<vtkDoubleArray> cutScalars;
+  cutScalars->SetName("cutScalars");
+    
+  vtkDataArray* dataArrayInput = input->GetPoints()->GetData();
+  
+  int dims[3], celldims[3];
+  input->GetDimensions(dims);
+  vtkIdType d01 = vtkIdType{dims[0]} * dims[1];
+  input->GetCellDims(celldims);
+  vtkIdType cd01 = vtkIdType{celldims[0]} * celldims[1];
+  auto inCD = input->GetCellData();
+  auto outCD = output->GetCellData();
+  outCD->CopyAllocate(inCD);
+
+  vtkNew<vtkIdList> ids;
+  vtkNew<vtkPoints> outPts;
+  vtkPoints *inPts = input->GetPoints();
+  ids->SetNumberOfIds(4);
+    
+  vtkIdType NumberOfContours = this->ContourValues->GetNumberOfContours();
+  if (AxisNumber == 0) {
+    outPts->Allocate(4 * celldims[1] * celldims[2]*NumberOfContours);
+  } else if (AxisNumber == 1) {
+    outPts->Allocate(4 * celldims[0] * celldims[2]*NumberOfContours);
+  } else if (AxisNumber == 2) {
+    outPts->Allocate(4 * celldims[0] * celldims[1]*NumberOfContours);
+  }
+  vtkIdType outCellId = 0;
+    
+  for(int i = 0; i != NumberOfContours; ++i)
+  {
+    double value = this->ContourValues->GetValue(i);
+    if (AxisNumber == 0) {
+      cutScalars->SetNumberOfTuples(dims[0]);
+      for(vtkIdType i = 0; i < dims[0]; ++i) {
+        double x[3];
+        dataArrayInput->GetTuple(i, x);
+        double FuncVal = this->CutFunction->EvaluateFunction(x);
+        cutScalars->SetTypedComponent(i, 0, std::abs(FuncVal - value));
+      }
+    } else if (AxisNumber == 1) {
+      cutScalars->SetNumberOfTuples(dims[1]);
+      for (vtkIdType i = 0, j = 0; i < d01; i = i + dims[0], ++j) {
+        double x[3];
+        dataArrayInput->GetTuple(i, x);
+        double FuncVal = this->CutFunction->EvaluateFunction(x);
+        cutScalars->SetTypedComponent(j, 0, std::abs(FuncVal - value));
+      }
+    } else if (AxisNumber == 2) {
+      cutScalars->SetNumberOfTuples(dims[2]);
+      for (vtkIdType i = 0, j = 0; i < numPts; i = i + d01, ++j) {
+        double x[3];
+        dataArrayInput->GetTuple(i, x);
+        double FuncVal = this->CutFunction->EvaluateFunction(x);
+        cutScalars->SetTypedComponent(j, 0, std::abs(FuncVal - value));
+      }
+    }
+    double *ptr = cutScalars->GetPointer(0);
+    vtkIdType min = std::distance(
+        ptr, std::min_element(ptr, ptr + cutScalars->GetNumberOfTuples()));
+
+    // check for out-of-bounds values
+    if (min == 0 || min == celldims[AxisNumber])
+      break;
+
+    min = std::min(min, static_cast<vtkIdType>(celldims[AxisNumber] - 1));
+
+    if (AxisNumber == 0) {
+      for (int j = 0; j < celldims[1]; ++j) {
+        for (int k=0; k < celldims[2]; ++k) {
+          vtkIdType index = min + j * celldims[0] + k * cd01;
+          if (input->IsCellVisible(index)) {
+            double x[3];
+            inPts->GetPoint(min + j * dims[0] + k * d01, x);
+            ids->SetId(0, outPts->InsertNextPoint(x));
+            inPts->GetPoint(min + j * dims[0] + (k + 1) * d01, x);
+            ids->SetId(1, outPts->InsertNextPoint(x));
+            inPts->GetPoint(min + (j + 1) * dims[0] + (k + 1) * d01, x);
+            ids->SetId(2, outPts->InsertNextPoint(x));
+            inPts->GetPoint(min + (j + 1) * dims[0] + k * d01, x);
+            ids->SetId(3, outPts->InsertNextPoint(x));
+            output->InsertNextCell(VTK_QUAD, ids.Get());
+            outCD->CopyData(inCD, index, outCellId++);
+          }
+        }
+      }
+    } else if (AxisNumber == 1) {
+      for (int i = 0; i < celldims[0]; ++i) {
+        for (int k=0; k < celldims[2]; ++k) {
+          vtkIdType index = i + min * celldims[0] + k * cd01;
+          if (input->IsCellVisible(index)) {
+            double x[3];
+            inPts->GetPoint(i + min * dims[0] + k * d01, x);
+            ids->SetId(0, outPts->InsertNextPoint(x));
+            inPts->GetPoint(i + 1 + min * dims[0] + k * d01, x);
+            ids->SetId(1, outPts->InsertNextPoint(x));
+            inPts->GetPoint(i + 1 + min * dims[0] + (k + 1) * d01, x);
+            ids->SetId(2, outPts->InsertNextPoint(x));
+            inPts->GetPoint(i + min * dims[0] + (k + 1) * d01, x);
+            ids->SetId(3, outPts->InsertNextPoint(x));
+            output->InsertNextCell(VTK_QUAD, ids.Get());
+            outCD->CopyData(inCD, index, outCellId++);
+          }
+        }
+      }
+    } else if (AxisNumber == 2) {
+      for (int i = 0; i < celldims[0]; ++i) {
+        for (int j=0; j < celldims[1]; ++j) {
+          vtkIdType index = i + j * celldims[0] + min * cd01;
+          if (input->IsCellVisible(index)) {
+            double x[3];
+            inPts->GetPoint(i + j * dims[0] + min * d01, x);
+            ids->SetId(0, outPts->InsertNextPoint(x));
+            inPts->GetPoint(i + (j + 1) * dims[0] + min * d01, x);
+            ids->SetId(1, outPts->InsertNextPoint(x));
+            inPts->GetPoint(i + 1 + (j + 1) * dims[0] + min * d01, x);
+            ids->SetId(2, outPts->InsertNextPoint(x));
+            inPts->GetPoint(i + 1 + j * dims[0] + min * d01, x);
+            ids->SetId(3, outPts->InsertNextPoint(x));
+            output->InsertNextCell(VTK_QUAD, ids.Get());
+            outCD->CopyData(inCD, index, outCellId++);
+          }
+        }
+      }
+    }
+  }
+  output->SetPoints(outPts.Get());
+  thisOutput->ShallowCopy(output.Get());
+}
+
+namespace{
+//----------------------------------------------------------------------------
+// Find the first visible cell in a vtkStructuredGrid.
+//
+vtkIdType GetFirstVisibleCell(vtkDataSet *DataSetInput)
+{
+  vtkStructuredGrid *input = vtkStructuredGrid::SafeDownCast(DataSetInput);
+  if(input)
+  {
+    if(input->HasAnyBlankCells())
+    {
+      vtkIdType size = input->GetNumberOfElements(vtkDataSet::CELL);
+      for(vtkIdType i = 0; i < size; ++i)
+      {
+        if(input->IsCellVisible(i) != 0)
+        {
+          return i;
+        }
+      }
+    }
+  }
+  return 0;
+}
+}
+
+//----------------------------------------------------------------------------
+// Cut through data generating surface.
+//
+int AlignedCutter::RequestData(
+  vtkInformation *request,
+  vtkInformationVector **inputVector,
+  vtkInformationVector *outputVector)
+{
+  // get the info objects
+  vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
+  vtkInformation *outInfo = outputVector->GetInformationObject(0);
+
+  // get the input and output
+  vtkDataSet *input = vtkDataSet::SafeDownCast(
+    inInfo->Get(vtkDataObject::DATA_OBJECT()));
+  vtkPolyData *output = vtkPolyData::SafeDownCast(
+    outInfo->Get(vtkDataObject::DATA_OBJECT()));
+
+  vtkDebugMacro(<< "Executing cutter");
+  if (!this->CutFunction)
+  {
+    vtkErrorMacro("No cut function specified");
+    return 0;
+  }
+
+  if (!input)
+  {
+    // this could be a table in a multiblock structure, i.e. no cut!
+    return 0;
+  }
+
+  if ( input->GetNumberOfPoints() < 1 || this->GetNumberOfContours() < 1 )
+  {
+    return 1;
+  }
+
+#ifdef TIMEME
+  vtkSmartPointer<vtkTimerLog> timer = vtkSmartPointer<vtkTimerLog>::New();
+  timer->StartTimer();
+#endif
+
+  if ((input->GetDataObjectType() == VTK_STRUCTURED_POINTS ||
+       input->GetDataObjectType() == VTK_IMAGE_DATA) &&
+       input->GetCell(0) && input->GetCell(0)->GetCellDimension() >= 3 )
+  {
+    this->StructuredPointsCutter(input, output, request, inputVector, outputVector);
+  }
+  else if (input->GetDataObjectType() == VTK_STRUCTURED_GRID &&
+           input->GetCell(0) &&
+           input->GetCell(GetFirstVisibleCell(input))->GetCellDimension() >= 3)
+  {
+    this->AlignedStructuredGridCutter(input, output);
+  }
+  else if (input->GetDataObjectType() == VTK_RECTILINEAR_GRID &&
+           static_cast<vtkRectilinearGrid *>(input)->GetDataDimension() == 3 )
+  {
+    this->RectilinearGridCutter(input, output);
+  }
+  else if (input->GetDataObjectType() == VTK_UNSTRUCTURED_GRID_BASE ||
+           input->GetDataObjectType() == VTK_UNSTRUCTURED_GRID)
+  {
+    vtkDebugMacro(<< "Executing Unstructured Grid Cutter");
+    this->UnstructuredGridCutter(input, output);
+  }
+  else
+  {
+    vtkDebugMacro(<< "Executing DataSet Cutter");
+    this->DataSetCutter(input, output);
+  }
+
+#ifdef TIMEME
+  timer->StopTimer();
+  cout << "Sliced "<<output->GetNumberOfCells()<<" cells in "<< timer->GetElapsedTime() <<" secs "<<endl;
+#endif
+  return 1;
+}
diff --git a/qt/paraview_ext/PVPlugins/Representations/AlignedCutter.h b/qt/paraview_ext/PVPlugins/Representations/AlignedCutter.h
new file mode 100644
index 0000000000000000000000000000000000000000..291e8121bb524ce26d3400ff1bb09473767dfe38
--- /dev/null
+++ b/qt/paraview_ext/PVPlugins/Representations/AlignedCutter.h
@@ -0,0 +1,75 @@
+/*=========================================================================
+
+  Program:   Visualization Toolkit
+  Module:    AlignedCutter.h
+
+  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
+  All rights reserved.
+  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
+
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+     PURPOSE.  See the above copyright notice for more information.
+
+=========================================================================*/
+/**
+ * @class   AlignedCutter
+ * @brief   Cut vtkDataSet with user-specified implicit function
+ *
+ * AlignedCutter is a filter to cut through data using any subclass of
+ * vtkImplicitFunction. That is, a polygonal surface is created
+ * corresponding to the implicit function F(x,y,z) = value(s), where
+ * you can specify one or more values used to cut with.
+ *
+ * In VTK, cutting means reducing a cell of dimension N to a cut surface
+ * of dimension N-1. For example, a tetrahedron when cut by a plane (i.e.,
+ * vtkPlane implicit function) will generate triangles. (In comparison,
+ * clipping takes a N dimensional cell and creates N dimension primitives.)
+ *
+ * AlignedCutter is generally used to "slice-through" a dataset, generating
+ * a surface that can be visualized. It is also possible to use AlignedCutter
+ * to do a form of volume rendering. AlignedCutter does this by generating
+ * multiple cut surfaces (usually planes) which are ordered (and rendered)
+ * from back-to-front. The surfaces are set translucent to give a
+ * volumetric rendering effect.
+ *
+ * Note that data can be cut using either 1) the scalar values associated
+ * with the dataset or 2) an implicit function associated with this class.
+ * By default, if an implicit function is set it is used to clip the data
+ * set, otherwise the dataset scalars are used to perform the clipping.
+ *
+ * @sa
+ * vtkImplicitFunction vtkClipPolyData
+*/
+
+#ifndef AlignedCutter_h
+#define AlignedCutter_h
+
+#include "vtkCutter.h"
+
+class VTK_EXPORT AlignedCutter : public vtkCutter {
+public:
+  vtkTypeMacro(AlignedCutter, vtkCutter);
+  vtkSetMacro(AxisNumber, int);
+  vtkGetMacro(AxisNumber, int);
+  /**
+   * Construct with user-specified implicit function; initial value of 0.0; and
+   * generating cut scalars turned off.
+   */
+  static AlignedCutter *New();
+
+protected:
+  explicit AlignedCutter(vtkImplicitFunction *cf = nullptr);
+  ~AlignedCutter() override;
+  int RequestData(vtkInformation *, vtkInformationVector **,
+                  vtkInformationVector *) override;
+  void AlignedStructuredGridCutter(vtkDataSet *, vtkPolyData *);
+  int AxisNumber{0};
+
+private:
+  AlignedCutter(const AlignedCutter &) VTK_DELETE_FUNCTION;
+  void operator=(const AlignedCutter &) VTK_DELETE_FUNCTION;
+};
+//@}
+
+#endif
diff --git a/qt/paraview_ext/PVPlugins/Representations/AlignedThreeSliceFilter.cxx b/qt/paraview_ext/PVPlugins/Representations/AlignedThreeSliceFilter.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..703d923eb41335d1a6186c91f2352388cdbf7182
--- /dev/null
+++ b/qt/paraview_ext/PVPlugins/Representations/AlignedThreeSliceFilter.cxx
@@ -0,0 +1,44 @@
+/*=========================================================================
+
+  Program:   Visualization Toolkit
+  Module:    AlignedThreeSliceFilter.cxx
+
+  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
+  All rights reserved.
+  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
+
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+     PURPOSE.  See the above copyright notice for more information.
+
+=========================================================================*/
+#include "AlignedThreeSliceFilter.h"
+
+#include "AlignedCutter.h"
+#include "vtkAppendPolyData.h"
+#include "vtkPlane.h"
+
+#include <math.h>
+
+vtkStandardNewMacro(AlignedThreeSliceFilter);
+
+//----------------------------------------------------------------------------
+AlignedThreeSliceFilter::AlignedThreeSliceFilter() : vtkThreeSliceFilter() {
+  this->CombinedFilteredInput->RemoveAllInputs();
+  for (int i = 0; i < 3; ++i)
+  {
+    // Allocate internal vars
+    this->Slices[i]->Delete();
+    // AxisNumber cannot be set after being cast to vtkCutter.
+    AlignedCutter *temp = AlignedCutter::New();
+    temp->SetAxisNumber(i);
+    temp->SetCutFunction(this->Planes[i]);
+    this->Slices[i] = temp;
+    // Bind pipeline
+    this->CombinedFilteredInput->AddInputConnection(this->Slices[i]->GetOutputPort());
+  }
+  this->SetToDefaultSettings();
+}
+
+//----------------------------------------------------------------------------
+AlignedThreeSliceFilter::~AlignedThreeSliceFilter() = default;
diff --git a/qt/paraview_ext/PVPlugins/Representations/AlignedThreeSliceFilter.h b/qt/paraview_ext/PVPlugins/Representations/AlignedThreeSliceFilter.h
new file mode 100644
index 0000000000000000000000000000000000000000..4aad92821b44f29bbf3b755fef358ced3f7a1c9d
--- /dev/null
+++ b/qt/paraview_ext/PVPlugins/Representations/AlignedThreeSliceFilter.h
@@ -0,0 +1,54 @@
+/*=========================================================================
+
+  Program:   Visualization Toolkit
+  Module:    AlignedThreeSliceFilter.h
+
+  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
+  All rights reserved.
+  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
+
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+     PURPOSE.  See the above copyright notice for more information.
+
+=========================================================================*/
+/**
+ * @class   AlignedThreeSliceFilter
+ * @brief   Cut vtkDataSet along 3 planes
+ *
+ * AlignedThreeSliceFilter is a filter that slice the input data using 3 plane
+ *cut.
+ * Each axis cut could embed several slices by providing several values.
+ * As output you will find 4 output ports.
+ * The output ports are defined as follow:
+ * - 0: Merge of all the cutter output
+ * - 1: Output of the first internal vtkCutter filter
+ * - 2: Output of the second internal vtkCutter filter
+ * - 3: Output of the third internal vtkCutter filter
+*/
+
+#ifndef AlignedThreeSliceFilter_h
+#define AlignedThreeSliceFilter_h
+
+#include "vtkPVClientServerCoreRenderingModule.h" //needed for exports
+#include "vtkThreeSliceFilter.h"
+
+class VTK_EXPORT AlignedThreeSliceFilter : public vtkThreeSliceFilter {
+public:
+  vtkTypeMacro(AlignedThreeSliceFilter, vtkThreeSliceFilter);
+  /**
+   * Construct with user-specified implicit function; initial value of 0.0; and
+   * generating cut scalars turned off.
+   */
+  static AlignedThreeSliceFilter *New();
+
+protected:
+  AlignedThreeSliceFilter();
+  ~AlignedThreeSliceFilter() override;
+
+private:
+  AlignedThreeSliceFilter(const AlignedThreeSliceFilter &) VTK_DELETE_FUNCTION;
+  void operator=(const AlignedThreeSliceFilter &) VTK_DELETE_FUNCTION;
+};
+
+#endif
diff --git a/qt/paraview_ext/PVPlugins/Representations/CMakeLists.txt b/qt/paraview_ext/PVPlugins/Representations/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..adbd7316bbf6cc066065398a268bff1ed2b17f79
--- /dev/null
+++ b/qt/paraview_ext/PVPlugins/Representations/CMakeLists.txt
@@ -0,0 +1,16 @@
+project( MantidParaViewRepresentation )
+include_directories( SYSTEM ${PARAVIEW_INCLUDE_DIRS} )
+ADD_PARAVIEW_PLUGIN(MantidParaViewRepresentationSMPlugin "1.0"
+  SERVER_MANAGER_XML Representation.xml
+  SERVER_MANAGER_SOURCES
+    vtkAlignedGeometrySliceRepresentation.cxx
+    AlignedThreeSliceFilter.cxx
+    AlignedCutter.cxx)
+
+# Add to the 'VatesParaViewPlugins' group in VS
+set_property( TARGET MantidParaViewRepresentationSMPlugin PROPERTY FOLDER "MantidVatesParaViewPlugins" )
+
+# Put library into subfolder.
+SET_TARGET_OUTPUT_DIRECTORY(MantidParaViewRepresentationSMPlugin  ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/${CMAKE_CFG_INTDIR}/${PVPLUGINS_DIR}/${PVPLUGINS_SUBDIR})
+
+install( TARGETS MantidParaViewRepresentationSMPlugin ${SYSTEM_PACKAGE_TARGET} DESTINATION ${PVPLUGINS_DIR}/${PVPLUGINS_SUBDIR})
diff --git a/qt/paraview_ext/PVPlugins/Representations/Representation.xml b/qt/paraview_ext/PVPlugins/Representations/Representation.xml
new file mode 100644
index 0000000000000000000000000000000000000000..366826581d273adfe834e1e60b04b76bd525d40f
--- /dev/null
+++ b/qt/paraview_ext/PVPlugins/Representations/Representation.xml
@@ -0,0 +1,56 @@
+<ServerManagerConfiguration>
+  <ProxyGroup name="representations">
+    <RepresentationProxy name="AlignedGeometrySliceRepresentation"
+                base_proxygroup="internal_representations"
+                base_proxyname="SurfaceRepresentationBase"
+                class="vtkAlignedGeometrySliceRepresentation"
+                processes="client|renderserver|dataserver">
+      <Documentation>
+        AlignedGeometrySliceRepresentation add support to show multiple slices in the view.
+        This is used by CompositeAlignedGeometrySliceRepresentation.
+      </Documentation>
+      <InputProperty command="SetInputConnection"
+                     name="Input">
+        <DataTypeDomain name="input_type">
+          <DataType value="vtkDataSet" />
+        </DataTypeDomain>
+        <Documentation>Set the input to the representation.</Documentation>
+      </InputProperty>
+
+      <IntVectorProperty name="ShowOutline"
+        command="SetShowOutline"
+        number_of_elements="1"
+        default_values="0">
+        <Documentation>
+          Check to show data outline when showing "Slices".
+        </Documentation>
+        <BooleanDomain name="bool" />
+      </IntVectorProperty>
+    </RepresentationProxy>
+    <PVRepresentationProxy name="CompositeAlignedGeometrySliceRepresentation"
+                           base_proxygroup="representations"
+                           base_proxyname="GeometryRepresentation"
+                           class="vtkPVCompositeRepresentation"
+                           processes="client|renderserver|dataserver" >
+       <RepresentationType  subproxy="AlignedGeometrySliceRepresentation"
+         text="Slices" subtype="Surface"/>
+       <SubProxy>
+         <Proxy name="AlignedGeometrySliceRepresentation"
+           proxygroup="representations"
+           proxyname="AlignedGeometrySliceRepresentation">
+         </Proxy>
+         <ShareProperties subproxy="SurfaceRepresentation">
+           <Exception name="Input" />
+           <Exception name="Visibility" />
+         </ShareProperties>
+         <ExposedProperties>
+           <PropertyGroup label="Slices Parameters">
+             <Property name="ShowOutline"
+                       panel_visibility="advanced"
+                       panel_visibility_default_for_representation="slices" />
+           </PropertyGroup>
+         </ExposedProperties>
+       </SubProxy>
+    </PVRepresentationProxy>
+  </ProxyGroup>
+</ServerManagerConfiguration>
diff --git a/qt/paraview_ext/PVPlugins/Representations/vtkAlignedGeometrySliceRepresentation.cxx b/qt/paraview_ext/PVPlugins/Representations/vtkAlignedGeometrySliceRepresentation.cxx
new file mode 100644
index 0000000000000000000000000000000000000000..5edce31a5ca28f8bd51dd5e665328918a6ae98b2
--- /dev/null
+++ b/qt/paraview_ext/PVPlugins/Representations/vtkAlignedGeometrySliceRepresentation.cxx
@@ -0,0 +1,360 @@
+/*=========================================================================
+
+  Program:   ParaView
+  Module:    vtkAlignedGeometrySliceRepresentation.cxx
+
+  Copyright (c) Kitware, Inc.
+  All rights reserved.
+  See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details.
+
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+     PURPOSE.  See the above copyright notice for more information.
+
+=========================================================================*/
+#include "vtkAlignedGeometrySliceRepresentation.h"
+
+#include "AlignedThreeSliceFilter.h"
+#include "vtkActor.h"
+#include "vtkAlgorithmOutput.h"
+#include "vtkCompositePolyDataMapper2.h"
+#include "vtkDataArray.h"
+#include "vtkDataObject.h"
+#include "vtkDoubleArray.h"
+#include "vtkFieldData.h"
+#include "vtkInformation.h"
+#include "vtkInformationVector.h"
+#include "vtkMath.h"
+#include "vtkMatrix4x4.h"
+#include "vtkNew.h"
+#include "vtkObjectFactory.h"
+#include "vtkOutlineSource.h"
+#include "vtkPVCacheKeeper.h"
+#include "vtkPVChangeOfBasisHelper.h"
+#include "vtkPVGeometryFilter.h"
+#include "vtkPVLODActor.h"
+#include "vtkPVMultiSliceView.h"
+#include "vtkPVOrthographicSliceView.h"
+#include "vtkPolyDataMapper.h"
+#include "vtkRenderer.h"
+#include "vtkSmartPointer.h"
+#include "vtkStringArray.h"
+#include "vtkVector.h"
+
+#include <cassert>
+#include <vector>
+namespace {
+bool GetNormalsToBasisPlanes(vtkMatrix4x4 *changeOfBasisMatrix,
+                             vtkVector3d sliceNormals[3]) {
+  if (!changeOfBasisMatrix) {
+    sliceNormals[0] = vtkVector3d(1, 0, 0);
+    sliceNormals[1] = vtkVector3d(0, 1, 0);
+    sliceNormals[2] = vtkVector3d(0, 0, 1);
+  } else {
+    vtkVector3d axisBases[3];
+    vtkPVChangeOfBasisHelper::GetBasisVectors(changeOfBasisMatrix, axisBases[0],
+                                              axisBases[1], axisBases[2]);
+    for (int cc = 0; cc < 3; cc++) {
+      sliceNormals[cc] = axisBases[(cc + 1) % 3].Cross(axisBases[(cc + 2) % 3]);
+      sliceNormals[cc].Normalize();
+    }
+  }
+  return true;
+}
+
+class vtkGSRGeometryFilter : public vtkPVGeometryFilter {
+  std::vector<double> SlicePositions[3];
+
+public:
+  /// Set positions for slice locations along each of the basis axis.
+  void SetSlicePositions(int axis, const std::vector<double> &positions) {
+    assert(axis >= 0 && axis <= 2);
+    if (this->SlicePositions[axis] != positions) {
+      this->SlicePositions[axis] = positions;
+      this->Modified();
+    }
+  }
+
+  static bool CacheBounds(vtkDataObject *dataObject, const double bounds[6]) {
+    vtkNew<vtkDoubleArray> boundsArray;
+    boundsArray->SetName("vtkGSRGeometryFilter_Bounds");
+    boundsArray->SetNumberOfComponents(6);
+    boundsArray->SetNumberOfTuples(1);
+    std::copy(bounds, bounds + 6, boundsArray->GetPointer(0));
+    dataObject->GetFieldData()->AddArray(boundsArray.GetPointer());
+    return true;
+  }
+  static bool ExtractCachedBounds(vtkDataObject *dataObject, double bounds[6]) {
+    if (dataObject == NULL || dataObject->GetFieldData() == NULL) {
+      return false;
+    }
+    vtkFieldData *fd = dataObject->GetFieldData();
+    // first try OrientedBoundingBox if present. These are more accurate when
+    // Basis is changed.
+    if (vtkPVChangeOfBasisHelper::GetBoundingBoxInBasis(dataObject, bounds)) {
+      return true;
+    }
+    if (fd->GetArray("vtkGSRGeometryFilter_Bounds") &&
+        fd->GetArray("vtkGSRGeometryFilter_Bounds")->GetNumberOfTuples() == 1 &&
+        fd->GetArray("vtkGSRGeometryFilter_Bounds")->GetNumberOfComponents() ==
+            6) {
+      fd->GetArray("vtkGSRGeometryFilter_Bounds")->GetTuple(0, bounds);
+      return (vtkMath::AreBoundsInitialized(bounds) == 1);
+    }
+    return false;
+  }
+
+public:
+  static vtkGSRGeometryFilter *New();
+  vtkTypeMacro(vtkGSRGeometryFilter, vtkPVGeometryFilter);
+
+  virtual int RequestData(vtkInformation *req,
+                          vtkInformationVector **inputVector,
+                          vtkInformationVector *outputVector) VTK_OVERRIDE {
+    vtkSmartPointer<vtkDataObject> inputDO =
+        vtkDataObject::GetData(inputVector[0]);
+    vtkSmartPointer<vtkMatrix4x4> changeOfBasisMatrix =
+        vtkPVChangeOfBasisHelper::GetChangeOfBasisMatrix(inputDO);
+
+    vtkVector3d sliceNormals[3];
+    GetNormalsToBasisPlanes(changeOfBasisMatrix, sliceNormals);
+
+    vtkNew<AlignedThreeSliceFilter> slicer;
+    slicer->SetInputDataObject(inputDO);
+    slicer->SetCutOrigins(0, 0, 0);
+    for (int axis = 0; axis < 3; axis++) {
+      slicer->SetNumberOfSlice(
+          axis, static_cast<int>(this->SlicePositions[axis].size()));
+      slicer->SetCutNormal(axis, sliceNormals[axis].GetData());
+      for (size_t cc = 0; cc < this->SlicePositions[axis].size(); cc++) {
+        double position[4] = {0, 0, 0, 1};
+        position[axis] = this->SlicePositions[axis][cc];
+        // The of position specified in the UI is in the coordinate space
+        // defined by the changeOfBasisMatrix. We need to convert it to
+        // cartesian space.
+        if (changeOfBasisMatrix) {
+          changeOfBasisMatrix->MultiplyPoint(position, position);
+          position[0] /= position[3];
+          position[1] /= position[3];
+          position[2] /= position[3];
+          position[3] = 1.0;
+        }
+        // project this point on slice normal since we're not directly
+        // specifying the slice point but the slice offset along the slice
+        // normal from the slice origin (which is (0,0,0)).
+        double offset = sliceNormals[axis].Dot(vtkVector3d(position));
+        slicer->SetCutValue(axis, static_cast<int>(cc), offset);
+      }
+    }
+    slicer->Update();
+    inputVector[0]->GetInformationObject(0)->Set(
+        vtkDataObject::DATA_OBJECT(), slicer->GetOutputDataObject(0));
+    int ret = this->Superclass::RequestData(req, inputVector, outputVector);
+    inputVector[0]->GetInformationObject(0)->Set(vtkDataObject::DATA_OBJECT(),
+                                                 inputDO);
+
+    // Add input bounds to the ouput field data so it gets cached for use in
+    // vtkAlignedGeometrySliceRepresentation::RequestData().
+    vtkDataObject *output = vtkDataObject::GetData(outputVector, 0);
+    double inputBds[6];
+    vtkGeometryRepresentation::GetBounds(inputDO, inputBds, NULL);
+    vtkGSRGeometryFilter::CacheBounds(output, inputBds);
+    return ret;
+  }
+
+protected:
+  vtkGSRGeometryFilter() {}
+
+  virtual ~vtkGSRGeometryFilter() {}
+
+private:
+  vtkGSRGeometryFilter(const vtkGSRGeometryFilter &);
+  void operator=(vtkGSRGeometryFilter &);
+};
+vtkStandardNewMacro(vtkGSRGeometryFilter);
+} // namespace
+
+class vtkAlignedGeometrySliceRepresentation::vtkInternals {
+public:
+  double OriginalDataBounds[6];
+  vtkNew<vtkOutlineSource> OutlineSource;
+  vtkNew<vtkPolyDataMapper> OutlineMapper;
+  vtkNew<vtkActor> OutlineActor;
+};
+
+vtkStandardNewMacro(vtkAlignedGeometrySliceRepresentation);
+//----------------------------------------------------------------------------
+vtkAlignedGeometrySliceRepresentation::vtkAlignedGeometrySliceRepresentation()
+    : Internals(new vtkAlignedGeometrySliceRepresentation::vtkInternals()) {
+  this->GeometryFilter->Delete();
+  this->GeometryFilter = vtkGSRGeometryFilter::New();
+  this->SetupDefaults();
+  this->Mode = ALL_SLICES;
+  this->ShowOutline = false;
+}
+
+//----------------------------------------------------------------------------
+vtkAlignedGeometrySliceRepresentation::
+    ~vtkAlignedGeometrySliceRepresentation() {
+  delete this->Internals;
+  this->Internals = NULL;
+}
+
+//----------------------------------------------------------------------------
+void vtkAlignedGeometrySliceRepresentation::SetupDefaults() {
+  vtkMath::UninitializeBounds(this->Internals->OriginalDataBounds);
+  this->Superclass::SetupDefaults();
+  vtkCompositePolyDataMapper2 *mapper =
+      vtkCompositePolyDataMapper2::SafeDownCast(this->Mapper);
+  mapper->SetPointIdArrayName("-");
+  mapper->SetCellIdArrayName("vtkSliceOriginalCellIds");
+  mapper->SetCompositeIdArrayName("vtkSliceCompositeIndex");
+
+  this->Internals->OutlineMapper->SetInputConnection(
+      this->Internals->OutlineSource->GetOutputPort());
+  this->Internals->OutlineActor->SetMapper(
+      this->Internals->OutlineMapper.GetPointer());
+  this->Internals->OutlineActor->SetUseBounds(0);
+  this->Internals->OutlineActor->SetVisibility(0);
+}
+
+//----------------------------------------------------------------------------
+int vtkAlignedGeometrySliceRepresentation::ProcessViewRequest(
+    vtkInformationRequestKey *request_type, vtkInformation *inInfo,
+    vtkInformation *outInfo) {
+  if (this->GetVisibility() == false) {
+    return 0;
+  }
+
+  if (request_type == vtkPVView::REQUEST_UPDATE()) {
+    vtkGSRGeometryFilter *geomFilter =
+        vtkGSRGeometryFilter::SafeDownCast(this->GeometryFilter);
+    assert(geomFilter);
+
+    // Propagate slice paramemeters from the view to the representation.
+    vtkPVMultiSliceView *view =
+        vtkPVMultiSliceView::SafeDownCast(inInfo->Get(vtkPVView::VIEW()));
+    if (view) {
+      for (int mode = X_SLICE_ONLY; mode < ALL_SLICES; mode++) {
+        if (this->Mode == mode || this->Mode == ALL_SLICES) {
+          geomFilter->SetSlicePositions(mode, view->GetSlices(mode));
+        } else {
+          geomFilter->SetSlicePositions(mode, std::vector<double>());
+        }
+      }
+      if (geomFilter->GetMTime() > this->GetMTime()) {
+        this->MarkModified();
+      }
+    }
+  }
+  int retVal =
+      this->Superclass::ProcessViewRequest(request_type, inInfo, outInfo);
+  if (retVal && request_type == vtkPVView::REQUEST_UPDATE()) {
+    vtkPVMultiSliceView *view =
+        vtkPVMultiSliceView::SafeDownCast(inInfo->Get(vtkPVView::VIEW()));
+    if (view) {
+      vtkPVMultiSliceView::SetDataBounds(inInfo,
+                                         this->Internals->OriginalDataBounds);
+    }
+    if (this->Mode != ALL_SLICES) {
+      // i.e. being used in vtkPVOrthographicSliceView for showing the
+      // orthographic slices. We don't parallel rendering those orthographic
+      // views for now.
+      vtkPVRenderView::SetDeliverToClientAndRenderingProcesses(inInfo, this,
+                                                               true, true);
+    }
+  }
+  if (request_type == vtkPVView::REQUEST_RENDER()) {
+    vtkAlgorithmOutput *producerPort =
+        vtkPVRenderView::GetPieceProducer(inInfo, this);
+    vtkAlgorithm *algo = producerPort->GetProducer();
+    vtkDataObject *localData =
+        algo->GetOutputDataObject(producerPort->GetIndex());
+
+    vtkSmartPointer<vtkMatrix4x4> changeOfBasisMatrix =
+        vtkPVChangeOfBasisHelper::GetChangeOfBasisMatrix(localData);
+
+    // This is called on the "rendering" nodes. We use this pass to communicate
+    // the "ModelTransformationMatrix" to the view.
+    if (vtkPVMultiSliceView *view =
+            vtkPVMultiSliceView::SafeDownCast(inInfo->Get(vtkPVView::VIEW()))) {
+      view->SetModelTransformationMatrix(changeOfBasisMatrix);
+      const char *titles[3] = {NULL, NULL, NULL};
+      vtkPVChangeOfBasisHelper::GetBasisName(localData, titles[0], titles[1],
+                                             titles[2]);
+      for (int axis = 0; axis < 3; ++axis) {
+        if (titles[axis] != NULL) {
+          vtkPVMultiSliceView::SetAxisTitle(inInfo, axis, titles[axis]);
+        }
+      }
+      double bds[6];
+      if (vtkGSRGeometryFilter::ExtractCachedBounds(localData, bds)) {
+        this->Internals->OutlineSource->SetBounds(bds);
+        this->Internals->OutlineActor->SetUserMatrix(changeOfBasisMatrix);
+        this->Internals->OutlineActor->SetVisibility(this->ShowOutline ? 1 : 0);
+      } else {
+        this->Internals->OutlineActor->SetVisibility(0);
+      }
+    }
+  }
+  return retVal;
+}
+
+//----------------------------------------------------------------------------
+int vtkAlignedGeometrySliceRepresentation::RequestData(
+    vtkInformation *request, vtkInformationVector **inputVector,
+    vtkInformationVector *outputVector) {
+  vtkMath::UninitializeBounds(this->Internals->OriginalDataBounds);
+  if (this->Superclass::RequestData(request, inputVector, outputVector)) {
+    // If data-bounds are provided in the meta-data, we will report those to the
+    // slice view so that the slice view shows the data bounds to the user when
+    // setting up slices.
+    vtkDataObject *localData = this->CacheKeeper->GetOutputDataObject(0);
+    vtkGSRGeometryFilter::ExtractCachedBounds(
+        localData, this->Internals->OriginalDataBounds);
+
+    return 1;
+  }
+  return 0;
+}
+
+//----------------------------------------------------------------------------
+bool vtkAlignedGeometrySliceRepresentation::AddToView(vtkView *view) {
+  vtkPVOrthographicSliceView *rview =
+      vtkPVOrthographicSliceView::SafeDownCast(view);
+  if (rview && this->Mode != ALL_SLICES) {
+    rview
+        ->GetRenderer(this->Mode +
+                      vtkPVOrthographicSliceView::SAGITTAL_VIEW_RENDERER)
+        ->AddActor(this->Actor);
+  } else if (vtkPVRenderView *rvview = vtkPVRenderView::SafeDownCast(view)) {
+    rvview->GetRenderer()->AddActor(this->Internals->OutlineActor.GetPointer());
+  } else {
+    return false;
+  }
+  return this->Superclass::AddToView(view);
+}
+
+//----------------------------------------------------------------------------
+bool vtkAlignedGeometrySliceRepresentation::RemoveFromView(vtkView *view) {
+  vtkPVOrthographicSliceView *rview =
+      vtkPVOrthographicSliceView::SafeDownCast(view);
+  if (rview && this->Mode != ALL_SLICES) {
+    rview
+        ->GetRenderer(this->Mode +
+                      vtkPVOrthographicSliceView::SAGITTAL_VIEW_RENDERER)
+        ->RemoveActor(this->Actor);
+  } else if (vtkPVRenderView *rvview = vtkPVRenderView::SafeDownCast(view)) {
+    rvview->GetRenderer()->RemoveActor(
+        this->Internals->OutlineActor.GetPointer());
+  } else {
+    return false;
+  }
+  return this->Superclass::RemoveFromView(view);
+}
+//----------------------------------------------------------------------------
+void vtkAlignedGeometrySliceRepresentation::PrintSelf(ostream &os,
+                                                      vtkIndent indent) {
+  this->Superclass::PrintSelf(os, indent);
+  os << indent << "ShowOutline: " << this->ShowOutline << endl;
+}
diff --git a/qt/paraview_ext/PVPlugins/Representations/vtkAlignedGeometrySliceRepresentation.h b/qt/paraview_ext/PVPlugins/Representations/vtkAlignedGeometrySliceRepresentation.h
new file mode 100644
index 0000000000000000000000000000000000000000..1e24e767c3bd85c30b843c992bfb12c348d4e559
--- /dev/null
+++ b/qt/paraview_ext/PVPlugins/Representations/vtkAlignedGeometrySliceRepresentation.h
@@ -0,0 +1,78 @@
+/*=========================================================================
+
+  Program:   ParaView
+  Module:    vtkAlignedGeometrySliceRepresentation.h
+
+  Copyright (c) Kitware, Inc.
+  All rights reserved.
+  See Copyright.txt or http://www.paraview.org/HTML/Copyright.html for details.
+
+     This software is distributed WITHOUT ANY WARRANTY; without even
+     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+     PURPOSE.  See the above copyright notice for more information.
+
+=========================================================================*/
+/**
+ * @class   vtkAlignedGeometrySliceRepresentation
+ * @brief   extends vtkGeometryRepresentation to
+ * add support for showing just specific slices from the dataset.
+ *
+ * vtkAlignedGeometrySliceRepresentation extends vtkGeometryRepresentation to
+ * show slices from the dataset. This is used for vtkPVMultiSliceView and
+ * vtkPVOrthographicSliceView.
+ */
+
+#ifndef vtkAlignedGeometrySliceRepresentation_h
+#define vtkAlignedGeometrySliceRepresentation_h
+
+#include "vtkGeometryRepresentation.h"
+
+class VTK_EXPORT vtkAlignedGeometrySliceRepresentation
+    : public vtkGeometryRepresentation {
+public:
+  static vtkAlignedGeometrySliceRepresentation *New();
+  vtkTypeMacro(vtkAlignedGeometrySliceRepresentation,
+               vtkGeometryRepresentation);
+  void PrintSelf(ostream &os, vtkIndent indent) VTK_OVERRIDE;
+
+  virtual int ProcessViewRequest(vtkInformationRequestKey *request_type,
+                                 vtkInformation *inInfo,
+                                 vtkInformation *outInfo) VTK_OVERRIDE;
+
+  enum { X_SLICE_ONLY, Y_SLICE_ONLY, Z_SLICE_ONLY, ALL_SLICES };
+  vtkSetClampMacro(Mode, int, X_SLICE_ONLY, ALL_SLICES);
+  vtkGetMacro(Mode, int);
+
+  //@{
+  /**
+   * Get/Set whether original data outline should be shown in the view.
+   */
+  vtkSetMacro(ShowOutline, bool);
+  vtkGetMacro(ShowOutline, bool);
+  //@}
+
+protected:
+  vtkAlignedGeometrySliceRepresentation();
+  ~vtkAlignedGeometrySliceRepresentation();
+
+  virtual void SetupDefaults() VTK_OVERRIDE;
+  virtual int RequestData(vtkInformation *request,
+                          vtkInformationVector **inputVector,
+                          vtkInformationVector *outputVector) VTK_OVERRIDE;
+
+  virtual bool AddToView(vtkView *view) VTK_OVERRIDE;
+  virtual bool RemoveFromView(vtkView *view) VTK_OVERRIDE;
+
+private:
+  vtkAlignedGeometrySliceRepresentation(
+      const vtkAlignedGeometrySliceRepresentation &) VTK_DELETE_FUNCTION;
+  void
+  operator=(const vtkAlignedGeometrySliceRepresentation &) VTK_DELETE_FUNCTION;
+
+  class vtkInternals;
+  vtkInternals *Internals;
+  int Mode;
+  bool ShowOutline;
+};
+
+#endif
diff --git a/qt/paraview_ext/VatesSimpleGui/QtWidgets/CMakeLists.txt b/qt/paraview_ext/VatesSimpleGui/QtWidgets/CMakeLists.txt
index 3ad75d8f9e9158c382ece13944b703e679b3405f..1c51a3ffedab223dae7264d110a77390faabbe55 100644
--- a/qt/paraview_ext/VatesSimpleGui/QtWidgets/CMakeLists.txt
+++ b/qt/paraview_ext/VatesSimpleGui/QtWidgets/CMakeLists.txt
@@ -36,7 +36,6 @@ qt4_wrap_ui( UI_BUILT_SOURCES
 include_directories(
   inc
   ${CMAKE_CURRENT_BINARY_DIR}
-  ${CMAKE_SOURCE_DIR}/MantidQt/API/inc
 )
 
 set( ALL_FILES
diff --git a/qt/paraview_ext/VatesSimpleGui/ViewWidgets/src/MultisliceView.cpp b/qt/paraview_ext/VatesSimpleGui/ViewWidgets/src/MultisliceView.cpp
index ad895df6de9fadb0e02bf3bf9518ba91af1fecd0..7f1833ab78428243974799da9354f1be83be8caa 100644
--- a/qt/paraview_ext/VatesSimpleGui/ViewWidgets/src/MultisliceView.cpp
+++ b/qt/paraview_ext/VatesSimpleGui/ViewWidgets/src/MultisliceView.cpp
@@ -22,6 +22,8 @@
 #include <vtkPVArrayInformation.h>
 #include <vtkPVChangeOfBasisHelper.h>
 #include <vtkPVDataInformation.h>
+#include <vtkSMMultiSliceViewProxy.h>
+#include <vtkSMPVRepresentationProxy.h>
 #include <vtkSMPropertyHelper.h>
 #include <vtkSMSourceProxy.h>
 #include <vtkVector.h>
@@ -67,7 +69,7 @@ MultiSliceView::MultiSliceView(QWidget *parent,
   if (createRenderProxy) {
     pqRenderView *tmp =
         this->createRenderView(this->m_ui.renderFrame, QString("MultiSlice"));
-
+    this->setupData();
     this->m_mainView = qobject_cast<pqMultiSliceView *>(tmp);
     QObject::connect(this->m_mainView,
                      SIGNAL(sliceClicked(int, double, int, int)), this,
@@ -92,8 +94,16 @@ void MultiSliceView::setupData() {
   // Make sure that origsrc exists
   if (this->origSrc) {
     pqDataRepresentation *drep = builder->createDataRepresentation(
-        this->origSrc->getOutputPort(0), this->m_mainView);
+        this->origSrc->getOutputPort(0), this->m_mainView,
+        "CompositeAlignedGeometrySliceRepresentation");
     vtkSMPropertyHelper(drep->getProxy(), "Representation").Set("Slices");
+    if (!this->isPeaksWorkspace(this->origSrc)) {
+      vtkSMPVRepresentationProxy::SetScalarColoring(
+          drep->getProxy(), "signal", vtkDataObject::FIELD_ASSOCIATION_CELLS);
+      vtkSMMultiSliceViewProxy *viewPxy =
+          vtkSMMultiSliceViewProxy::SafeDownCast(this->m_mainView->getProxy());
+      viewPxy->CreateDefaultRepresentation(this->origSrc->getProxy(), 0);
+    }
     drep->getProxy()->UpdateVTKObjects();
   }
 }
diff --git a/qt/python/mantidqt.sip b/qt/python/mantidqt.sip
index 8550a099832cfb82b1a075690223d28f028c3d1b..0a6a2efc29a820d65783ed85bfc8e4ecf18d43d7 100644
--- a/qt/python/mantidqt.sip
+++ b/qt/python/mantidqt.sip
@@ -1536,6 +1536,8 @@ class QDataProcessorWidget : QWidget
 #include "MantidQtWidgets/Common/DataProcessorUI/QDataProcessorWidget.h"
 %End
 public:
+QDataProcessorWidget(const MantidQt::MantidWidgets::DataProcessorWhiteList &,
+                     QWidget *parent );
 QDataProcessorWidget(const MantidQt::MantidWidgets::DataProcessorWhiteList &,
                      const MantidQt::MantidWidgets::DataProcessorProcessingAlgorithm &,
                      QWidget *parent );
@@ -1554,11 +1556,19 @@ QDataProcessorWidget(const MantidQt::MantidWidgets::DataProcessorWhiteList &,
                      QWidget *parent );
 void accept(MantidQt::MantidWidgets::DataProcessorMainPresenter *);
 void setInstrumentList(const QString &instruments, const QString &defaultInstrument);
+QString getCurrentInstrument() const;
 void transfer(const QList<QString> &);
 void setForcedReProcessing(bool);
+void setCell(const QString &, int, int, int parentRow = 0, int parentColumn = 0);
+QString getCell(int, int, int parentRow = 0, int parentColumn = 0);
+int getNumberOfRows();
+void clearTable();
 
 signals:
 void runPythonCode(const QString &);
+void processButtonClicked();
+void processingFinished();
+void instrumentHasChanged();
 
 private:
 QDataProcessorWidget(const MantidQt::MantidWidgets::QDataProcessorWidget &);
diff --git a/qt/scientific_interfaces/DynamicPDF/SliceSelector.h b/qt/scientific_interfaces/DynamicPDF/SliceSelector.h
index fba89ad3027ed7528fd02d4d8884583fae624154..b90d8ac1f66f81a8142b532172fcb9526eafa243 100644
--- a/qt/scientific_interfaces/DynamicPDF/SliceSelector.h
+++ b/qt/scientific_interfaces/DynamicPDF/SliceSelector.h
@@ -31,7 +31,7 @@ namespace DynamicPDF {
 class WorkspaceRecord {
 
 public:
-  WorkspaceRecord(const std::string &workspaceName);
+  explicit WorkspaceRecord(const std::string &workspaceName);
   ~WorkspaceRecord();
   void updateMetadata(const size_t &newIndex);
   std::pair<double, double> getErange();
@@ -47,7 +47,7 @@ class SliceSelector : public QMainWindow,
   Q_OBJECT
 
 public:
-  SliceSelector(QWidget *parent = nullptr);
+  explicit SliceSelector(QWidget *parent = nullptr);
   ~SliceSelector();
 
 protected:
diff --git a/qt/scientific_interfaces/EnggDiffraction/EnggDiffFittingPresenter.cpp b/qt/scientific_interfaces/EnggDiffraction/EnggDiffFittingPresenter.cpp
index 7566e1da7bdb087aec0983b94e41531ecf967bee..892aa78f9d975a317bbb71d2f8f889309ae97942 100644
--- a/qt/scientific_interfaces/EnggDiffraction/EnggDiffFittingPresenter.cpp
+++ b/qt/scientific_interfaces/EnggDiffraction/EnggDiffFittingPresenter.cpp
@@ -421,7 +421,7 @@ std::vector<std::string> EnggDiffFittingPresenter::getAllBrowsedFilePaths(
   * @return List of found full file paths for the files specified
   */
 std::vector<std::string>
-EnggDiffFittingPresenter::processMultiRun(const std::string userInput) {
+EnggDiffFittingPresenter::processMultiRun(const std::string &userInput) {
 
   // Split user input into the first and last run number
   std::vector<std::string> firstLastRunNoVec;
@@ -1030,7 +1030,7 @@ void EnggDiffFittingPresenter::doFitting(const std::string &focusedRunNo,
 }
 
 void EnggDiffFittingPresenter::runLoadAlg(
-    const std::string focusedFile,
+    const std::string &focusedFile,
     Mantid::API::MatrixWorkspace_sptr &focusedWS) {
   // load the focused workspace file to perform single peak fits
   try {
@@ -1713,7 +1713,7 @@ void EnggDiffFittingPresenter::setDefaultBank(
     m_view->setFittingRunNo(selectedFile);
 }
 
-bool EnggDiffFittingPresenter::isDigit(const std::string text) const {
+bool EnggDiffFittingPresenter::isDigit(const std::string &text) const {
   return std::all_of(text.cbegin(), text.cend(), ::isdigit);
 }
 
diff --git a/qt/scientific_interfaces/EnggDiffraction/EnggDiffFittingPresenter.h b/qt/scientific_interfaces/EnggDiffraction/EnggDiffFittingPresenter.h
index fecf23ead46bc978ece5a255d61d771ff1d15f48..16a27d250fd3b5584acff3ed512af6568b773d33 100644
--- a/qt/scientific_interfaces/EnggDiffraction/EnggDiffFittingPresenter.h
+++ b/qt/scientific_interfaces/EnggDiffraction/EnggDiffFittingPresenter.h
@@ -76,7 +76,7 @@ public:
   void doFitting(const std::string &focusedRunNo,
                  const std::string &expectedPeaks);
 
-  void runLoadAlg(const std::string focusedFile,
+  void runLoadAlg(const std::string &focusedFile,
                   Mantid::API::MatrixWorkspace_sptr &focusedWS);
 
   void runFittingAlgs(std::string FocusedFitPeaksTableName,
@@ -145,7 +145,7 @@ protected slots:
   void fittingRunNoChanged();
 
 private:
-  bool isDigit(const std::string text) const;
+  bool isDigit(const std::string &text) const;
 
   // Methods related single peak fits
   virtual void
@@ -184,7 +184,7 @@ private:
   getAllBrowsedFilePaths(const std::string &inputFullPath,
                          std::vector<std::string> &foundFullFilePaths);
 
-  std::vector<std::string> processMultiRun(const std::string userInput);
+  std::vector<std::string> processMultiRun(const std::string &userInput);
 
   std::vector<std::string>
   processSingleRun(const std::string &userInputBasename,
diff --git a/qt/scientific_interfaces/EnggDiffraction/EnggDiffractionPresenter.cpp b/qt/scientific_interfaces/EnggDiffraction/EnggDiffractionPresenter.cpp
index 32f285c2296c1eb0dfc61585684fa74af5a25605..bdf00d291afecb4eea4989f318f5a18e3154c0b2 100644
--- a/qt/scientific_interfaces/EnggDiffraction/EnggDiffractionPresenter.cpp
+++ b/qt/scientific_interfaces/EnggDiffraction/EnggDiffractionPresenter.cpp
@@ -180,14 +180,9 @@ void EnggDiffractionPresenter::notify(
   }
 }
 
-void EnggDiffractionPresenter::processStart() {
-  EnggDiffCalibSettings cs = m_view->currentCalibSettings();
-  m_view->showStatus("Ready");
-}
+void EnggDiffractionPresenter::processStart() { m_view->showStatus("Ready"); }
 
 void EnggDiffractionPresenter::processLoadExistingCalib() {
-  EnggDiffCalibSettings cs = m_view->currentCalibSettings();
-
   const std::string fname = m_view->askExistingCalibFilename();
   if (fname.empty()) {
     return;
@@ -1247,7 +1242,7 @@ void EnggDiffractionPresenter::doCalib(const EnggDiffCalibSettings &cs,
   * @param outVanName The fixed filename for the vanadium run
   */
 void EnggDiffractionPresenter::appendCalibInstPrefix(
-    const std::string vanNo, std::string &outVanName) const {
+    const std::string &vanNo, std::string &outVanName) const {
   // Use a single non numeric digit so we are guaranteed to skip
   // generating cerium file names
   const std::string cer = "-";
@@ -1266,7 +1261,7 @@ void EnggDiffractionPresenter::appendCalibInstPrefix(
   * @param outCerName The fixed filename for the cerium run
   */
 void EnggDiffractionPresenter::appendCalibInstPrefix(
-    const std::string vanNo, const std::string cerNo, std::string &outVanName,
+    const std::string &vanNo, const std::string &cerNo, std::string &outVanName,
     std::string &outCerName) const {
 
   // Load uses the default instrument if we don't give it the name of the
@@ -1925,7 +1920,7 @@ void EnggDiffractionPresenter::doFocusing(const EnggDiffCalibSettings &cs,
 void EnggDiffractionPresenter::loadOrCalcVanadiumWorkspaces(
     const std::string &vanNo, const std::string &inputDirCalib,
     ITableWorkspace_sptr &vanIntegWS, MatrixWorkspace_sptr &vanCurvesWS,
-    bool forceRecalc, const std::string specNos) {
+    bool forceRecalc, const std::string &specNos) {
   bool foundPrecalc = false;
 
   std::string preIntegFilename, preCurvesFilename;
@@ -2057,7 +2052,7 @@ void EnggDiffractionPresenter::findPrecalcVanadiumCorrFilenames(
 void EnggDiffractionPresenter::loadVanadiumPrecalcWorkspaces(
     const std::string &preIntegFilename, const std::string &preCurvesFilename,
     ITableWorkspace_sptr &vanIntegWS, MatrixWorkspace_sptr &vanCurvesWS,
-    const std::string &vanNo, const std::string specNos) {
+    const std::string &vanNo, const std::string &specNos) {
   AnalysisDataServiceImpl &ADS = Mantid::API::AnalysisDataService::Instance();
 
   auto alg =
@@ -2160,7 +2155,7 @@ void EnggDiffractionPresenter::calcVanadiumWorkspaces(
 * @param runNo run number to search for the file with 'Load'.
 */
 Workspace_sptr
-EnggDiffractionPresenter::loadToPreproc(const std::string runNo) {
+EnggDiffractionPresenter::loadToPreproc(const std::string &runNo) {
   const std::string instStr = m_view->currentInstrument();
   Workspace_sptr inWS;
 
@@ -2805,7 +2800,7 @@ std::string EnggDiffractionPresenter::plotDifcZeroWorkspace(
 * @param bank_i current loop of the bank during calibration
 */
 std::string EnggDiffractionPresenter::outFitParamsTblNameGenerator(
-    const std::string specNos, const size_t bank_i) const {
+    const std::string &specNos, const size_t bank_i) const {
   std::string outFitParamsTblName;
   bool specNumUsed = specNos != "";
 
diff --git a/qt/scientific_interfaces/EnggDiffraction/EnggDiffractionPresenter.h b/qt/scientific_interfaces/EnggDiffraction/EnggDiffractionPresenter.h
index 53fcfaf37475fca01da9e1d3d37a1952ea78940b..610cc6c9c0ac83c9bc4cef23d218ea66adb7811c 100644
--- a/qt/scientific_interfaces/EnggDiffraction/EnggDiffractionPresenter.h
+++ b/qt/scientific_interfaces/EnggDiffraction/EnggDiffractionPresenter.h
@@ -149,10 +149,10 @@ private:
                const std::string &ceriaNo, const std::string &outFilename,
                const std::string &specNos);
 
-  void appendCalibInstPrefix(const std::string vanNo,
+  void appendCalibInstPrefix(const std::string &vanNo,
                              std::string &outVanName) const;
 
-  void appendCalibInstPrefix(const std::string vanNo, const std::string cerNo,
+  void appendCalibInstPrefix(const std::string &vanNo, const std::string &cerNo,
                              std::string &outVanName,
                              std::string &outCerName) const;
 
@@ -215,7 +215,7 @@ private:
                                const std::string &inputDirCalib,
                                Mantid::API::ITableWorkspace_sptr &vanIntegWS,
                                Mantid::API::MatrixWorkspace_sptr &vanCurvesWS,
-                               bool forceRecalc, const std::string specNos);
+                               bool forceRecalc, const std::string &specNos);
 
   void findPrecalcVanadiumCorrFilenames(const std::string &vanNo,
                                         const std::string &inputDirCalib,
@@ -227,7 +227,7 @@ private:
       const std::string &preIntegFilename, const std::string &preCurvesFilename,
       Mantid::API::ITableWorkspace_sptr &vanIntegWS,
       Mantid::API::MatrixWorkspace_sptr &vanCurvesWS, const std::string &vanNo,
-      const std::string specNos);
+      const std::string &specNos);
 
   void calcVanadiumWorkspaces(const std::string &vanNo,
                               Mantid::API::ITableWorkspace_sptr &vanIntegWS,
@@ -242,7 +242,7 @@ private:
   void inputChecksBeforeRebinPulses(const std::string &runNo, size_t nperiods,
                                     double timeStep);
 
-  Mantid::API::Workspace_sptr loadToPreproc(const std::string runNo);
+  Mantid::API::Workspace_sptr loadToPreproc(const std::string &runNo);
 
   virtual void startAsyncRebinningTimeWorker(const std::string &runNo,
                                              double bin,
@@ -285,7 +285,7 @@ private:
   void copyFocusedToUserAndAll(const std::string &fullFilename);
 
   // generates appropriate names for table workspaces
-  std::string outFitParamsTblNameGenerator(const std::string specNos,
+  std::string outFitParamsTblNameGenerator(const std::string &specNos,
                                            size_t bank_i) const;
 
   // generates the pycode string which can be passed to view
diff --git a/qt/scientific_interfaces/General/Background.h b/qt/scientific_interfaces/General/Background.h
index 817853f93e7ea361fad3b05898771120abfa91d0..2f5c343518320448391ad3a1a1b89606fed1421b 100644
--- a/qt/scientific_interfaces/General/Background.h
+++ b/qt/scientific_interfaces/General/Background.h
@@ -19,7 +19,7 @@ class Background : public API::MantidDialog {
   Q_OBJECT
 
 public:
-  Background(QWidget *parent = NULL);
+  explicit Background(QWidget *parent = NULL);
 
   bool removeBackground() const;
   void removeBackground(bool remove);
diff --git a/qt/scientific_interfaces/General/DataComparison.h b/qt/scientific_interfaces/General/DataComparison.h
index 8260ec5a2574c7cc2f983498741f3f1965533602..0d78bba70175f1ce76114cb60f022c96ce7a3036 100644
--- a/qt/scientific_interfaces/General/DataComparison.h
+++ b/qt/scientific_interfaces/General/DataComparison.h
@@ -29,7 +29,7 @@ public:
 
 public:
   /// Default Constructor
-  DataComparison(QWidget *parent = 0);
+  explicit DataComparison(QWidget *parent = 0);
 
   /// Tests if a workspace is shown in the UI
   bool containsWorkspace(Mantid::API::MatrixWorkspace_const_sptr ws);
diff --git a/qt/scientific_interfaces/General/DirectConvertToEnergy.cpp b/qt/scientific_interfaces/General/DirectConvertToEnergy.cpp
index a1a364975913af3e026247cf0e03a6dcf5fd398a..6a8308caa5aa36d501ba9a60116d49295e48d5a1 100644
--- a/qt/scientific_interfaces/General/DirectConvertToEnergy.cpp
+++ b/qt/scientific_interfaces/General/DirectConvertToEnergy.cpp
@@ -251,8 +251,7 @@ void DirectConvertToEnergy::userSelectInstrument(const QString &prefix) {
 }
 
 void DirectConvertToEnergy::openDirectoryDialog() {
-  MantidQt::API::ManageUserDirectories *ad =
-      new MantidQt::API::ManageUserDirectories(this);
+  auto ad = new MantidQt::API::ManageUserDirectories(this);
   ad->show();
   ad->setFocus();
 }
diff --git a/qt/scientific_interfaces/General/DirectConvertToEnergy.h b/qt/scientific_interfaces/General/DirectConvertToEnergy.h
index 0cdc44529b8fd595f59d17e07d6f92adfea81fd6..27087eb15cd49aaa19decb7787c47a8028aa61ff 100644
--- a/qt/scientific_interfaces/General/DirectConvertToEnergy.h
+++ b/qt/scientific_interfaces/General/DirectConvertToEnergy.h
@@ -55,7 +55,7 @@ public: // public constants, ennumerations and types
 
 public: // public constructor, destructor and functions
   /// Default Constructor
-  DirectConvertToEnergy(QWidget *parent = 0);
+  explicit DirectConvertToEnergy(QWidget *parent = 0);
   /// Destructor
   ~DirectConvertToEnergy() override;
   /// Interface name
diff --git a/qt/scientific_interfaces/General/MantidEV.cpp b/qt/scientific_interfaces/General/MantidEV.cpp
index 9b93fb3fd14b83ba33a6cc85d04b720ba64666b6..e05818accc574bbb8ad249106ec06dd723023716 100644
--- a/qt/scientific_interfaces/General/MantidEV.cpp
+++ b/qt/scientific_interfaces/General/MantidEV.cpp
@@ -50,16 +50,10 @@ RunFindPeaks::RunFindPeaks(MantidEVWorker *worker,
                            const std::string &md_ws_name,
                            const std::string &peaks_ws_name, double max_abc,
                            size_t num_to_find, double min_intensity,
-                           double minQPeaks, double maxQPeaks) {
-  this->worker = worker;
-  this->ev_ws_name = ev_ws_name;
-  this->md_ws_name = md_ws_name;
-  this->peaks_ws_name = peaks_ws_name;
-  this->max_abc = max_abc;
-  this->num_to_find = num_to_find;
-  this->min_intensity = min_intensity;
-  this->minQPeaks = minQPeaks;
-  this->maxQPeaks = maxQPeaks;
+                           double minQPeaks, double maxQPeaks)
+    : worker(worker), ev_ws_name(ev_ws_name), md_ws_name(md_ws_name),
+      peaks_ws_name(peaks_ws_name), max_abc(max_abc), num_to_find(num_to_find),
+      min_intensity(min_intensity), minQPeaks(minQPeaks), maxQPeaks(maxQPeaks) {
 }
 
 /**
@@ -77,14 +71,10 @@ RunPredictPeaks::RunPredictPeaks(MantidEVWorker *worker,
                                  const std::string &peaks_ws_name,
                                  double min_pred_wl, double max_pred_wl,
                                  double min_pred_dspacing,
-                                 double max_pred_dspacing) {
-  this->worker = worker;
-  this->peaks_ws_name = peaks_ws_name;
-  this->min_pred_wl = min_pred_wl;
-  this->max_pred_wl = max_pred_wl;
-  this->min_pred_dspacing = min_pred_dspacing;
-  this->max_pred_dspacing = max_pred_dspacing;
-}
+                                 double max_pred_dspacing)
+    : worker(worker), peaks_ws_name(peaks_ws_name), min_pred_wl(min_pred_wl),
+      max_pred_wl(max_pred_wl), min_pred_dspacing(min_pred_dspacing),
+      max_pred_dspacing(max_pred_dspacing) {}
 
 /**
  *  Class to call predictPeaks in a separate thread.
@@ -103,21 +93,16 @@ RunSphereIntegrate::RunSphereIntegrate(
     double outer_radius, bool integrate_edge, bool use_cylinder_integration,
     double cylinder_length, double cylinder_percent_bkg,
     const std::string &cylinder_profile_fit, bool adaptiveQBkg,
-    double adaptiveQMult) {
-  this->worker = worker;
-  this->peaks_ws_name = peaks_ws_name;
-  this->event_ws_name = event_ws_name;
-  this->peak_radius = peak_radius;
-  this->inner_radius = inner_radius;
-  this->outer_radius = outer_radius;
-  this->integrate_edge = integrate_edge;
-  this->use_cylinder_integration = use_cylinder_integration;
-  this->cylinder_length = cylinder_length;
-  this->cylinder_percent_bkg = cylinder_percent_bkg;
-  this->cylinder_profile_fit = cylinder_profile_fit;
-  this->adaptiveQBkg = adaptiveQBkg;
-  this->adaptiveQMult = adaptiveQMult;
-}
+    double adaptiveQMult)
+    : worker(worker), peaks_ws_name(peaks_ws_name),
+      event_ws_name(event_ws_name), peak_radius(peak_radius),
+      inner_radius(inner_radius), outer_radius(outer_radius),
+      integrate_edge(integrate_edge),
+      use_cylinder_integration(use_cylinder_integration),
+      cylinder_length(cylinder_length),
+      cylinder_percent_bkg(cylinder_percent_bkg),
+      cylinder_profile_fit(cylinder_profile_fit), adaptiveQBkg(adaptiveQBkg),
+      adaptiveQMult(adaptiveQMult) {}
 
 /**
  *  Class to call sphereIntegrate in a separate thread.
@@ -137,13 +122,10 @@ RunFitIntegrate::RunFitIntegrate(MantidEVWorker *worker,
                                  const std::string &event_ws_name,
                                  const std::string &rebin_params,
                                  size_t n_bad_edge_pix,
-                                 bool use_ikeda_carpenter) {
-  this->worker = worker;
-  this->peaks_ws_name = peaks_ws_name;
-  this->event_ws_name = event_ws_name;
-  this->rebin_params = rebin_params;
-  this->n_bad_edge_pix = n_bad_edge_pix;
-  this->use_ikeda_carpenter = use_ikeda_carpenter;
+                                 bool use_ikeda_carpenter)
+    : worker(worker), peaks_ws_name(peaks_ws_name),
+      event_ws_name(event_ws_name), rebin_params(rebin_params),
+      n_bad_edge_pix(n_bad_edge_pix), use_ikeda_carpenter(use_ikeda_carpenter) {
 }
 
 /**
@@ -160,16 +142,11 @@ void RunFitIntegrate::run() {
 RunEllipsoidIntegrate::RunEllipsoidIntegrate(
     MantidEVWorker *worker, const std::string &peaks_ws_name,
     const std::string &event_ws_name, double region_radius, bool specify_size,
-    double peak_size, double inner_size, double outer_size) {
-  this->worker = worker;
-  this->peaks_ws_name = peaks_ws_name;
-  this->event_ws_name = event_ws_name;
-  this->region_radius = region_radius;
-  this->specify_size = specify_size;
-  this->peak_size = peak_size;
-  this->inner_size = inner_size;
-  this->outer_size = outer_size;
-}
+    double peak_size, double inner_size, double outer_size)
+    : worker(worker), peaks_ws_name(peaks_ws_name),
+      event_ws_name(event_ws_name), region_radius(region_radius),
+      specify_size(specify_size), peak_size(peak_size), inner_size(inner_size),
+      outer_size(outer_size) {}
 
 /**
  *  Class to call ellipsoidIntegrate in a separate thread.
@@ -187,12 +164,11 @@ void RunEllipsoidIntegrate::run() {
  *  Constructor for MantidEV.  Makes the thread pool and instance of
  *  MantidEVWorker.
  */
-MantidEV::MantidEV(QWidget *parent) : UserSubWindow(parent) {
-  last_Q = V3D(0, 0, 0);
-  worker = new MantidEVWorker();
-  m_thread_pool = new QThreadPool(this);
-  m_thread_pool->setMaxThreadCount(1);
+MantidEV::MantidEV(QWidget *parent)
+    : UserSubWindow(parent), worker(new MantidEVWorker()), last_Q(V3D(0, 0, 0)),
+      m_thread_pool(new QThreadPool(this)) {
 
+  m_thread_pool->setMaxThreadCount(1);
   QObject::connect(&(MantidQt::API::SelectionNotificationService::Instance()),
                    SIGNAL(QPointSelection_signal(bool, double, double, double)),
                    this,
diff --git a/qt/scientific_interfaces/General/MantidEV.h b/qt/scientific_interfaces/General/MantidEV.h
index 0539d9c4a382b8e70c22e96ecfc129e71db4af69..1385c2a00157116cd1e4cc322b5a8a34f7bf6e5c 100644
--- a/qt/scientific_interfaces/General/MantidEV.h
+++ b/qt/scientific_interfaces/General/MantidEV.h
@@ -31,14 +31,12 @@ namespace CustomInterfaces {
 class RunLoadAndConvertToMD : public QRunnable {
 public:
   /// Constructor just saves the info needed by the run() method
-  RunLoadAndConvertToMD(MantidEVWorker *worker, const std::string &file_name,
-                        const std::string &ev_ws_name,
-                        const std::string &md_ws_name, const double modQ,
-                        const double minQ, const double maxQ,
-                        const bool do_lorentz_corr, const bool load_data,
-                        const bool load_det_cal,
-                        const std::string &det_cal_file,
-                        const std::string &det_cal_file2);
+  explicit RunLoadAndConvertToMD(
+      MantidEVWorker *worker, const std::string &file_name,
+      const std::string &ev_ws_name, const std::string &md_ws_name,
+      const double modQ, const double minQ, const double maxQ,
+      const bool do_lorentz_corr, const bool load_data, const bool load_det_cal,
+      const std::string &det_cal_file, const std::string &det_cal_file2);
 
   /// Calls worker->loadAndConvertToMD from a separate thread
   void run() override;
@@ -194,7 +192,7 @@ class MantidEV : public API::UserSubWindow {
 
 public:
   /// Constructor
-  MantidEV(QWidget *parent = 0);
+  explicit MantidEV(QWidget *parent = 0);
 
   /// Destructor
   ~MantidEV() override;
diff --git a/qt/scientific_interfaces/General/SampleTransmission.h b/qt/scientific_interfaces/General/SampleTransmission.h
index 4f49a410b57fe6cfea34d63a6360a50c9d58f082..11ac968b3a248e9ab9df9f49d725514192076b19 100644
--- a/qt/scientific_interfaces/General/SampleTransmission.h
+++ b/qt/scientific_interfaces/General/SampleTransmission.h
@@ -23,7 +23,7 @@ public:
 
 public:
   /// Default Constructor
-  SampleTransmission(QWidget *parent = 0);
+  explicit SampleTransmission(QWidget *parent = 0);
 
 private slots:
   /// Opens the Qt help page for the interface
diff --git a/qt/scientific_interfaces/General/StepScan.h b/qt/scientific_interfaces/General/StepScan.h
index 641c77706a7b1593f77a73c4c3e5b2c3d86a33a7..0f1036bc1ef1e442370fb5021d3de87a3ada9abe 100644
--- a/qt/scientific_interfaces/General/StepScan.h
+++ b/qt/scientific_interfaces/General/StepScan.h
@@ -22,7 +22,7 @@ public:
   // This interface's categories.
   static QString categoryInfo() { return "General"; }
 
-  StepScan(QWidget *parent = 0);
+  explicit StepScan(QWidget *parent = 0);
   ~StepScan() override;
 
 signals:
diff --git a/qt/scientific_interfaces/ISISReflectometry/CMakeLists.txt b/qt/scientific_interfaces/ISISReflectometry/CMakeLists.txt
index 225cb5e24b842e117fb6a7a707f305612de931c5..285f119ba72c0ba7226b539ef0217e03f4ae98a6 100644
--- a/qt/scientific_interfaces/ISISReflectometry/CMakeLists.txt
+++ b/qt/scientific_interfaces/ISISReflectometry/CMakeLists.txt
@@ -1,69 +1,77 @@
 set ( SRC_FILES
-	MeasurementItem.cpp
-	QtReflEventTabView.cpp
-	QtReflEventView.cpp
-	QtReflMainWindowView.cpp
-	QtReflRunsTabView.cpp
-	QtReflSaveTabView.cpp
-	QtReflSettingsTabView.cpp
-	QtReflSettingsView.cpp
-	ReflCatalogSearcher.cpp
-	ReflDataProcessorPresenter.cpp
-	ReflEventPresenter.cpp
-	ReflEventTabPresenter.cpp
+    MeasurementItem.cpp
+    QtReflEventTabView.cpp
+    QtReflEventView.cpp
+    QtReflMainWindowView.cpp
+    QtReflRunsTabView.cpp
+    QtReflSaveTabView.cpp
+    QtReflSettingsTabView.cpp
+    QtReflSettingsView.cpp
+    ReflCatalogSearcher.cpp
+    ReflDataProcessorPresenter.cpp
+    ReflEventPresenter.cpp
+    ReflEventTabPresenter.cpp
     ReflFromStdStringMap.cpp
-	ReflGenericDataProcessorPresenterFactory.cpp
-	ReflLegacyTransferStrategy.cpp
-	ReflMainWindowPresenter.cpp
-	ReflMeasureTransferStrategy.cpp
-	ReflNexusMeasurementItemSource.cpp
-	ReflRunsTabPresenter.cpp
-	ReflSearchModel.cpp
-	ReflSaveTabPresenter.cpp
-	ReflSettingsPresenter.cpp
-	ReflSettingsTabPresenter.cpp
-	ReflTableSchema.cpp
-	TransferResults.cpp
+    ReflGenericDataProcessorPresenterFactory.cpp
+    ReflLegacyTransferStrategy.cpp
+    ReflMainWindowPresenter.cpp
+    ReflMeasureTransferStrategy.cpp
+    ReflNexusMeasurementItemSource.cpp
+    ReflRunsTabPresenter.cpp
+    ReflSaveTabPresenter.cpp
+    ReflSearchModel.cpp
+    ReflSettingsPresenter.cpp
+    ReflSettingsTabPresenter.cpp
+    ReflTableSchema.cpp
+    TransferResults.cpp
 )
 
 # Include files aren't required, but this makes them appear in Visual Studio
 # IMPORTANT: Include files are required in the MOC_FILES set. Scroll down to find it.
 set ( INC_FILES
     DllConfig.h
-	IReflEventPresenter.h
-	IReflEventTabPresenter.h
-	IReflEventView.h
-	IReflMainWindowPresenter.h
-	IReflMainWindowView.h
-	IReflRunsTabPresenter.h
-	IReflRunsTabView.h
-	IReflSearcher.h
-	IReflSaveTabPresenter.h
-	IReflSaveTabView.h
-	IReflSettingsPresenter.h
-	IReflSettingsTabPresenter.h
-	IReflSettingsView.h
-	MeasurementItem.h
-	QtReflMainWindowView.h
-	QtReflRunsTabView.h
-	ReflCatalogSearcher.h
-	ReflDataProcessorPresenter.h
-	ReflEventPresenter.h
-	ReflEventTabPresenter.h
+    IReflEventPresenter.h
+    IReflEventTabPresenter.h
+    IReflEventView.h
+    IReflMainWindowPresenter.h
+    IReflMainWindowView.h
+    IReflRunsTabPresenter.h
+    IReflRunsTabView.h
+    IReflSaveTabPresenter.h
+    IReflSaveTabView.h
+    IReflSearcher.h
+    IReflSettingsPresenter.h
+    IReflSettingsTabPresenter.h
+    IReflSettingsView.h
+    MeasurementItem.h
+    PrecompiledHeader.h
+    QtReflEventTabView.h
+    QtReflEventView.h
+    QtReflMainWindowView.h
+    QtReflRunsTabView.h
+    QtReflSaveTabView.h
+    QtReflSettingsTabView.h
+    QtReflSettingsView.h
+    ReflCatalogSearcher.h
+    ReflDataProcessorMainPresenter.h
+    ReflDataProcessorPresenter.h
+    ReflEventPresenter.h
+    ReflEventTabPresenter.h
     ReflFromStdStringMap.h
-	ReflGenericDataProcessorPresenterFactory.h
-	ReflLegacyTransferStrategy.h
-	ReflMainWindowPresenter.h
-	ReflMeasureTransferStrategy.h
-	ReflMeasurementItemSource.h
-	ReflNexusMeasurementItemSource.h
-	ReflRunsTabPresenter.h
-	ReflSettingsPresenter.h
-	ReflSettingsTabPresenter.h
-	ReflSearchModel.h
-	ReflTableSchema.h
-	ReflTransferStrategy.h
-	TransferResults.h
+    ReflGenericDataProcessorPresenterFactory.h
+    ReflLegacyTransferStrategy.h
+    ReflMainWindowPresenter.h
+    ReflMeasureTransferStrategy.h
+    ReflMeasurementItemSource.h
+    ReflNexusMeasurementItemSource.h
+    ReflRunsTabPresenter.h
+    ReflSaveTabPresenter.h
+    ReflSearchModel.h
+    ReflSettingsPresenter.h
+    ReflSettingsTabPresenter.h
+    ReflTableSchema.h
+    ReflTransferStrategy.h
+    TransferResults.h
 )
 
 set ( MOC_FILES 
diff --git a/qt/scientific_interfaces/ISISReflectometry/QtReflEventView.h b/qt/scientific_interfaces/ISISReflectometry/QtReflEventView.h
index b437c803a4cefe33c49c8ed7445be76ea23c5d3e..7d09116f6ea15ed7e3e5afccd23e04f9246350f8 100644
--- a/qt/scientific_interfaces/ISISReflectometry/QtReflEventView.h
+++ b/qt/scientific_interfaces/ISISReflectometry/QtReflEventView.h
@@ -39,7 +39,7 @@ class QtReflEventView : public QWidget, public IReflEventView {
   Q_OBJECT
 public:
   /// Constructor
-  QtReflEventView(QWidget *parent = 0);
+  explicit QtReflEventView(QWidget *parent = 0);
   /// Destructor
   ~QtReflEventView() override;
   /// Returns the presenter managing this view
diff --git a/qt/scientific_interfaces/ISISReflectometry/QtReflMainWindowView.h b/qt/scientific_interfaces/ISISReflectometry/QtReflMainWindowView.h
index bb2b01176ffa7b94dee8d43b0d66d7ac28406439..90bdcb242851c31ba29130bd2c516fe952ec4d95 100644
--- a/qt/scientific_interfaces/ISISReflectometry/QtReflMainWindowView.h
+++ b/qt/scientific_interfaces/ISISReflectometry/QtReflMainWindowView.h
@@ -46,7 +46,7 @@ class QtReflMainWindowView : public MantidQt::API::UserSubWindow,
                              public IReflMainWindowView {
 public:
   /// Constructor
-  QtReflMainWindowView(QWidget *parent = 0);
+  explicit QtReflMainWindowView(QWidget *parent = 0);
   /// Destructor
   ~QtReflMainWindowView() override;
   /// Name of the interface
diff --git a/qt/scientific_interfaces/ISISReflectometry/QtReflSettingsView.h b/qt/scientific_interfaces/ISISReflectometry/QtReflSettingsView.h
index 6bba5c2f490087f12a9577a4e9735a1867c33a0b..8526697d1537879e4e5bdf4c8a5553fa3ecc1225 100644
--- a/qt/scientific_interfaces/ISISReflectometry/QtReflSettingsView.h
+++ b/qt/scientific_interfaces/ISISReflectometry/QtReflSettingsView.h
@@ -39,7 +39,7 @@ class QtReflSettingsView : public QWidget, public IReflSettingsView {
   Q_OBJECT
 public:
   /// Constructor
-  QtReflSettingsView(QWidget *parent = 0);
+  explicit QtReflSettingsView(QWidget *parent = 0);
   /// Destructor
   ~QtReflSettingsView() override;
   /// Returns the presenter managing this view
diff --git a/qt/scientific_interfaces/ISISSANS/SANSEventSlicing.h b/qt/scientific_interfaces/ISISSANS/SANSEventSlicing.h
index 3b7f190b1c317229f220b2fb6563407155c1b0cd..d4a3870b9b39a145bd9d085213058c1e1e59d083 100644
--- a/qt/scientific_interfaces/ISISSANS/SANSEventSlicing.h
+++ b/qt/scientific_interfaces/ISISSANS/SANSEventSlicing.h
@@ -13,7 +13,7 @@ class SANSEventSlicing : public API::UserSubWindow {
 
 public:
   /// Default Constructor
-  SANSEventSlicing(QWidget *parent = 0);
+  explicit SANSEventSlicing(QWidget *parent = 0);
   /// Destructor
   ~SANSEventSlicing() override;
 
diff --git a/qt/scientific_interfaces/ISISSANS/SANSPlotSpecial.h b/qt/scientific_interfaces/ISISSANS/SANSPlotSpecial.h
index 4cf8adedb87b8f3ca5fa3f576dfefafec98f84de..d753b4cd8f3b83a0dd7595772772762f9a80bd46 100644
--- a/qt/scientific_interfaces/ISISSANS/SANSPlotSpecial.h
+++ b/qt/scientific_interfaces/ISISSANS/SANSPlotSpecial.h
@@ -42,7 +42,7 @@ public:
       LogLog,
       General
     };
-    Transform(TransformType type);
+    explicit Transform(TransformType type);
     ~Transform();
     void init();
     std::vector<double> functionConstants();
@@ -72,7 +72,7 @@ public:
     InterceptDerived,
     InterceptUnits
   };
-  SANSPlotSpecial(QWidget *parent = 0);
+  explicit SANSPlotSpecial(QWidget *parent = 0);
   ~SANSPlotSpecial() override;
 
 public slots:
diff --git a/qt/scientific_interfaces/ISISSANS/SANSRunWindow.h b/qt/scientific_interfaces/ISISSANS/SANSRunWindow.h
index 7b2e2921e3362ee55b9c620bbbfe081a32a9e849..8d6bcfc73f77c8ad18f1f21eb608bd421d01c2ec 100644
--- a/qt/scientific_interfaces/ISISSANS/SANSRunWindow.h
+++ b/qt/scientific_interfaces/ISISSANS/SANSRunWindow.h
@@ -80,7 +80,7 @@ public:
     TwoD  ///< For 2D reductions
   };
   /// Default Constructor
-  SANSRunWindow(QWidget *parent = 0);
+  explicit SANSRunWindow(QWidget *parent = 0);
   /// Destructor
   ~SANSRunWindow() override;
 
diff --git a/qt/scientific_interfaces/Indirect/ConvFit.cpp b/qt/scientific_interfaces/Indirect/ConvFit.cpp
index cf043adaffd9fb5ec490bf824833526e3b806eaf..2d2d75f432fa5485feffb6fc5857a27e3384fdae 100644
--- a/qt/scientific_interfaces/Indirect/ConvFit.cpp
+++ b/qt/scientific_interfaces/Indirect/ConvFit.cpp
@@ -330,6 +330,7 @@ IAlgorithm_sptr ConvFit::sequentialFit(const std::string &specMin,
   cfs->initialize();
   cfs->setProperty("InputWorkspace", m_cfInputWS->getName());
   cfs->setProperty("Function", function);
+  cfs->setProperty("PassWSIndexToFunction", true);
   cfs->setProperty("BackgroundType",
                    m_uiForm.cbBackground->currentText().toStdString());
   cfs->setProperty("StartX", m_properties["StartX"]->valueText().toStdString());
@@ -585,36 +586,45 @@ void ConvFit::newDataLoaded(const QString wsName) {
 
 /**
 * Create a resolution workspace with the same number of histograms as in the
-* sample.
+* sample, if the resolution and sample differ in their number of histograms.
 *
 * Needed to allow DiffSphere and DiffRotDiscreteCircle fit functions to work as
-* they need
-* to have the WorkspaceIndex attribute set.
+* they need to have the WorkspaceIndex attribute set.
 */
 void ConvFit::extendResolutionWorkspace() {
   if (m_cfInputWS && m_uiForm.dsResInput->isValid()) {
     const QString resWsName = m_uiForm.dsResInput->getCurrentDataName();
-    API::BatchAlgorithmRunner::AlgorithmRuntimeProps appendProps;
-    appendProps["InputWorkspace1"] = "__ConvFit_Resolution";
-
+    // Check spectra consistency between resolution and sample
+    auto resolutionInputWS =
+        AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(
+            resWsName.toStdString());
+    size_t resolutionNumHist = resolutionInputWS->getNumberHistograms();
     size_t numHist = m_cfInputWS->getNumberHistograms();
-    for (size_t i = 0; i < numHist; i++) {
+    if (resolutionNumHist != 1 && resolutionNumHist != numHist) {
+      std::string msg(
+          "Resolution must have either one or as many spectra as the sample");
+      throw std::runtime_error(msg);
+    }
+    // Clone resolution workspace
+    IAlgorithm_sptr cloneAlg =
+        AlgorithmManager::Instance().create("CloneWorkspace");
+    cloneAlg->setLogging(false);
+    cloneAlg->initialize();
+    cloneAlg->setProperty("InputWorkspace", resWsName.toStdString());
+    cloneAlg->setProperty("OutputWorkspace", "__ConvFit_Resolution");
+    cloneAlg->execute();
+    // Append to cloned workspace if necessary
+    if (resolutionNumHist == 1 && numHist > 1) {
       IAlgorithm_sptr appendAlg =
           AlgorithmManager::Instance().create("AppendSpectra");
       appendAlg->setLogging(false);
       appendAlg->initialize();
-      appendAlg->setProperty("InputWorkspace2", resWsName.toStdString());
-      appendAlg->setProperty("OutputWorkspace", "__ConvFit_Resolution");
-
-      if (i == 0) {
-        appendAlg->setProperty("InputWorkspace1", resWsName.toStdString());
-        m_batchAlgoRunner->addAlgorithm(appendAlg);
-      } else {
-        m_batchAlgoRunner->addAlgorithm(appendAlg, appendProps);
-      }
+      appendAlg->setPropertyValue("InputWorkspace1", "__ConvFit_Resolution");
+      appendAlg->setPropertyValue("InputWorkspace2", resWsName.toStdString());
+      appendAlg->setProperty("Number", static_cast<int>(numHist - 1));
+      appendAlg->setPropertyValue("OutputWorkspace", "__ConvFit_Resolution");
+      appendAlg->execute();
     }
-
-    m_batchAlgoRunner->executeBatchAsync();
   }
 }
 
diff --git a/qt/scientific_interfaces/Indirect/ConvFit.h b/qt/scientific_interfaces/Indirect/ConvFit.h
index fb21cc26c6d01702e7992ed35642c44e94a0f452..57bf31a68ac91b4738ffb20da0dba594d4f56b67 100644
--- a/qt/scientific_interfaces/Indirect/ConvFit.h
+++ b/qt/scientific_interfaces/Indirect/ConvFit.h
@@ -82,6 +82,7 @@ private:
   QtStringPropertyManager *m_stringManager;
   QtTreePropertyBrowser *m_cfTree;
   QMap<QtProperty *, QtProperty *> m_fixedProps;
+  // Pointer to sample workspace object
   Mantid::API::MatrixWorkspace_sptr m_cfInputWS;
   Mantid::API::MatrixWorkspace_sptr m_previewPlotData;
   QString m_cfInputWSName;
diff --git a/qt/scientific_interfaces/Indirect/Elwin.cpp b/qt/scientific_interfaces/Indirect/Elwin.cpp
index ec17ca2a205dc12e4a5b595caf9c5cbb71571168..6595e785e6c593766860a77f134c2897e5c642bd 100644
--- a/qt/scientific_interfaces/Indirect/Elwin.cpp
+++ b/qt/scientific_interfaces/Indirect/Elwin.cpp
@@ -490,7 +490,11 @@ void Elwin::plotClicked() {
 
   if (checkADSForPlotSaveWorkspace((workspaceBaseName + "_elf").toStdString(),
                                    true))
-    plotSpectrum((workspaceBaseName + "_elf"), 0, 9);
+    plotSpectrum(workspaceBaseName + "_elf");
+
+  if (checkADSForPlotSaveWorkspace((workspaceBaseName + "_elt").toStdString(),
+                                   true))
+    plotSpectrum(workspaceBaseName + "_elt");
 }
 
 /**
@@ -513,6 +517,10 @@ void Elwin::saveClicked() {
                                    false))
     addSaveWorkspaceToQueue(workspaceBaseName + "_elf");
 
+  if (checkADSForPlotSaveWorkspace((workspaceBaseName + "_elt").toStdString(),
+                                   false))
+    addSaveWorkspaceToQueue(workspaceBaseName + "_elt");
+
   m_batchAlgoRunner->executeBatchAsync();
 }
 
diff --git a/qt/scientific_interfaces/Indirect/IndirectCorrections.cpp b/qt/scientific_interfaces/Indirect/IndirectCorrections.cpp
index 20cf261ccf60b857818b3605d821d00653894e8f..9b2a76f80d69186fd3ec19f59bc1b116bc8c3cf6 100644
--- a/qt/scientific_interfaces/Indirect/IndirectCorrections.cpp
+++ b/qt/scientific_interfaces/Indirect/IndirectCorrections.cpp
@@ -131,8 +131,7 @@ void IndirectCorrections::run() {
  * Opens a directory dialog.
  */
 void IndirectCorrections::openDirectoryDialog() {
-  MantidQt::API::ManageUserDirectories *ad =
-      new MantidQt::API::ManageUserDirectories(this);
+  auto ad = new MantidQt::API::ManageUserDirectories(this);
   ad->show();
   ad->setFocus();
 }
diff --git a/qt/scientific_interfaces/Indirect/IndirectCorrections.h b/qt/scientific_interfaces/Indirect/IndirectCorrections.h
index d807997a2cce5c7dc0c6fb09cb7c05c2981fac1d..bab34cd320a5e3f6aea4254ea3360ea8068b10cd 100644
--- a/qt/scientific_interfaces/Indirect/IndirectCorrections.h
+++ b/qt/scientific_interfaces/Indirect/IndirectCorrections.h
@@ -50,7 +50,7 @@ public:
   // This interface's categories.
   static QString categoryInfo() { return "Indirect"; }
   /// Default Constructor
-  IndirectCorrections(QWidget *parent = 0);
+  explicit IndirectCorrections(QWidget *parent = 0);
 
 private:
   /// Initialize the layout
diff --git a/qt/scientific_interfaces/Indirect/IndirectDataAnalysis.cpp b/qt/scientific_interfaces/Indirect/IndirectDataAnalysis.cpp
index 6e39f5c47d16eb8c2055d77ae5095ef07759541c..51480b2d62c0b7c94f5fe2ab41ca811831a80a3d 100644
--- a/qt/scientific_interfaces/Indirect/IndirectDataAnalysis.cpp
+++ b/qt/scientific_interfaces/Indirect/IndirectDataAnalysis.cpp
@@ -130,8 +130,7 @@ void IndirectDataAnalysis::run() {
  * Opens a directory dialog.
  */
 void IndirectDataAnalysis::openDirectoryDialog() {
-  MantidQt::API::ManageUserDirectories *ad =
-      new MantidQt::API::ManageUserDirectories(this);
+  auto ad = new MantidQt::API::ManageUserDirectories(this);
   ad->show();
   ad->setFocus();
 }
diff --git a/qt/scientific_interfaces/Indirect/IndirectDataAnalysis.h b/qt/scientific_interfaces/Indirect/IndirectDataAnalysis.h
index 2527ec658a23f417835c9b660b26b1e7689d2b8e..5e18dceca6a84ecb224ab686450d2f243b0035e1 100644
--- a/qt/scientific_interfaces/Indirect/IndirectDataAnalysis.h
+++ b/qt/scientific_interfaces/Indirect/IndirectDataAnalysis.h
@@ -48,7 +48,7 @@ public:
   // This interface's categories.
   static QString categoryInfo() { return "Indirect"; }
   /// Default Constructor
-  IndirectDataAnalysis(QWidget *parent = 0);
+  explicit IndirectDataAnalysis(QWidget *parent = 0);
 
 private:
   /// Initialize the layout
diff --git a/qt/scientific_interfaces/Indirect/IndirectDataReduction.cpp b/qt/scientific_interfaces/Indirect/IndirectDataReduction.cpp
index c3c46c2cd57e578c3dfb82adf0478d2ade40be37..774dc94f85aaaba2b6660b1c3afc5c19f19718a7 100644
--- a/qt/scientific_interfaces/Indirect/IndirectDataReduction.cpp
+++ b/qt/scientific_interfaces/Indirect/IndirectDataReduction.cpp
@@ -522,8 +522,7 @@ void IndirectDataReduction::filterUiForFacility(QString facility) {
  * Handles showing the manage directory dialog box.
  */
 void IndirectDataReduction::openDirectoryDialog() {
-  MantidQt::API::ManageUserDirectories *ad =
-      new MantidQt::API::ManageUserDirectories(this);
+  auto ad = new MantidQt::API::ManageUserDirectories(this);
   ad->show();
   ad->setFocus();
 }
diff --git a/qt/scientific_interfaces/Indirect/IndirectDataReduction.h b/qt/scientific_interfaces/Indirect/IndirectDataReduction.h
index 2b6fbb9ea8929a4f3b65c76f3c631722b08754a1..d16033824164945fae5f03e859b5a1687b431ed8 100644
--- a/qt/scientific_interfaces/Indirect/IndirectDataReduction.h
+++ b/qt/scientific_interfaces/Indirect/IndirectDataReduction.h
@@ -59,7 +59,7 @@ class IndirectDataReduction : public MantidQt::API::UserSubWindow {
 
 public:
   /// Default Constructor
-  IndirectDataReduction(QWidget *parent = 0);
+  explicit IndirectDataReduction(QWidget *parent = 0);
   /// Destructor
   ~IndirectDataReduction() override;
   /// Interface name
diff --git a/qt/scientific_interfaces/Indirect/IndirectDiffractionReduction.cpp b/qt/scientific_interfaces/Indirect/IndirectDiffractionReduction.cpp
index ea8288119bba24bc826193bec841fd167a7c3085..d39eca06841f4c33c0975f643a2328e06e09ed71 100644
--- a/qt/scientific_interfaces/Indirect/IndirectDiffractionReduction.cpp
+++ b/qt/scientific_interfaces/Indirect/IndirectDiffractionReduction.cpp
@@ -490,8 +490,8 @@ void IndirectDiffractionReduction::runOSIRISdiffonlyReduction() {
  *diffonly)
  */
 MatrixWorkspace_sptr
-IndirectDiffractionReduction::loadInstrument(std::string instrumentName,
-                                             std::string reflection) {
+IndirectDiffractionReduction::loadInstrument(const std::string &instrumentName,
+                                             const std::string &reflection) {
   std::string idfPath = Mantid::Kernel::ConfigService::Instance().getString(
       "instrumentDefinition.directory");
 
@@ -615,8 +615,7 @@ void IndirectDiffractionReduction::instrumentSelected(
  * Handles opening the directory manager window.
  */
 void IndirectDiffractionReduction::openDirectoryDialog() {
-  MantidQt::API::ManageUserDirectories *ad =
-      new MantidQt::API::ManageUserDirectories(this);
+  auto ad = new MantidQt::API::ManageUserDirectories(this);
   ad->show();
   ad->setFocus();
 }
diff --git a/qt/scientific_interfaces/Indirect/IndirectDiffractionReduction.h b/qt/scientific_interfaces/Indirect/IndirectDiffractionReduction.h
index c5b8bdb2c245d6c18bae76f027b2eb1cc8455b67..b19a71de77089b33ecbeee0d54ed68cff9b26d33 100644
--- a/qt/scientific_interfaces/Indirect/IndirectDiffractionReduction.h
+++ b/qt/scientific_interfaces/Indirect/IndirectDiffractionReduction.h
@@ -22,7 +22,7 @@ public:
 
 public:
   /// Default Constructor
-  IndirectDiffractionReduction(QWidget *parent = 0);
+  explicit IndirectDiffractionReduction(QWidget *parent = 0);
   ~IndirectDiffractionReduction() override;
 
 public slots:
@@ -51,8 +51,9 @@ private:
   bool validateVanCal();
   bool validateCalOnly();
 
-  Mantid::API::MatrixWorkspace_sptr loadInstrument(std::string instrumentName,
-                                                   std::string reflection = "");
+  Mantid::API::MatrixWorkspace_sptr
+  loadInstrument(const std::string &instrumentName,
+                 const std::string &reflection = "");
 
   void runGenericReduction(QString instName, QString mode);
   void runOSIRISdiffonlyReduction();
diff --git a/qt/scientific_interfaces/MultiDatasetFit/MDFAddWorkspaceDialog.h b/qt/scientific_interfaces/MultiDatasetFit/MDFAddWorkspaceDialog.h
index 8340ac6b60d77ce7b361eaf450ddd08e4c31e908..c8e8904ae2957dbafc3cd704a87d0b0515c240b1 100644
--- a/qt/scientific_interfaces/MultiDatasetFit/MDFAddWorkspaceDialog.h
+++ b/qt/scientific_interfaces/MultiDatasetFit/MDFAddWorkspaceDialog.h
@@ -14,7 +14,7 @@ namespace MDF {
 class AddWorkspaceDialog : public QDialog {
   Q_OBJECT
 public:
-  AddWorkspaceDialog(QWidget *parent);
+  explicit AddWorkspaceDialog(QWidget *parent);
   QString workspaceName() const { return m_workspaceName; }
   std::vector<int> workspaceIndices() const { return m_wsIndices; }
 private slots:
diff --git a/qt/scientific_interfaces/MultiDatasetFit/MDFLocalParameterItemDelegate.h b/qt/scientific_interfaces/MultiDatasetFit/MDFLocalParameterItemDelegate.h
index be43306e096c4f20dfd18ef6d536a68ec5c0bc11..04bfcbdcd993acf7617d40dd8a0caa2d7f27b97d 100644
--- a/qt/scientific_interfaces/MultiDatasetFit/MDFLocalParameterItemDelegate.h
+++ b/qt/scientific_interfaces/MultiDatasetFit/MDFLocalParameterItemDelegate.h
@@ -22,7 +22,7 @@ class LocalParameterEditor;
 class LocalParameterItemDelegate : public QStyledItemDelegate {
   Q_OBJECT
 public:
-  LocalParameterItemDelegate(EditLocalParameterDialog *parent = NULL);
+  explicit LocalParameterItemDelegate(EditLocalParameterDialog *parent = NULL);
   QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
                         const QModelIndex &index) const override;
   void setEditorData(QWidget *editor, const QModelIndex &index) const override;
diff --git a/qt/scientific_interfaces/Muon/ALCPeakFittingPresenter.cpp b/qt/scientific_interfaces/Muon/ALCPeakFittingPresenter.cpp
index 792be09a85196b19c24925b0ebeb831149760764..ce0f4ea40c8d04b01e9fcb52c60c97e7656f7281 100644
--- a/qt/scientific_interfaces/Muon/ALCPeakFittingPresenter.cpp
+++ b/qt/scientific_interfaces/Muon/ALCPeakFittingPresenter.cpp
@@ -70,7 +70,7 @@ void ALCPeakFittingPresenter::onPeakPickerChanged() {
   // If PeakPicker is changed, it should be enabled, which means a peak function
   // should be selected
   // (See onCurrentFunctionChanged)
-  assert(index);
+  assert(bool(index));
 
   auto peakFunc = m_view->peakPicker();
 
diff --git a/qt/scientific_interfaces/Muon/MuonAnalysis.cpp b/qt/scientific_interfaces/Muon/MuonAnalysis.cpp
index 0e399f2eda36972b1d83aea0ec488a32b9a22b56..b0c13680c821199088ff857ab6195e4c14b84b3a 100644
--- a/qt/scientific_interfaces/Muon/MuonAnalysis.cpp
+++ b/qt/scientific_interfaces/Muon/MuonAnalysis.cpp
@@ -3031,8 +3031,7 @@ void MuonAnalysis::nowDataAvailable() {
 }
 
 void MuonAnalysis::openDirectoryDialog() {
-  MantidQt::API::ManageUserDirectories *ad =
-      new MantidQt::API::ManageUserDirectories(this);
+  auto ad = new MantidQt::API::ManageUserDirectories(this);
   ad->show();
   ad->setFocus();
 }
diff --git a/qt/scientific_interfaces/Muon/MuonAnalysis.h b/qt/scientific_interfaces/Muon/MuonAnalysis.h
index dd6833afb04f6e82a8cc04938b554e313744ba02..e022362bfbad94686743562f8879907be1755c92 100644
--- a/qt/scientific_interfaces/Muon/MuonAnalysis.h
+++ b/qt/scientific_interfaces/Muon/MuonAnalysis.h
@@ -82,7 +82,7 @@ public:
   static QString categoryInfo() { return "Muon"; }
 
   /// Default Constructor
-  MuonAnalysis(QWidget *parent = 0);
+  explicit MuonAnalysis(QWidget *parent = 0);
 
   /// Destructor
   ~MuonAnalysis();
diff --git a/qt/scientific_interfaces/Muon/MuonAnalysisFitDataTab.h b/qt/scientific_interfaces/Muon/MuonAnalysisFitDataTab.h
index 4d2e039379af92282459f7e5692358ac83f67dc8..9d03abc78cd3219a02a563b1e5fe7ad534711a6b 100644
--- a/qt/scientific_interfaces/Muon/MuonAnalysisFitDataTab.h
+++ b/qt/scientific_interfaces/Muon/MuonAnalysisFitDataTab.h
@@ -51,7 +51,8 @@ class MuonAnalysisFitDataTab : MantidQt::API::UserSubWindow {
 
 public:
   /// Constructor.
-  MuonAnalysisFitDataTab(Ui::MuonAnalysis &uiForm) : m_uiForm(uiForm) {}
+  explicit MuonAnalysisFitDataTab(Ui::MuonAnalysis &uiForm)
+      : m_uiForm(uiForm) {}
   /// Initialise.
   void init();
   /// Copy the given raw workspace and keep for later.
diff --git a/qt/scientific_interfaces/Muon/MuonAnalysisResultTableTab.h b/qt/scientific_interfaces/Muon/MuonAnalysisResultTableTab.h
index 0a0e64c12d2059462a230cb09d0539715e901732..0bc9675b88a1901db54c71f2a7352a1001d73a37 100644
--- a/qt/scientific_interfaces/Muon/MuonAnalysisResultTableTab.h
+++ b/qt/scientific_interfaces/Muon/MuonAnalysisResultTableTab.h
@@ -49,7 +49,7 @@ Code Documentation is available at: <http://doxygen.mantidproject.org>
 class MuonAnalysisResultTableTab : public QWidget {
   Q_OBJECT
 public:
-  MuonAnalysisResultTableTab(Ui::MuonAnalysis &uiForm);
+  explicit MuonAnalysisResultTableTab(Ui::MuonAnalysis &uiForm);
 
   // Refresh the label list and re-populate the tables
   void refresh();
diff --git a/qt/scientific_interfaces/test/EnggDiffractionPresenterTest.h b/qt/scientific_interfaces/test/EnggDiffractionPresenterTest.h
index 084db8aae91154f2d49f2df8077eb44d88ee0f6f..3e4bf7caa6e3b2aaf60f7cb2a9a4094ae74260fb 100644
--- a/qt/scientific_interfaces/test/EnggDiffractionPresenterTest.h
+++ b/qt/scientific_interfaces/test/EnggDiffractionPresenterTest.h
@@ -124,12 +124,6 @@ public:
     testing::NiceMock<MockEnggDiffractionView> mockView;
     MantidQt::CustomInterfaces::EnggDiffractionPresenter pres(&mockView);
 
-    // needs basic calibration settings from the user
-    EnggDiffCalibSettings calibSettings;
-    EXPECT_CALL(mockView, currentCalibSettings())
-        .Times(1)
-        .WillOnce(Return(calibSettings));
-
     // should set a ready or similar status
     EXPECT_CALL(mockView, showStatus(testing::_)).Times(1);
 
@@ -148,12 +142,6 @@ public:
     testing::NiceMock<MockEnggDiffractionView> mockView;
     MantidQt::CustomInterfaces::EnggDiffractionPresenter pres(&mockView);
 
-    // will need basic calibration settings from the user
-    EnggDiffCalibSettings calibSettings;
-    EXPECT_CALL(mockView, currentCalibSettings())
-        .Times(1)
-        .WillOnce(Return(calibSettings));
-
     const std::string mockFname = "foo.par";
     EXPECT_CALL(mockView, askExistingCalibFilename())
         .Times(1)
@@ -186,12 +174,6 @@ public:
 
     MantidQt::CustomInterfaces::EnggDiffractionPresenter pres(&mockView);
 
-    // will need basic calibration settings from the user
-    EnggDiffCalibSettings calibSettings;
-    EXPECT_CALL(mockView, currentCalibSettings())
-        .Times(1)
-        .WillOnce(Return(calibSettings));
-
     // update the selected instrument
     const std::string mockFname = "ENGINX_111111_222222_foo_bar.par";
     EXPECT_CALL(mockView, askExistingCalibFilename())
diff --git a/qt/widgets/common/inc/MantidQtWidgets/Common/DataProcessorUI/DataProcessorMockObjects.h b/qt/widgets/common/inc/MantidQtWidgets/Common/DataProcessorUI/DataProcessorMockObjects.h
index 81ba5f1e923c37522d8876306fd89fa6bea03b3e..8d7c13f34d39e3fb5772767f1f4192ac31853340 100644
--- a/qt/widgets/common/inc/MantidQtWidgets/Common/DataProcessorUI/DataProcessorMockObjects.h
+++ b/qt/widgets/common/inc/MantidQtWidgets/Common/DataProcessorUI/DataProcessorMockObjects.h
@@ -67,6 +67,9 @@ public:
   // Processing options
   MOCK_METHOD1(setForcedReProcessing, void(bool));
 
+  // Accessor
+  MOCK_CONST_METHOD0(getCurrentInstrument, QString());
+
   // Actions/commands
   // Gmock requires parameters and return values of mocked methods to be
   // copyable which means we have to mock addActions() via a proxy method
@@ -80,6 +83,9 @@ public:
       MantidQt::MantidWidgets::AbstractDataProcessorTreeModel>) override{};
   void saveSettings(const std::map<QString, QVariant> &) override{};
 
+  void emitProcessClicked() override{};
+  void emitProcessingFinished() override{};
+
   DataProcessorPresenter *getPresenter() const override { return nullptr; }
 };
 
@@ -159,7 +165,13 @@ private:
   void transfer(const std::vector<std::map<QString, QString>> &) override {}
   void setInstrumentList(const QStringList &, const QString &) override {}
   // void accept(WorkspaceReceiver *) {};
-  void acceptViews(DataProcessorView *, ProgressableView *) override {}
+  void acceptViews(DataProcessorView *, ProgressableView *) override{};
+
+  void setCell(int, int, int, int, const std::string &) override{};
+  std::string getCell(int, int, int, int) override { return ""; };
+  int getNumberOfRows() override { return 2; }
+
+  void clearTable() override {}
 
   std::map<QString, QVariant> m_options;
 };
diff --git a/qt/widgets/common/inc/MantidQtWidgets/Common/DataProcessorUI/DataProcessorOneLevelTreeManager.h b/qt/widgets/common/inc/MantidQtWidgets/Common/DataProcessorUI/DataProcessorOneLevelTreeManager.h
index ef9dd9b1a557fee9615aaf23872a14aa44fef5a2..e84e30307a2a09ebd0d5a6bbf32a735192abe38f 100644
--- a/qt/widgets/common/inc/MantidQtWidgets/Common/DataProcessorUI/DataProcessorOneLevelTreeManager.h
+++ b/qt/widgets/common/inc/MantidQtWidgets/Common/DataProcessorUI/DataProcessorOneLevelTreeManager.h
@@ -87,6 +87,11 @@ public:
   /// Get the number of rows of a given parent
   int rowCount() const override;
   int rowCount(int parent) const override;
+  void setCell(int row, int column, int parentRow, int parentColumn,
+               const std::string &value) override;
+  int getNumberOfRows() override;
+  std::string getCell(int row, int column, int parentRow,
+                      int parentColumn) override;
   /// Get the 'processed' status of a data item
   bool isProcessed(int position) const override;
   bool isProcessed(int position, int parent) const override;
diff --git a/qt/widgets/common/inc/MantidQtWidgets/Common/DataProcessorUI/DataProcessorPresenter.h b/qt/widgets/common/inc/MantidQtWidgets/Common/DataProcessorUI/DataProcessorPresenter.h
index 542f18f72860303f4327cd6c5b1140ee0b02f0f1..a9ef76ac1a4cb06b4721371c8e925c2ebafe3b89 100644
--- a/qt/widgets/common/inc/MantidQtWidgets/Common/DataProcessorUI/DataProcessorPresenter.h
+++ b/qt/widgets/common/inc/MantidQtWidgets/Common/DataProcessorUI/DataProcessorPresenter.h
@@ -98,6 +98,12 @@ public:
                                const QString &title) const = 0;
   virtual bool isProcessing() const = 0;
   virtual void setForcedReProcessing(bool forceReProcessing) = 0;
+  virtual void setCell(int row, int column, int parentRow, int parentColumn,
+                       const std::string &value) = 0;
+  virtual std::string getCell(int row, int column, int parentRow,
+                              int parentColumn) = 0;
+  virtual int getNumberOfRows() = 0;
+  virtual void clearTable() = 0;
 };
 }
 }
diff --git a/qt/widgets/common/inc/MantidQtWidgets/Common/DataProcessorUI/DataProcessorProcessingAlgorithm.h b/qt/widgets/common/inc/MantidQtWidgets/Common/DataProcessorUI/DataProcessorProcessingAlgorithm.h
index abf8a87efa97b781141a0880a619294d4e074ed0..b6125538c50d264c76a914758169eb131535d00d 100644
--- a/qt/widgets/common/inc/MantidQtWidgets/Common/DataProcessorUI/DataProcessorProcessingAlgorithm.h
+++ b/qt/widgets/common/inc/MantidQtWidgets/Common/DataProcessorUI/DataProcessorProcessingAlgorithm.h
@@ -38,7 +38,7 @@ Code Documentation is available at: <http://doxygen.mantidproject.org>
 class EXPORT_OPT_MANTIDQT_COMMON DataProcessorProcessingAlgorithm
     : public DataProcessorProcessingAlgorithmBase {
 public:
-  DataProcessorProcessingAlgorithm() = delete;
+  DataProcessorProcessingAlgorithm();
   // Constructor
   DataProcessorProcessingAlgorithm(
       const QString &name, const std::vector<QString> &prefix,
diff --git a/qt/widgets/common/inc/MantidQtWidgets/Common/DataProcessorUI/DataProcessorTreeManager.h b/qt/widgets/common/inc/MantidQtWidgets/Common/DataProcessorUI/DataProcessorTreeManager.h
index 106f89fe2ac3803a4c31b2a2abae8b10c1acbccc..c3bfc4ce0dc811648d89a26e11ee51e9ac039cbf 100644
--- a/qt/widgets/common/inc/MantidQtWidgets/Common/DataProcessorUI/DataProcessorTreeManager.h
+++ b/qt/widgets/common/inc/MantidQtWidgets/Common/DataProcessorUI/DataProcessorTreeManager.h
@@ -97,7 +97,12 @@ public:
   /// Set the 'processed' status of a data item
   virtual void setProcessed(bool processed, int position) = 0;
   virtual void setProcessed(bool processed, int position, int parent) = 0;
-
+  /// Access cells
+  virtual void setCell(int row, int column, int parentRow, int parentColumn,
+                       const std::string &value) = 0;
+  virtual std::string getCell(int row, int column, int parentRow,
+                              int parentColumn) = 0;
+  virtual int getNumberOfRows() = 0;
   /// Validate a table workspace
   virtual bool isValidModel(Mantid::API::Workspace_sptr ws,
                             size_t whitelistColumns) const = 0;
diff --git a/qt/widgets/common/inc/MantidQtWidgets/Common/DataProcessorUI/DataProcessorTwoLevelTreeManager.h b/qt/widgets/common/inc/MantidQtWidgets/Common/DataProcessorUI/DataProcessorTwoLevelTreeManager.h
index b5541418c439a65e2c22bfa6924cad8cadf5ac59..32522abe498cec34faae705e2f8956d65fc4a007 100644
--- a/qt/widgets/common/inc/MantidQtWidgets/Common/DataProcessorUI/DataProcessorTwoLevelTreeManager.h
+++ b/qt/widgets/common/inc/MantidQtWidgets/Common/DataProcessorUI/DataProcessorTwoLevelTreeManager.h
@@ -87,6 +87,11 @@ public:
   /// Get the number of rows of a given parent
   int rowCount() const override;
   int rowCount(int parent) const override;
+  void setCell(int row, int column, int parentRow, int parentColumn,
+               const std::string &value) override;
+  std::string getCell(int row, int column, int parentRow,
+                      int parentColumn) override;
+  int getNumberOfRows() override;
   /// Get the 'processed' status of a data item
   bool isProcessed(int position) const override;
   bool isProcessed(int position, int parent) const override;
diff --git a/qt/widgets/common/inc/MantidQtWidgets/Common/DataProcessorUI/DataProcessorView.h b/qt/widgets/common/inc/MantidQtWidgets/Common/DataProcessorUI/DataProcessorView.h
index a875756ef414cdb61cc5db8d4855095952c618ff..974f24b242f2eecb2f624dca1e77167cad646cc9 100644
--- a/qt/widgets/common/inc/MantidQtWidgets/Common/DataProcessorUI/DataProcessorView.h
+++ b/qt/widgets/common/inc/MantidQtWidgets/Common/DataProcessorUI/DataProcessorView.h
@@ -106,9 +106,13 @@ public:
   virtual QString getClipboard() const = 0;
   virtual QString getProcessInstrument() const = 0;
   virtual DataProcessorPresenter *getPresenter() const = 0;
+  virtual QString getCurrentInstrument() const = 0;
 
   // Force re-processing of rows
   virtual void setForcedReProcessing(bool forceReProcessing) = 0;
+  // Methods to emit signals
+  virtual void emitProcessClicked() = 0;
+  virtual void emitProcessingFinished() = 0;
 };
 }
 }
diff --git a/qt/widgets/common/inc/MantidQtWidgets/Common/DataProcessorUI/GenericDataProcessorPresenter.h b/qt/widgets/common/inc/MantidQtWidgets/Common/DataProcessorUI/GenericDataProcessorPresenter.h
index 84691cd1bfa8ddd5f9d8359abb318bcf15739516..3ca74da17feb6b0bc8549babba02c748c48dba48 100644
--- a/qt/widgets/common/inc/MantidQtWidgets/Common/DataProcessorUI/GenericDataProcessorPresenter.h
+++ b/qt/widgets/common/inc/MantidQtWidgets/Common/DataProcessorUI/GenericDataProcessorPresenter.h
@@ -98,6 +98,8 @@ public:
   GenericDataProcessorPresenter(
       const DataProcessorWhiteList &whitelist,
       const DataProcessorProcessingAlgorithm &processor);
+  // Constructor: only whitelist
+  GenericDataProcessorPresenter(const DataProcessorWhiteList &whitelist);
   // Delegating constructor: pre-processing, no post-processing
   GenericDataProcessorPresenter(
       const DataProcessorWhiteList &whitelist,
@@ -314,6 +316,14 @@ private:
                           Mantid::API::Workspace_sptr workspace) override;
   void saveNotebook(const TreeData &data);
   std::vector<std::unique_ptr<DataProcessorCommand>> getTableList();
+
+  // set/get values in the table
+  void setCell(int row, int column, int parentRow, int parentColumn,
+               const std::string &value) override;
+  std::string getCell(int row, int column, int parentRow,
+                      int parentColumn) override;
+  int getNumberOfRows() override;
+  void clearTable() override;
 };
 }
 }
diff --git a/qt/widgets/common/inc/MantidQtWidgets/Common/DataProcessorUI/QDataProcessorWidget.h b/qt/widgets/common/inc/MantidQtWidgets/Common/DataProcessorUI/QDataProcessorWidget.h
index d71599018f7bb66f97e13db9610597db7966bb89..17df44ea293f45678a42f5caf70add1199d34641 100644
--- a/qt/widgets/common/inc/MantidQtWidgets/Common/DataProcessorUI/QDataProcessorWidget.h
+++ b/qt/widgets/common/inc/MantidQtWidgets/Common/DataProcessorUI/QDataProcessorWidget.h
@@ -53,6 +53,7 @@ class EXPORT_OPT_MANTIDQT_COMMON QDataProcessorWidget
 public:
   QDataProcessorWidget(std::unique_ptr<DataProcessorPresenter> presenter,
                        QWidget *parent = 0);
+  QDataProcessorWidget(const DataProcessorWhiteList &, QWidget *parent);
   QDataProcessorWidget(const DataProcessorWhiteList &,
                        const DataProcessorProcessingAlgorithm &,
                        QWidget *parent);
@@ -134,6 +135,7 @@ public:
   QString getClipboard() const override;
 
   DataProcessorPresenter *getPresenter() const override;
+  QString getCurrentInstrument() const override;
 
   // Forward a main presenter to this view's presenter
   void accept(DataProcessorMainPresenter *);
@@ -141,6 +143,24 @@ public:
   // Force re-processing of rows
   void setForcedReProcessing(bool forceReProcessing) override;
 
+  // Get value in a cell
+  QString getCell(int row, int column, int parentRow = 0, int parentColumn = 0);
+  // Set value in a cell
+  void setCell(const QString &value, int row, int column, int parentRow = 0,
+               int parentColumn = 0);
+  int getNumberOfRows();
+  void clearTable();
+
+  // Methods to emit signals
+  void emitProcessClicked() override { emit processButtonClicked(); };
+
+  void emitProcessingFinished() override { emit processingFinished(); }
+
+signals:
+  void processButtonClicked();
+  void processingFinished();
+  void instrumentHasChanged();
+
 private:
   // initialise the interface
   void createTable();
diff --git a/qt/widgets/common/src/DataProcessorUI/DataProcessorOneLevelTreeManager.cpp b/qt/widgets/common/src/DataProcessorUI/DataProcessorOneLevelTreeManager.cpp
index d0429953db0a4dac8a5e57a2d4f84f4d987d2d9c..9e067308cb251b11108dc84f539f541cdaec4c09 100644
--- a/qt/widgets/common/src/DataProcessorUI/DataProcessorOneLevelTreeManager.cpp
+++ b/qt/widgets/common/src/DataProcessorUI/DataProcessorOneLevelTreeManager.cpp
@@ -511,5 +511,50 @@ bool DataProcessorOneLevelTreeManager::isValidModel(
   }
   return true;
 }
+
+/** Sets a value in a cell
+ *
+ * @param row : the row index
+ * @param column : the column index
+ * @param parentRow : the row index of the parent item (unused)
+ * @param parentColumn : the column index of the parent item (unused)
+ * @param value : the new value to populate the cell with
+*/
+void DataProcessorOneLevelTreeManager::setCell(int row, int column,
+                                               int parentRow, int parentColumn,
+                                               const std::string &value) {
+
+  UNUSED_ARG(parentRow);
+  UNUSED_ARG(parentColumn);
+
+  m_model->setData(m_model->index(row, column),
+                   QVariant(QString::fromStdString(value)));
+}
+
+/** Returns the value in a cell as a string
+ *
+ * @param row : the row index
+ * @param column : the column index
+ * @param parentRow : the row index of the parent item (unused)
+ * @param parentColumn : the column index of the parent item (unused)
+ * @return : the value in the cell as a string
+*/
+std::string DataProcessorOneLevelTreeManager::getCell(int row, int column,
+                                                      int parentRow,
+                                                      int parentColumn) {
+  UNUSED_ARG(parentRow);
+  UNUSED_ARG(parentColumn);
+
+  return m_model->data(m_model->index(row, column)).toString().toStdString();
+}
+
+/**
+ * Gets the number of rows.
+ * @return : the number of rows.
+ */
+int DataProcessorOneLevelTreeManager::getNumberOfRows() {
+  return m_model->rowCount();
+}
+
 }
 }
diff --git a/qt/widgets/common/src/DataProcessorUI/DataProcessorProcessingAlgorithm.cpp b/qt/widgets/common/src/DataProcessorUI/DataProcessorProcessingAlgorithm.cpp
index 0d8e9f945312a837036ad335c8fedac8c44be53b..391e2d757e233aa63fc9f59357df74af9c5fe592 100644
--- a/qt/widgets/common/src/DataProcessorUI/DataProcessorProcessingAlgorithm.cpp
+++ b/qt/widgets/common/src/DataProcessorUI/DataProcessorProcessingAlgorithm.cpp
@@ -47,6 +47,12 @@ DataProcessorProcessingAlgorithm::DataProcessorProcessingAlgorithm(
     : DataProcessorProcessingAlgorithm(name, convertStringToVector(prefix),
                                        convertStringToSet(blacklist)) {}
 
+/**
+ * Constructor
+*/
+DataProcessorProcessingAlgorithm::DataProcessorProcessingAlgorithm()
+    : m_prefix(), m_inputProperties(), m_outputProperties() {}
+
 // Destructor
 DataProcessorProcessingAlgorithm::~DataProcessorProcessingAlgorithm() {}
 
diff --git a/qt/widgets/common/src/DataProcessorUI/DataProcessorTwoLevelTreeManager.cpp b/qt/widgets/common/src/DataProcessorUI/DataProcessorTwoLevelTreeManager.cpp
index 69fea999a5602d1ff82f9e471d5bea23ac93013a..5ac26a01fdc7d54962f90e205e14d94a26729e94 100644
--- a/qt/widgets/common/src/DataProcessorUI/DataProcessorTwoLevelTreeManager.cpp
+++ b/qt/widgets/common/src/DataProcessorUI/DataProcessorTwoLevelTreeManager.cpp
@@ -719,5 +719,50 @@ bool DataProcessorTwoLevelTreeManager::isValidModel(
   }
   return true;
 }
+
+
+/** Sets a value in a cell
+ *
+ * @param row : the row index
+ * @param column : the column index
+ * @param parentRow : the row index of the parent item
+ * @param parentColumn : the column index of the parent item
+ * @param value : the new value to populate the cell with
+*/
+void DataProcessorTwoLevelTreeManager::setCell(int row, int column,
+                                               int parentRow, int parentColumn,
+                                               const std::string &value) {
+
+  m_model->setData(
+      m_model->index(row, column, m_model->index(parentRow, parentColumn)),
+      QVariant(QString::fromStdString(value)));
+}
+
+/** Returns the value in a cell as a string
+ *
+ * @param row : the row index
+ * @param column : the column index
+ * @param parentRow : the row index of the parent item (unused)
+ * @param parentColumn : the column index of the parent item (unused)
+ * @return : the value in the cell as a string
+*/
+std::string DataProcessorTwoLevelTreeManager::getCell(int row, int column,
+                                                      int parentRow,
+                                                      int parentColumn) {
+
+  return m_model->data(m_model->index(row, column,
+                                      m_model->index(parentRow, parentColumn)))
+      .toString()
+      .toStdString();
+}
+
+/**
+ * Get number of rows.
+ * @return the number of rows.
+ */
+int DataProcessorTwoLevelTreeManager::getNumberOfRows() {
+  return m_model->rowCount();
+}
+
 }
 }
diff --git a/qt/widgets/common/src/DataProcessorUI/GenericDataProcessorPresenter.cpp b/qt/widgets/common/src/DataProcessorUI/GenericDataProcessorPresenter.cpp
index d334b27de887d4b050aa36c42014d76ae1e2c505..bd7a06f676136e70faf3e63113a6c0d9a7866ed8 100644
--- a/qt/widgets/common/src/DataProcessorUI/GenericDataProcessorPresenter.cpp
+++ b/qt/widgets/common/src/DataProcessorUI/GenericDataProcessorPresenter.cpp
@@ -185,6 +185,17 @@ GenericDataProcessorPresenter::GenericDataProcessorPresenter(
           whitelist, std::map<QString, DataProcessorPreprocessingAlgorithm>(),
           processor, postprocessor) {}
 
+/**
+ * Delegating constructor (only whitelist specified)
+ * @param whitelist : The set of properties we want to show as columns
+ */
+GenericDataProcessorPresenter::GenericDataProcessorPresenter(
+    const DataProcessorWhiteList &whitelist)
+    : GenericDataProcessorPresenter(
+          whitelist, std::map<QString, DataProcessorPreprocessingAlgorithm>(),
+          DataProcessorProcessingAlgorithm(),
+          DataProcessorPostprocessingAlgorithm()) {}
+
 /**
 * Delegating constructor (no post-processing needed)
 * @param whitelist : The set of properties we want to show as columns
@@ -286,6 +297,8 @@ void GenericDataProcessorPresenter::acceptViews(
 Process selected data
 */
 void GenericDataProcessorPresenter::process() {
+  // Emit a signal hat the process is starting
+  m_view->emitProcessClicked();
 
   m_selectedData = m_manager->selectedData(m_promptUser);
 
@@ -1429,6 +1442,8 @@ void GenericDataProcessorPresenter::setInstrumentList(
 
 /** Plots any currently selected rows */
 void GenericDataProcessorPresenter::plotRow() {
+  if (m_processor.name().isEmpty())
+    return;
 
   // Set of workspaces to plot
   QOrderedSet<QString> workspaces;
@@ -1471,6 +1486,8 @@ void GenericDataProcessorPresenter::issueNotFoundWarning(
 
 /** Plots any currently selected groups */
 void GenericDataProcessorPresenter::plotGroup() {
+  if (m_processor.name().isEmpty())
+    return;
 
   // This method shouldn't be called if a post-processing algorithm is not
   // defined
@@ -1745,5 +1762,49 @@ void GenericDataProcessorPresenter::setForcedReProcessing(
     bool forceReProcessing) {
   m_forceProcessing = forceReProcessing;
 }
+
+/** Set a value in the table
+ *
+ * @param row : the row index
+ * @param column : the column index
+ * @param parentRow : the row index of the parent item
+ * @param parentColumn : the column index of the parent item
+ * @param value : the new value
+*/
+void GenericDataProcessorPresenter::setCell(int row, int column, int parentRow,
+                                            int parentColumn,
+                                            const std::string &value) {
+
+  m_manager->setCell(row, column, parentRow, parentColumn, value);
+}
+
+/** Gets a cell from the table
+ *
+ * @param row : the row index
+ * @param column : the column index
+ * @param parentRow : the row index of the parent item
+ * @param parentColumn : the column index of the parent item
+ * @return : the value in the cell
+*/
+std::string GenericDataProcessorPresenter::getCell(int row, int column,
+                                                   int parentRow,
+                                                   int parentColumn) {
+
+  return m_manager->getCell(row, column, parentRow, parentColumn);
+}
+
+/**
+ * Gets the number of rows.
+ * @return : the number of rows.
+ */
+int GenericDataProcessorPresenter::getNumberOfRows() {
+  return m_manager->getNumberOfRows();
+}
+
+/**
+  * Clear the table
+ **/
+void GenericDataProcessorPresenter::clearTable() { m_manager->deleteRow(); }
+
 }
 }
diff --git a/qt/widgets/common/src/DataProcessorUI/QDataProcessorWidget.cpp b/qt/widgets/common/src/DataProcessorUI/QDataProcessorWidget.cpp
index cec914b41898350871e32f1ed41f81e9256543ff..b522f3b1cbcc9a59829561e64a4aeccb6398edfb 100644
--- a/qt/widgets/common/src/DataProcessorUI/QDataProcessorWidget.cpp
+++ b/qt/widgets/common/src/DataProcessorUI/QDataProcessorWidget.cpp
@@ -32,6 +32,17 @@ QDataProcessorWidget::QDataProcessorWidget(
   m_presenter->acceptViews(this, this);
 }
 
+/** Delegating constructor
+ * @param whitelist :: [input] The white list
+ * @param parent :: [input] The parent of this view
+ */
+QDataProcessorWidget::QDataProcessorWidget(
+    const DataProcessorWhiteList &whitelist, QWidget *parent)
+    : QDataProcessorWidget(
+          Mantid::Kernel::make_unique<GenericDataProcessorPresenter>(whitelist),
+          parent) {}
+
+
 /** Delegating constructor
 * @param whitelist :: [input] The white list
 * @param algorithm :: [input] The processing algorithm
@@ -209,6 +220,7 @@ void QDataProcessorWidget::setTableList(const QSet<QString> &tables) {
 void QDataProcessorWidget::on_comboProcessInstrument_currentIndexChanged(
     int index) {
   ui.comboProcessInstrument->setCurrentIndex(index);
+  emit instrumentHasChanged();
 }
 
 /**
@@ -418,6 +430,7 @@ void QDataProcessorWidget::setInstrumentList(const QString &instruments,
   int index =
       ui.comboProcessInstrument->findData(defaultInstrument, Qt::DisplayRole);
   ui.comboProcessInstrument->setCurrentIndex(index);
+  emit instrumentHasChanged();
 }
 
 /**
@@ -614,9 +627,58 @@ void QDataProcessorWidget::transfer(const QList<QString> &runs) {
   m_presenter->transfer(runsMap);
 }
 
+/** Get a cell from the table
+ *
+ * @param row : the row index
+ * @param column : the column index
+ * @param parentRow : the row index of the parent
+ * @param parentColumn : the row index of the parent
+ * @return : the value in the cell as a string
+*/
+QString QDataProcessorWidget::getCell(int row, int column, int parentRow,
+                                      int parentColumn) {
+
+  return QString::fromStdString(
+      m_presenter->getCell(row, column, parentRow, parentColumn));
+}
+
+/** Set a value in the table
+ *
+ * @param value : the new value
+ * @param row : the row index
+ * @param column : the column index
+ * @param parentRow : the row index of the parent
+ * @param parentColumn : the row index of the parent
+*/
+void QDataProcessorWidget::setCell(const QString &value, int row, int column,
+                                   int parentRow, int parentColumn) {
+
+  m_presenter->setCell(row, column, parentRow, parentColumn,
+                       value.toStdString());
+}
+
+int QDataProcessorWidget::getNumberOfRows() {
+  return m_presenter->getNumberOfRows();
+}
+
+void QDataProcessorWidget::clearTable() {
+  const auto numberOfRows = getNumberOfRows();
+  std::set<int> groups;
+  for (int index = 0; index < numberOfRows; ++index) {
+    groups.insert(groups.end(), index);
+  }
+  setSelection(groups);
+  m_presenter->clearTable();
+}
+
+
 void QDataProcessorWidget::setForcedReProcessing(bool forceReProcessing) {
   m_presenter->setForcedReProcessing(forceReProcessing);
 }
 
+QString QDataProcessorWidget::getCurrentInstrument() const {
+  return ui.comboProcessInstrument->currentText();
+}
+
 } // namespace MantidWidgets
 } // namespace Mantid
diff --git a/qt/widgets/sliceviewer/test/CMakeLists.txt b/qt/widgets/sliceviewer/test/CMakeLists.txt
index 88e1b728830cde65fab0d2c3e5cee8b92b8be5d7..766fef8747760402fc5b49cddbf33b4f27182fa2 100644
--- a/qt/widgets/sliceviewer/test/CMakeLists.txt
+++ b/qt/widgets/sliceviewer/test/CMakeLists.txt
@@ -16,7 +16,6 @@ if ( CXXTEST_FOUND )
     target_link_libraries( SliceViewerTest LINK_PRIVATE ${TCMALLOC_LIBRARIES_LINKTIME}
             SliceViewer
             Crystal
-            MantidQtAPI
             API
             DataObjects
             Geometry
diff --git a/scripts/Calibration/Examples/TubeCalibDemoMaps_All.py b/scripts/Calibration/Examples/TubeCalibDemoMaps_All.py
index cda7cc19a66fe3c5bd9b00d922264f7caefe6b92..524b4c95fe1b27c799fbabd5f613b2df4c947b23 100644
--- a/scripts/Calibration/Examples/TubeCalibDemoMaps_All.py
+++ b/scripts/Calibration/Examples/TubeCalibDemoMaps_All.py
@@ -52,6 +52,8 @@ Calibration technique: Finding tubes not well calibrated
 
 """
 
+from __future__ import absolute_import, division, print_function
+
 import mantid.simpleapi as mantid
 import tube
 import numpy
@@ -500,8 +502,8 @@ def completeCalibration(filename):
     mantid.ApplyCalibration(Workspace=CalibInstWS, PositionTable=calibrationTable)
 
     # == Save workspace ==
-    # SaveNexusProcessed( CalibInstWS, path+'TubeCalibDemoMapsResult.nxs',"Result of Running TCDemoMaps.py")
-    # print "saved calibrated workspace (CalibInstWS) into Nexus file TubeCalibDemoMapsResult.nxs"
+    # mantid.SaveNexusProcessed(CalibInstWS, path+'TubeCalibDemoMapsResult.nxs', "Result of Running TCDemoMaps.py")
+    # print("saved calibrated workspace (CalibInstWS) into Nexus file TubeCalibDemoMapsResult.nxs")
 
 
 ####
diff --git a/scripts/Calibration/Examples/TubeCalibDemoMaps_B1.py b/scripts/Calibration/Examples/TubeCalibDemoMaps_B1.py
index 37a02fa1e3e6d709f086607a7f1f19f4b86e3873..15c1a6142dda307120ed79a7f54105fcb75095e1 100644
--- a/scripts/Calibration/Examples/TubeCalibDemoMaps_B1.py
+++ b/scripts/Calibration/Examples/TubeCalibDemoMaps_B1.py
@@ -4,7 +4,8 @@
 #
 # Here we run the calibration of a selected part of MAPS
 
-#
+from __future__ import absolute_import, division, print_function
+
 import tube
 from tube_calib_fit_params import TubeCalibFitParams
 import mantid.simpleapi as mantid
diff --git a/scripts/Calibration/Examples/TubeCalibDemoMaps_C4C3.py b/scripts/Calibration/Examples/TubeCalibDemoMaps_C4C3.py
index 493a8207be9ea0296fec99a244ad2979d283e877..65e4a5ec8dd49c6d83ad197a51a6be4dee6cafec 100644
--- a/scripts/Calibration/Examples/TubeCalibDemoMaps_C4C3.py
+++ b/scripts/Calibration/Examples/TubeCalibDemoMaps_C4C3.py
@@ -5,13 +5,12 @@
 # Here we run the calibration of a selected part of MAPS consisting of several components
 # by running setTubeSpecByString several times.
 
-#
+from __future__ import absolute_import, division, print_function
+
 import tube
 from tube_spec import TubeSpec
 import mantid.simpleapi as mantid
 
-# from tube_calib_fit_params import  # To handle fit parameters
-
 
 # == Set parameters for calibration ==
 
@@ -54,5 +53,5 @@ mantid.ApplyCalibration(Workspace=CalibInstWS, PositionTable=calibrationTable)
 print("Applied calibration")
 
 # == Save workspace ==
-# SaveNexusProcessed( CalibInstWS, path+'TubeCalibDemoMapsResult.nxs',"Result of Running TCDemoMaps.py")
-print("saved calibrated workspace (CalibInstWS) into Nexus file TubeCalibDemoMapsResult.nxs")
+# mantid.SaveNexusProcessed(CalibInstWS, path+'TubeCalibDemoMapsResult.nxs', "Result of Running TCDemoMaps.py")
+# print("saved calibrated workspace (CalibInstWS) into Nexus file TubeCalibDemoMapsResult.nxs")
diff --git a/scripts/Calibration/Examples/TubeCalibDemoMaps_C4C3C2.py b/scripts/Calibration/Examples/TubeCalibDemoMaps_C4C3C2.py
index 916de7b178c4374b3be97742a9af00adb74eda00..a234317ce54673e3324aba0b3b0508be0d127c00 100644
--- a/scripts/Calibration/Examples/TubeCalibDemoMaps_C4C3C2.py
+++ b/scripts/Calibration/Examples/TubeCalibDemoMaps_C4C3C2.py
@@ -5,6 +5,8 @@
 # Here we run the calibration of a selected part of MAPS consisting of several components
 # specifying them in an array of strings.
 
+from __future__ import absolute_import, division, print_function
+
 import tube
 import mantid.simpleapi as mantid
 
@@ -44,5 +46,5 @@ mantid.ApplyCalibration(Workspace=CalibInstWS, PositionTable=calibrationTable)
 print("Applied calibration")
 
 # == Save workspace ==
-# SaveNexusProcessed( CalibInstWS, path+'TubeCalibDemoMapsResult.nxs',"Result of Running TCDemoMaps.py")
-print("saved calibrated workspace (CalibInstWS) into Nexus file TubeCalibDemoMapsResult.nxs")
+# mantid.SaveNexusProcessed(CalibInstWS, path+'TubeCalibDemoMapsResult.nxs', "Result of Running TCDemoMaps.py")
+# print("saved calibrated workspace (CalibInstWS) into Nexus file TubeCalibDemoMapsResult.nxs")
diff --git a/scripts/Calibration/Examples/TubeCalibDemoMaps_D2.py b/scripts/Calibration/Examples/TubeCalibDemoMaps_D2.py
index a59232d971d617dc1d1df65238335c270acaf0e6..5a638f55f1ea22edab84a105051d571a1c445321 100644
--- a/scripts/Calibration/Examples/TubeCalibDemoMaps_D2.py
+++ b/scripts/Calibration/Examples/TubeCalibDemoMaps_D2.py
@@ -4,7 +4,8 @@
 #
 # Here we run the calibration of a selected part of MAPS
 
-#
+from __future__ import absolute_import, division, print_function
+
 import tube
 from tube_calib_fit_params import TubeCalibFitParams
 import mantid.simpleapi as mantid
@@ -53,5 +54,5 @@ mantid.ApplyCalibration(Workspace=CalibInstWS, PositionTable=calibrationTable)
 print("Applied calibration")
 
 # == Save workspace ==
-# SaveNexusProcessed( CalibInstWS, 'TubeCalibDemoMapsResult.nxs',"Result of Running TCDemoMaps.py")
-# print "saved calibrated workspace (CalibInstWS) into Nexus file TubeCalibDemoMapsResult.nxs"
+# mantid.SaveNexusProcessed(CalibInstWS, 'TubeCalibDemoMapsResult.nxs', "Result of Running TCDemoMaps.py")
+# print("saved calibrated workspace (CalibInstWS) into Nexus file TubeCalibDemoMapsResult.nxs")
diff --git a/scripts/Calibration/Examples/TubeCalibDemoMaps_D2_WideMargins.py b/scripts/Calibration/Examples/TubeCalibDemoMaps_D2_WideMargins.py
index a5a42ac3e0e2ff7c8a1fbac3456e83f893338502..8d1364489e0df678020e9d5c950fab74d68e41ec 100644
--- a/scripts/Calibration/Examples/TubeCalibDemoMaps_D2_WideMargins.py
+++ b/scripts/Calibration/Examples/TubeCalibDemoMaps_D2_WideMargins.py
@@ -4,7 +4,8 @@
 #
 # Here we run the calibration of a selected part of MAPS
 
-#
+from __future__ import absolute_import, division, print_function
+
 import tube
 import mantid.simpleapi as mantid
 
@@ -42,5 +43,5 @@ print("Applied calibration")
 
 
 # == Save workspace ==
-# SaveNexusProcessed( CalibInstWS, path+'TubeCalibDemoMapsResult.nxs',"Result of Running TCDemoMaps.py")
-# print "saved calibrated workspace (CalibInstWS) into Nexus file TubeCalibDemoMapsResult.nxs"
+# mantid.SaveNexusProcessed(CalibInstWS, path+'TubeCalibDemoMapsResult.nxs', "Result of Running TCDemoMaps.py")
+# print("saved calibrated workspace (CalibInstWS) into Nexus file TubeCalibDemoMapsResult.nxs")
diff --git a/scripts/Calibration/Examples/TubeCalibDemoMaps_D4.py b/scripts/Calibration/Examples/TubeCalibDemoMaps_D4.py
index fb89634c6cd1655365e5748e352e38daedfa0e39..bab3431cb800df735a5f8e55cdf8c80f50823535 100644
--- a/scripts/Calibration/Examples/TubeCalibDemoMaps_D4.py
+++ b/scripts/Calibration/Examples/TubeCalibDemoMaps_D4.py
@@ -4,7 +4,8 @@
 #
 # Here we run the calibration of a selected part of MAPS
 
-#
+from __future__ import absolute_import, division, print_function
+
 import tube
 from tube_calib_fit_params import TubeCalibFitParams
 import mantid.simpleapi as mantid
@@ -53,5 +54,5 @@ print("Applied calibration")
 
 
 # == Save workspace ==
-mantid.SaveNexusProcessed( CalibInstWS, 'TubeCalibDemoMapsResult.nxs',"Result of Running TCDemoMaps.py")
+mantid.SaveNexusProcessed(CalibInstWS, 'TubeCalibDemoMapsResult.nxs',"Result of Running TCDemoMaps.py")
 print("saved calibrated workspace (CalibInstWS) into Nexus file TubeCalibDemoMapsResult.nxs")
diff --git a/scripts/Calibration/Examples/TubeCalibDemoMerlin.py b/scripts/Calibration/Examples/TubeCalibDemoMerlin.py
index aa7eeabfd432d0662121e4e3d01ecad45ab71ac4..79b467a4ab9ff27b9e94a99664fee8947ebb0cdb 100644
--- a/scripts/Calibration/Examples/TubeCalibDemoMerlin.py
+++ b/scripts/Calibration/Examples/TubeCalibDemoMerlin.py
@@ -42,6 +42,9 @@ The previous calibrated instrument view:
 
 .. sectionauthor:: Gesner Passos - ISIS
 """
+
+from __future__ import absolute_import, division, print_function
+
 import numpy
 import mantid.simpleapi as mantid
 import tube
@@ -149,7 +152,8 @@ def calibrateMerlin(filename):
     CalibratedComponent = ['MERLIN/door3/tube_1_%d' % (i) for i in range(1, 9)]
 
     half_diff_center = (
-                           2.92713867188 - 1.22879882813) / 2  # difference among the expected center position for
+                           2.92713867188 - 1.22879882813) / 2
+    # difference among the expected center position for
     # both tubes here a little bit of attempts is necessary.
     # The effective center position and lengh is different for the calibrated tube, that is the reason,
     # the calibrated values of the smaller tube does not seems aligned with the others. By, finding the
@@ -174,11 +178,10 @@ def calibrateMerlin(filename):
     analisePeakTable(peakTable, 'door3_tube1_peaks')
 
     # calibrating tubes 2_x
-    CalibratedComponent = ['MERLIN/door3/tube_2_%d' % (i) for i in range(1, 9)]
+    CalibratedComponent = ['MERLIN/door3/tube_2_%d' % (i) for i in range(1,9)]
     # the knownpositions were given with the center of the bigger tube as origin, to convert
     # to the center of the lower tube as origin is necessary to sum them with  (len_big - len_small)/2
     doorpos = knownPositions[[0, 1, 2, 3]] + half_diff_center
-    # print doorpos
     doorfunc = [2, 2, 1, 1]
 
     # for the smal tubes, automatically searching for the peak position in pixel was not working quite well,
@@ -226,8 +229,8 @@ def calibrateMerlin(filename):
     print("Applied calibration")
 
     # == Save workspace ==
-    # SaveNexusProcessed( CalibInstWS, 'TubeCalibDemoMerlinResult.nxs',"Result of Running TCDemoMerlin.py")
-    # print "saved calibrated workspace (CalibInstWS) into Nexus file TubeCalibDemoMerlinResult.nxs"
+    # mantid.SaveNexusProcessed(CalibInstWS, 'TubeCalibDemoMerlinResult.nxs', "Result of Running TCDemoMerlin.py")
+    # print("saved calibrated workspace (CalibInstWS) into Nexus file TubeCalibDemoMerlinResult.nxs")
 
 
 if __name__ == "__main__":
diff --git a/scripts/Calibration/Examples/TubeCalibDemoMerlin_Simple.py b/scripts/Calibration/Examples/TubeCalibDemoMerlin_Simple.py
index a7ab13a619276a9dca00095ef3c81543cdf7ccb2..4f1e0a43020aa42a11a37520637314390b081d62 100644
--- a/scripts/Calibration/Examples/TubeCalibDemoMerlin_Simple.py
+++ b/scripts/Calibration/Examples/TubeCalibDemoMerlin_Simple.py
@@ -12,6 +12,8 @@
 # The workspace with calibrated instrument is saved to a Nexus file
 #
 
+from __future__ import absolute_import, division, print_function
+
 import tube
 from tube_calib_fit_params import TubeCalibFitParams
 import numpy
@@ -81,8 +83,8 @@ def CalibrateMerlin(RunNumber):
     print("Applied calibration")
 
     # == Save workspace ==
-    # SaveNexusProcessed( CalibInstWS, 'TubeCalibDemoMerlinResult.nxs',"Result of Running TubeCalibDemoMerlin_Simple.py")
-    # print "saved calibrated workspace (CalibInstWS) into Nexus file TubeCalibDemoMerlinResult.nxs"
+    # mantid.SaveNexusProcessed(CalibInstWS, 'TubeCalibDemoMerlinResult.nxs', "Result of Running TubeCalibDemoMerlin_Simple.py")
+    # print("saved calibrated workspace (CalibInstWS) into Nexus file TubeCalibDemoMerlinResult.nxs")
 
     # == Reset dafault instrument ==
     mantid.config['default.instrument'] = previousDefaultInstrument
diff --git a/scripts/Calibration/Examples/TubeCalibDemoWish0.py b/scripts/Calibration/Examples/TubeCalibDemoWish0.py
index 79607d0f2ef11682b7b37bfb48047625aa47676a..e7473e6f7fb6c0758e193fa960d15f292ba44e4c 100644
--- a/scripts/Calibration/Examples/TubeCalibDemoWish0.py
+++ b/scripts/Calibration/Examples/TubeCalibDemoWish0.py
@@ -9,6 +9,8 @@
 #  because we do not consider the upper and lower position of the tubes around the
 # WISH instrument.
 #
+from __future__ import absolute_import, division, print_function
+
 import tube
 import mantid.simpleapi as mantid
 
@@ -31,5 +33,5 @@ calibrationTable = tube.calibrate(CalibInstWS, CalibratedComponent,
 print("Got calibration (new positions of detectors)")
 
 #Apply the calibration
-mantid.ApplyCalibration( Workspace=CalibInstWS, PositionTable=calibrationTable)
+mantid.ApplyCalibration(Workspace=CalibInstWS, PositionTable=calibrationTable)
 print("Applied calibration")
diff --git a/scripts/Calibration/Examples/TubeCalibDemoWish1.py b/scripts/Calibration/Examples/TubeCalibDemoWish1.py
index 43185f51137ac67585e055973984b3c35af8c81a..6124f18d1678ac7977ffd9557e8bd70a8038e05e 100644
--- a/scripts/Calibration/Examples/TubeCalibDemoWish1.py
+++ b/scripts/Calibration/Examples/TubeCalibDemoWish1.py
@@ -5,6 +5,9 @@
 # Here we run the calibration of WISH panel03
 # We base the ideal tube on one tube of this door.
 #
+
+from __future__ import absolute_import, division, print_function
+
 import tube
 reload(tube) # noqa
 from tube_spec import TubeSpec
@@ -42,5 +45,5 @@ calibrationTable = tube.calibrate( CalibInstWS, 'WISH/panel03', known_pos, func_
 print("Got calibration (new positions of detectors)")
 
 #Apply the calibration
-mantid.ApplyCalibration( Workspace=CalibInstWS, PositionTable=calibrationTable)
+mantid.ApplyCalibration(Workspace=CalibInstWS, PositionTable=calibrationTable)
 print("Applied calibration")
diff --git a/scripts/Calibration/Examples/TubeCalibDemoWish_5panels.py b/scripts/Calibration/Examples/TubeCalibDemoWish_5panels.py
index ce40f500fa8628115d0378736d5dbdfabb66117e..14523f734cc94782ec90517c36b71f920ca71ecb 100644
--- a/scripts/Calibration/Examples/TubeCalibDemoWish_5panels.py
+++ b/scripts/Calibration/Examples/TubeCalibDemoWish_5panels.py
@@ -11,6 +11,9 @@ This examples show how you can use these runs to produce a single calibration ta
 to calibrate the whole instrument.
 
 """
+
+from __future__ import absolute_import, division, print_function
+
 import numpy
 import mantid.simpleapi as mantid
 
diff --git a/scripts/Calibration/Examples/TubeCalibDemoWish_Simple.py b/scripts/Calibration/Examples/TubeCalibDemoWish_Simple.py
index 48bda575fbeb7af16024f262a1846a6e68e953cd..f403d36b3a5941a5474bd65130f45c72effec736 100644
--- a/scripts/Calibration/Examples/TubeCalibDemoWish_Simple.py
+++ b/scripts/Calibration/Examples/TubeCalibDemoWish_Simple.py
@@ -4,6 +4,9 @@
 #
 # Here we run the calibration of WISH panel03 using a simple CalibrateWish function.
 #
+
+from __future__ import absolute_import, division, print_function
+
 import numpy
 import tube
 import mantid.simpleapi as mantid
@@ -58,9 +61,9 @@ def CalibrateWish(RunNumber, PanelNumber):
 
     # == Save workspace ==
     # uncomment these lines to save the workspace
-    # nexusName = "TubeCalibDemoWish"+PanelNumber+"Result.nxs"
-    # SaveNexusProcessed( CalibInstWS, 'TubeCalibDemoWishResult.nxs',"Result of Running TubeCalibWishMerlin_Simple.py")
-    # print "saved calibrated workspace (CalibInstWS) into Nexus file",nexusName
+    # nexusName = "TubeCalibDemoWish" + PanelNumber + "Result.nxs"
+    # mantid.SaveNexusProcessed(CalibInstWS, 'TubeCalibDemoWishResult.nxs', "Result of Running TubeCalibWishMerlin_Simple.py")
+    # print("saved calibrated workspace (CalibInstWS) into Nexus file", nexusName)
 
     # == Reset dafault instrument ==
     mantid.config['default.instrument'] = previousDefaultInstrument
diff --git a/scripts/Calibration/tube.py b/scripts/Calibration/tube.py
index 67a32da528f8bac34b5e1358e63de31ba938ed29..f1ecadbad68f4a19b1071ff5c0bed60126fd3a1c 100644
--- a/scripts/Calibration/tube.py
+++ b/scripts/Calibration/tube.py
@@ -1,4 +1,7 @@
 # pylint: disable=invalid-name
+
+from __future__ import absolute_import, division, print_function
+
 import numpy
 import os
 import re
@@ -652,7 +655,7 @@ def savePeak(peakTable, filePath):
         row = peakTable.row(line)
         peak_values = [row[k] for k in peaksNames]
         tube_name = row['TubeId'].replace(' ', '%20')
-        print >> pFile, tube_name, peak_values
+        print(tube_name, peak_values, file = pFile)
 
     pFile.close()
 
@@ -668,8 +671,8 @@ def readPeakFile(file_name):
     .. code-block:: python
 
        for (det_code, cal_values) in readPeakFile('pathname/TubeDemo'):
-          print det_code
-          print cal_values
+          print(det_code)
+          print(cal_values)
 
     :param file_name: Path for the file
     :rtype: list of tuples(det_code, peaks_values)
@@ -691,8 +694,6 @@ def readPeakFile(file_name):
         try:
             f_values = [float(v) for v in line_vals[1:] if v != '']
         except ValueError:
-            # print 'Wrong format: we expected only numbers,
-            # but receive this line ',str(line_vals[1:])
             continue
 
         loaded_file.append((id_, f_values))
@@ -841,7 +842,7 @@ def correctMisalignedTubes(ws, calibrationTable, peaksTable, spec, idealTube,
     mean_peaks, bad_tubes = findBadPeakFits(peaksTable, threshold)
 
     for index in bad_tubes:
-        print "Refitting tube %s" % spec.getTubeName(index)
+        print("Refitting tube %s" % spec.getTubeName(index))
         tube_dets, _ = spec.getTube(index)
         getPoints(ws, idealTube.getFunctionalForms(), fitPar, tube_dets)
         tube_ws = mtd['TubePlot']
diff --git a/scripts/Calibration/tube_calib.py b/scripts/Calibration/tube_calib.py
index 77e7c45152b1e1ae0fe9419cfa46d538125a0192..ae16b409cd60e4865d0bcfe765b3bcc625ea1a0b 100644
--- a/scripts/Calibration/tube_calib.py
+++ b/scripts/Calibration/tube_calib.py
@@ -11,6 +11,7 @@ Users should not need to directly call any other function other than :func:`getC
 """
 ## Author: Karl palmen ISIS and for readPeakFile Gesner Passos ISIS
 
+from __future__ import absolute_import, division, print_function
 
 import numpy
 from mantid.simpleapi import *
@@ -80,12 +81,10 @@ def get_ypos(work_handle,pixel_float):
 
 
 def fitGaussianParams ( height, centre, sigma ): # Compose string argument for fit
-    #print "name=Gaussian, Height="+str(height)+", PeakCentre="+str(centre)+", Sigma="+str(sigma)
     return "name=Gaussian, Height="+str(height)+", PeakCentre="+str(centre)+", Sigma="+str(sigma)
 
 
 def fitEndErfcParams ( B, C ): # Compose string argument for fit
-    #print "name=EndErfc, B="+str(B)+", C="+str(C)
     return "name=EndErfc, B="+str(B)+", C="+str(C)
 
 #
@@ -249,12 +248,9 @@ def getIdealTubeFromNSlits ( IntegratedWorkspace, slits ):
 
     """
     ideal = []
-    # print "slits for ideal tube", slits
     for i in range(len(slits)):
-        # print slits[i]
         ideal.append( get_ypos( IntegratedWorkspace, slits[i] )) # Use Pascal Manuel's Y conversion.
 
-    # print "Ideal Tube",ideal
     return ideal
 
 
@@ -287,7 +283,6 @@ def correctTube( AP, BP, CP, nDets ):
         xo = x[i]
         xBinNew.append( xo + ( xo*(nDets-xo)*GainError )) #Final bin position values corrected for offsets and gain
 
-    # print xBinNew
     return xBinNew
 
 
@@ -307,11 +302,9 @@ def correctTubeToIdealTube( tubePoints, idealTubePoints, nDets, TestMode=False,
        Note that any element of tubePoints not between 0.0 and nDets is considered a rogue point and so is ignored.
     """
 
-    #print "correctTubeToIdealTube"
-
     # Check the arguments
     if  len(tubePoints) != len(idealTubePoints) :
-        print "Number of points in tube", len(tubePoints),"must equal number of points in ideal tube", len(idealTubePoints)
+        print("Number of points in tube", len(tubePoints),"must equal number of points in ideal tube", len(idealTubePoints))
         return xResult
 
     # Filter out rogue slit points
@@ -327,11 +320,11 @@ def correctTubeToIdealTube( tubePoints, idealTubePoints, nDets, TestMode=False,
 
     # State number of rogue slit points, if any
     if  len(tubePoints) != len(usedTubePoints):
-        print "Only",len(usedTubePoints),"out of",len(tubePoints)," slit points used. Missed",missedTubePoints
+        print("Only",len(usedTubePoints),"out of",len(tubePoints)," slit points used. Missed",missedTubePoints)
 
     # Check number of usable points
     if  len(usedTubePoints) < 3:
-        print "Too few usable points in tube",len(usedTubePoints)
+        print("Too few usable points in tube",len(usedTubePoints))
         return []
 
     # Fit quadratic to ideal tube points
@@ -339,7 +332,7 @@ def correctTubeToIdealTube( tubePoints, idealTubePoints, nDets, TestMode=False,
     try:
         Fit(InputWorkspace="PolyFittingWorkspace",Function='name=Polynomial,n=%d'%(polinFit),StartX=str(0.0),EndX=str(nDets),Output="QF")
     except:
-        print "Fit failed"
+        print("Fit failed")
         return []
 
     paramQF = mtd['QF_Parameters']
@@ -354,12 +347,10 @@ def correctTubeToIdealTube( tubePoints, idealTubePoints, nDets, TestMode=False,
     # In test mode, shove the pixels that are closest to the reckoned peaks
     # to the position of the first detector so that the resulting gaps can be seen.
     if  TestMode :
-        print "TestMode code"
+        print("TestMode code")
         for i in range( len(usedTubePoints) ):
-           #print "used point",i,"shoving pixel",int(usedTubePoints[i])
             xResult[ int(usedTubePoints[i]) ] = xResult[0]
 
-    # print xResult
     return xResult
 
 
@@ -389,9 +380,8 @@ def getCalibratedPixelPositions( ws, tubePts, idealTubePts, whichTube, peakTestM
 
     # Correct positions of detectors in tube by quadratic fit
     pixels = correctTubeToIdealTube ( tubePts, idealTubePts, nDets, TestMode=peakTestMode, polinFit=polinFit )
-    #print pixels
     if  len(pixels) != nDets:
-        print "Tube correction failed."
+        print("Tube correction failed.")
         return detIDs, detPositions
     baseInstrument = ws.getInstrument().getBaseInstrument()
     # Get tube unit vector
@@ -403,7 +393,7 @@ def getCalibratedPixelPositions( ws, tubePts, idealTubePts, whichTube, peakTestM
     ## identical to norm of vector: |dNpos - d0pos|
     tubeLength = det0.getDistance(detN)
     if  tubeLength <= 0.0:
-        print "Zero length tube cannot be calibrated, calibration failed."
+        print("Zero length tube cannot be calibrated, calibration failed.")
         return detIDs, detPositions
     #unfortunatelly, the operation '/' is not defined in V3D object, so
     #I have to use the multiplication.
@@ -423,7 +413,6 @@ def getCalibratedPixelPositions( ws, tubePts, idealTubePts, whichTube, peakTestM
 
         detIDs.append( deti.getID() )
         detPositions.append( newPos )
-        # print i, detIDs[i], detPositions[i]
 
     return detIDs, detPositions
 
@@ -436,8 +425,8 @@ def readPeakFile(file_name):
 
     Example of usage:
         for (det_code, cal_values) in readPeakFile('pathname/TubeDemo'):
-            print det_code
-            print cal_values
+            print(det_code)
+            print(cal_values)
 
     """
     loaded_file = []
@@ -461,7 +450,6 @@ def readPeakFile(file_name):
         try:
             f_values = [float(v) for v in line_vals[1:] if v!='']
         except ValueError:
-            #print 'Wrong format: we expected only numbers, but receive this line ',str(line_vals[1:])
             continue
 
         loaded_file.append((id_,f_values))
@@ -496,7 +484,7 @@ def getCalibration( ws, tubeSet, calibTable, fitPar, iTube, peaksTable,
     This is the main method called from :func:`~tube.calibrate` to perform the calibration.
     """
     nTubes = tubeSet.getNumTubes()
-    print "Number of tubes =",nTubes
+    print("Number of tubes =",nTubes)
 
     if rangeList is None:
         rangeList = range(nTubes)
@@ -509,9 +497,9 @@ def getCalibration( ws, tubeSet, calibTable, fitPar, iTube, peaksTable,
         wht, skipped = tubeSet.getTube(i)
         all_skipped.update(skipped)
 
-        print "Calibrating tube", i+1,"of",nTubes, tubeSet.getTubeName(i)
+        print("Calibrating tube", i+1,"of",nTubes, tubeSet.getTubeName(i))
         if  len(wht) < 1 :
-            print "Unable to get any workspace indices (spectra) for this tube. Tube",tubeSet.getTubeName(i),"not calibrated."
+            print("Unable to get any workspace indices (spectra) for this tube. Tube",tubeSet.getTubeName(i),"not calibrated.")
            #skip this tube
             continue
 
@@ -550,7 +538,7 @@ def getCalibration( ws, tubeSet, calibTable, fitPar, iTube, peaksTable,
                 calibTable.addRow ( nextRow )
 
     if len(all_skipped) > 0:
-        print "%i histogram(s) were excluded from the calibration since they did not have an assigned detector." % len(all_skipped)
+        print("%i histogram(s) were excluded from the calibration since they did not have an assigned detector." % len(all_skipped))
 
     # Delete temporary workspaces used in the calibration
     for ws_name in ('TubePlot','CalibPoint_NormalisedCovarianceMatrix',
@@ -581,7 +569,7 @@ def getCalibrationFromPeakFile ( ws, calibTable, iTube,  PeakFile ):
     # Read Peak File
     PeakArray = readPeakFile( PeakFile )
     nTubes = len(PeakArray)
-    print "Number of tubes read from file =",nTubes
+    print("Number of tubes read from file =",nTubes)
 
     for i in range(nTubes):
 
@@ -592,14 +580,13 @@ def getCalibrationFromPeakFile ( ws, calibTable, iTube,  PeakFile ):
         actualTube = PeakArray[i][1] # e.g.  [2.0, 512.5, 1022.0]
 
         wht, _ = tube.getTube(0)
-        print "Calibrating tube", i+1 ,"of", nTubes, TubeName #, " length", tubeSet.getTubeLength(i)
+        print("Calibrating tube", i+1 ,"of", nTubes, TubeName)
         if  len(wht) < 1 :
-            print "Unable to get any workspace indices for this tube. Calibration abandoned."
+            print("Unable to get any workspace indices for this tube. Calibration abandoned.")
             return
 
         detIDList, detPosList = getCalibratedPixelPositions( ws, actualTube, idealTube, wht)
 
-        #print len(wht)
         if  len(detIDList) == len(wht): # We have corrected positions
             for j in range(len(wht)):
                 nextRow = {'Detector ID': detIDList[j], 'Detector Position': detPosList[j] }
@@ -634,10 +621,9 @@ def constructIdealTubeFromRealTube( ws, tube, fitPar, funcForm ):
     if nTubes < 1:
         raise RuntimeError("Invalid tube specification received by constructIdealTubeFromRealTube")
     elif nTubes > 1:
-        print "Specification has several tubes. The ideal tube will be based on the first tube",tube.getTubeName(0)
+        print("Specification has several tubes. The ideal tube will be based on the first tube",tube.getTubeName(0))
 
     wht, _ = tube.getTube(0)
-   # print wht
 
    # Check tube
     if  len(wht) < 1 :
@@ -645,7 +631,7 @@ def constructIdealTubeFromRealTube( ws, tube, fitPar, funcForm ):
 
    # Get actual tube on which ideal tube is based
     actualTube = getPoints ( ws, funcForm, fitPar, wht)
-    print "Actual tube that ideal tube is to be based upon",actualTube
+    print("Actual tube that ideal tube is to be based upon",actualTube)
 
    # Get ideal tube based on this actual tube
     try:
diff --git a/scripts/Calibration/tube_calib_fit_params.py b/scripts/Calibration/tube_calib_fit_params.py
index 345bd62a1bf034bfc8be6eda7983f6eb80606473..c96a2e235b08eaa676b5b4522e64fa7aa932e454 100644
--- a/scripts/Calibration/tube_calib_fit_params.py
+++ b/scripts/Calibration/tube_calib_fit_params.py
@@ -1,3 +1,6 @@
+from __future__ import absolute_import, division, print_function
+
+
 class TubeCalibFitParams(object):
 
 # This class is to take the fitting method and parameters for fitting the peaks crated by the calibration slits etc
diff --git a/scripts/Calibration/tube_spec.py b/scripts/Calibration/tube_spec.py
index 10b5bb3ace31578f45840bace0b9f19f3f9521d4..f17a35a541db0172752573fe738d832853c278d4 100644
--- a/scripts/Calibration/tube_spec.py
+++ b/scripts/Calibration/tube_spec.py
@@ -6,6 +6,8 @@
 
 # Author: Karl Palmen ISIS
 
+from __future__ import absolute_import, division, print_function
+
 
 class TubeSpec:
     """
@@ -119,7 +121,6 @@ class TubeSpec:
 
         if self.isTube( comp ):
             self.tubes.append( comp )
-             #print "Tube found", comp.getName()
          # If not tube, Search children, if any
         else:
             if  hasattr( comp, "nelements"):
@@ -156,7 +157,7 @@ class TubeSpec:
             return self.componentArray[0]
 
         # We look for the component
-        print "Looking for", self.componentNameArray[0],
+        print("Looking for", self.componentNameArray[0], end="")
 
         comp = self.inst.getComponentByName(self.componentNameArray[0])
 
@@ -176,15 +177,15 @@ class TubeSpec:
 
         # We look for the components
         for i in range( len(self.componentNameArray)):
-            print "Looking for", self.componentNameArray[i]
+            print("Looking for", self.componentNameArray[i])
 
             comp = self.inst.getComponentByName(self.componentNameArray[i])
 
         if  comp :
             self.componentArray.append(comp)
         else:
-            print "Did not find", self.componentNameArray[i]
-            print "Tube specification not valid"
+            print("Did not find", self.componentNameArray[i])
+            print("Tube specification not valid")
             self.componentArray = []
             return []
 
@@ -209,10 +210,10 @@ class TubeSpec:
         """
         nTubes = self.getNumTubes()
         if nTubes < 0:
-            print "Error in listing tubes"
+            print("Error in listing tubes")
             return 0, 0, 1
         if tubeIx < 0 or tubeIx >= nTubes:
-            print "Tube index",tubeIx,"out of range 0 to",nTubes
+            print("Tube index",tubeIx,"out of range 0 to",nTubes)
             return 0, 0, 1
 
         comp = self.tubes[tubeIx]
@@ -225,18 +226,16 @@ class TubeSpec:
             if lastDet < firstDet:
                 step = -1
                 if  firstDet - lastDet + 1 != numDet:
-                    print "Detector number range",firstDet-lastDet+1," not equal to number of detectors",numDet
-                    print "Detectors not numbered continuously in this tube. Calibration will fail for this tube."
+                    print("Detector number range",firstDet-lastDet+1," not equal to number of detectors",numDet)
+                    print("Detectors not numbered continuously in this tube. Calibration will fail for this tube.")
             else:
                 step = 1
                 if  lastDet - firstDet + 1 != numDet:
-                    print "Detector number range",lastDet-firstDet+1," not equal to number of detectors",numDet
-                    print "Detectors not numbered continuously in this tube. Calibration will fail for this tube."
+                    print("Detector number range",lastDet-firstDet+1," not equal to number of detectors",numDet)
+                    print("Detectors not numbered continuously in this tube. Calibration will fail for this tube.")
 
-            #print "First dectector ", firstDet," Last detector ", firstDet+numDet-1, "Number of detectors ", numDet
-            #print "First dectector ", firstDet," Last detector ", comp[numDet-1].getID()
         else:
-            print self.componentNameArray[0], tubeIx, "not found"
+            print(self.componentNameArray[0], tubeIx, "not found")
             return 0, 0, 1
 
         return firstDet, numDet, step
@@ -252,10 +251,10 @@ class TubeSpec:
         """
         nTubes = self.getNumTubes()
         if nTubes < 0:
-            print "Error in listing tubes"
+            print("Error in listing tubes")
             return 0.0
         if tubeIx < 0 or tubeIx >= nTubes:
-            print "Tube index",tubeIx,"out of range 0 to",nTubes
+            print("Tube index",tubeIx,"out of range 0 to",nTubes)
             return 0.0
 
         comp = self.tubes[tubeIx]
@@ -264,7 +263,7 @@ class TubeSpec:
             numDet = comp.nelements()
             return comp[0].getDistance( comp[numDet-1] )
         else:
-            print self.componentNameArray[0], tubeIx, "not found"
+            print(self.componentNameArray[0], tubeIx, "not found")
             return 0.0
 
     def getTubeName ( self, tubeIx ):
@@ -280,10 +279,10 @@ class TubeSpec:
         """
         nTubes = self.getNumTubes()
         if nTubes < 0:
-            print "Error in listing tubes"
+            print("Error in listing tubes")
             return 'Unknown'
         if tubeIx < 0 or tubeIx >= nTubes:
-            print "Tube index",tubeIx,"out of range 0 to",nTubes
+            print("Tube index",tubeIx,"out of range 0 to",nTubes)
             return 'Unknown'
 
         comp = self.tubes[tubeIx]
@@ -291,7 +290,7 @@ class TubeSpec:
         if comp != 0:
             return comp.getFullName()
         else:
-            print self.componentNameArray[0], tubeIx, "not found"
+            print(self.componentNameArray[0], tubeIx, "not found")
             return "Unknown"
 
     def getTubeByString(self, tubeIx):
@@ -315,8 +314,8 @@ class TubeSpec:
         detids = sp.getDetectorIDs()
         numDetsPerWkID = len(detids)
         if  numDetsPerWkID != 1:
-            print "We have",numDetsPerWkID,"detectors per workspace index. 1 is required."
-            print "cannot obtain range of workspace indices for this tube in this workspace"
+            print("We have",numDetsPerWkID,"detectors per workspace index. 1 is required.")
+            print("cannot obtain range of workspace indices for this tube in this workspace")
             return wkIds, skipped
 
         # Go and get workspace Indices
@@ -335,13 +334,11 @@ class TubeSpec:
                 if detID  >= startDet and detID < startDet+numDet:
                     iPixel = detID - firstDet
                     wkIds = range( i - iPixel, i - iPixel + step*numDet, step)
-                    # print "Workspace indices",i-iPixel,"to",i-iPixel+numDet-1
 
-        #print  firstDet, numDet
         if numDet > 0:
             return wkIds, skipped
         else:
-            print "specified tube has no detectors."
+            print("specified tube has no detectors.")
             self.numTubes = 0
         return wkIds, skipped
 
@@ -357,4 +354,4 @@ class TubeSpec:
         if  (0 <= tubeIx) & (tubeIx < nTubes) :
             return self.getTubeByString(tubeIx)
         else:
-            print "Tube", tubeIx, "out of range 0 to",self.numTubes,"."
+            print("Tube", tubeIx, "out of range 0 to",self.numTubes,".")
diff --git a/scripts/DGS_Reduction.py b/scripts/DGS_Reduction.py
index 77d01a58792e061b679d1c5d656989d86b26338d..b69558e4077f18334ff41aeae2b62e7c33f76263 100644
--- a/scripts/DGS_Reduction.py
+++ b/scripts/DGS_Reduction.py
@@ -2,6 +2,7 @@
 """
     Script used to start the DGS reduction GUI from MantidPlot
 """
+from __future__ import (absolute_import, division, print_function)
 from reduction_application import ReductionGUI
 
 reducer = ReductionGUI(instrument_list=["ARCS", "CNCS", "HYSPEC", "MAPS",
diff --git a/scripts/DiamondAttenuationCorrection/FitTrans.py b/scripts/DiamondAttenuationCorrection/FitTrans.py
index c10e68ac4b57422cbf3f18ab50608d2604807075..b4f024fa7007085fddbf5ed12f3ebb816b13de3e 100644
--- a/scripts/DiamondAttenuationCorrection/FitTrans.py
+++ b/scripts/DiamondAttenuationCorrection/FitTrans.py
@@ -13,6 +13,7 @@ Data types:
 ***
 '''
 # Import all needed libraries
+from __future__ import (absolute_import, division, print_function)
 from matplotlib import pyplot as plt
 import numpy as np
 import itertools as itt
diff --git a/scripts/DiamondAttenuationCorrection/UBMatrixGenerator.py b/scripts/DiamondAttenuationCorrection/UBMatrixGenerator.py
index 28faf3a576c1e5344f3512cd65a033723f89c581..33d0353a9f99848afd31da13b7bbd372fba78837 100644
--- a/scripts/DiamondAttenuationCorrection/UBMatrixGenerator.py
+++ b/scripts/DiamondAttenuationCorrection/UBMatrixGenerator.py
@@ -4,6 +4,7 @@ Identifies upstream and downstream diamonds and assigns matrices to them
 '''
 
 # Import all needed libraries
+from __future__ import (absolute_import, division, print_function)
 import numpy as np
 import itertools as itt
 
@@ -102,6 +103,7 @@ def EquivMatch(refh, hkl, gam, tol):
 
     return hklmatch
 
+
 '''Jacobsen - Implementation of method articulated in RA Jacobsen
  Zeitschrift fur Krystallographie(1996).
 
@@ -194,7 +196,7 @@ def UBMatrixGen(fileName):
         print('{0:0.0f}    {1:0.0f} {2:0.0f} {3:0.0f}     {4:0.3f}'.format(
             i, h[i][0], h[i][1], h[i][2], d[i]))
 
-    nref1 = int(raw_input('Choose one reference reflection: '))
+    nref1 = int(input('Choose one reference reflection: '))
 
     print('REF | h k l | obs|  calc')
     beta = np.zeros(N)
@@ -219,7 +221,7 @@ def UBMatrixGen(fileName):
                 print('{0:0.0f} |   {1:0.0f} {2:0.0f} {3:0.0f} |    {4:0.3f} | {5:0.3f}'.format(
                     i, h[i][0], h[i][1], h[i][2], beta[i], calcang))
 
-    nref2 = int(raw_input('Choose a second reflection to use for indexing: '))
+    nref2 = int(input('Choose a second reflection to use for indexing: '))
 
     h1 = h[nref1]
     q1 = q[nref1]
@@ -231,7 +233,7 @@ def UBMatrixGen(fileName):
     # Re-index all input reflections using this UB
     hindx = (np.linalg.inv(UB1).dot(q.transpose())).transpose()
     print('Reflections will be re-indexed using this UB')
-    tol = float(raw_input('Enter tolerance for accepting index: '))
+    tol = float(input('Enter tolerance for accepting index: '))
     print('REF | h k l | obs|  calc')
     nindexed1 = 0
     for i in range(N):   # decide if reflection is indexed to being within an integer by less then the tolerance
@@ -266,7 +268,7 @@ def UBMatrixGen(fileName):
             print('{0:0.0f}    {1:0.0f} {2:0.0f} {3:0.0f}     {4:0.3f}'.format(
                 i, hsub[i][0], hsub[i][1], hsub[i][2], dsub[i]))
 
-        nref1 = int(raw_input('Choose one reference reflection: '))
+        nref1 = int(input('Choose one reference reflection: '))
 
         for i in range(nsub):
             beta[i] = np.degrees(np.arccos(np.dot(qsub[nref1], qsub[
@@ -291,7 +293,7 @@ def UBMatrixGen(fileName):
                                                                                                         2], beta[i],
                                                                                                     calcang))
         nref2 = int(
-            raw_input('Choose a second reflection to use for indexing: '))
+            input('Choose a second reflection to use for indexing: '))
 
     h1 = hsub[nref1]
     q1 = qsub[nref1]
@@ -299,6 +301,6 @@ def UBMatrixGen(fileName):
     h2 = hsub[nref2]
 
     UB2 = Jacobsen(h1, q1, h2, q2)
-    print 'UB1 = ', UB1
-    print 'UB2 = ', UB2
+    print('UB1 = ', UB1)
+    print('UB2 = ', UB2)
     return UB1, UB2
diff --git a/scripts/Diffraction/isis_powder/gem_routines/gem_algs.py b/scripts/Diffraction/isis_powder/gem_routines/gem_algs.py
index bb366ca0d92cba8bfff1bd484cdd2b3fe24f29e5..fcba0656630e1e0e0b697fbc4e067bbe262a4685 100644
--- a/scripts/Diffraction/isis_powder/gem_routines/gem_algs.py
+++ b/scripts/Diffraction/isis_powder/gem_routines/gem_algs.py
@@ -15,7 +15,8 @@ def calculate_van_absorb_corrections(ws_to_correct, multiple_scattering):
     absorb_dict = gem_advanced_config.absorption_correction_params
     sample_details_obj = absorb_corrections.create_vanadium_sample_details_obj(config_dict=absorb_dict)
     ws_to_correct = absorb_corrections.run_cylinder_absorb_corrections(
-        ws_to_correct=ws_to_correct, multiple_scattering=multiple_scattering, sample_details_obj=sample_details_obj)
+        ws_to_correct=ws_to_correct, multiple_scattering=multiple_scattering, sample_details_obj=sample_details_obj,
+        is_vanadium=True)
     return ws_to_correct
 
 
diff --git a/scripts/Diffraction/isis_powder/polaris.py b/scripts/Diffraction/isis_powder/polaris.py
index 4a93ffe71cd91fe617bb6c85e544c4c04e1f628e..6c5d91bc62b54a37f6e2c68cce2ad4f41a9815a9 100644
--- a/scripts/Diffraction/isis_powder/polaris.py
+++ b/scripts/Diffraction/isis_powder/polaris.py
@@ -46,11 +46,12 @@ class Polaris(AbstractInst):
     def _apply_absorb_corrections(self, run_details, ws_to_correct):
         if self._is_vanadium:
             return polaris_algs.calculate_van_absorb_corrections(
-                ws_to_correct=ws_to_correct, multiple_scattering=self._inst_settings.multiple_scattering)
+                ws_to_correct=ws_to_correct, multiple_scattering=self._inst_settings.multiple_scattering,
+                is_vanadium=self._is_vanadium)
         else:
             return absorb_corrections.run_cylinder_absorb_corrections(
                 ws_to_correct=ws_to_correct, multiple_scattering=self._inst_settings.multiple_scattering,
-                sample_details_obj=self._sample_details)
+                sample_details_obj=self._sample_details, is_vanadium=self._is_vanadium)
 
     @staticmethod
     def _can_auto_gen_vanadium_cal():
diff --git a/scripts/Diffraction/isis_powder/polaris_routines/polaris_algs.py b/scripts/Diffraction/isis_powder/polaris_routines/polaris_algs.py
index 463ad022e689d379068898463ba8171e391eb363..923d2085f25234082631f8a5f61c20dfd1b7e881 100644
--- a/scripts/Diffraction/isis_powder/polaris_routines/polaris_algs.py
+++ b/scripts/Diffraction/isis_powder/polaris_routines/polaris_algs.py
@@ -8,13 +8,14 @@ from isis_powder.routines.run_details import create_run_details_object, \
 from isis_powder.polaris_routines import polaris_advanced_config
 
 
-def calculate_van_absorb_corrections(ws_to_correct, multiple_scattering):
+def calculate_van_absorb_corrections(ws_to_correct, multiple_scattering, is_vanadium):
     mantid.MaskDetectors(ws_to_correct, SpectraList=list(range(1, 55)))
 
     absorb_dict = polaris_advanced_config.absorption_correction_params
     sample_details_obj = absorb_corrections.create_vanadium_sample_details_obj(config_dict=absorb_dict)
     ws_to_correct = absorb_corrections.run_cylinder_absorb_corrections(
-        ws_to_correct=ws_to_correct, multiple_scattering=multiple_scattering, sample_details_obj=sample_details_obj)
+        ws_to_correct=ws_to_correct, multiple_scattering=multiple_scattering, sample_details_obj=sample_details_obj,
+        is_vanadium=is_vanadium)
     return ws_to_correct
 
 
diff --git a/scripts/Diffraction/isis_powder/routines/absorb_corrections.py b/scripts/Diffraction/isis_powder/routines/absorb_corrections.py
index fcfb677301eeae1054a3d6fdd8608c3b1de81ece..afa3eecac5d46e4fbfcc13961a854d50586f6901 100644
--- a/scripts/Diffraction/isis_powder/routines/absorb_corrections.py
+++ b/scripts/Diffraction/isis_powder/routines/absorb_corrections.py
@@ -31,7 +31,7 @@ def create_vanadium_sample_details_obj(config_dict):
     return vanadium_sample_details
 
 
-def run_cylinder_absorb_corrections(ws_to_correct, multiple_scattering, sample_details_obj):
+def run_cylinder_absorb_corrections(ws_to_correct, multiple_scattering, sample_details_obj, is_vanadium):
     """
     Sets a cylindrical sample from the user specified config dictionary and performs Mayers
     sample correction on the workspace. The SampleDetails object defines the sample, material
@@ -40,6 +40,7 @@ def run_cylinder_absorb_corrections(ws_to_correct, multiple_scattering, sample_d
     :param ws_to_correct: The workspace to perform Mayers sample correction on
     :param multiple_scattering: Boolean of whether to account for the effects of multiple scattering
     :param sample_details_obj: The object containing the sample details
+    :param is_vanadium: Whether the sample is a vanadium
     :return: The corrected workspace
     """
 
@@ -53,15 +54,16 @@ def run_cylinder_absorb_corrections(ws_to_correct, multiple_scattering, sample_d
     if not sample_details_obj.is_material_set():
         raise RuntimeError("The material for this sample has not been set yet. Please call"
                            " set_material on the SampleDetails object to set the material")
-
+    if multiple_scattering and not is_vanadium:
+        raise NotImplementedError("Multiple scattering absorption corrections are not yet implemented for "
+                                  "anisotropic samples")
     ws_to_correct = _calculate__cylinder_absorb_corrections(
         ws_to_correct=ws_to_correct, multiple_scattering=multiple_scattering,
-        sample_details_obj=sample_details_obj)
-
+        sample_details_obj=sample_details_obj, is_vanadium=is_vanadium)
     return ws_to_correct
 
 
-def _calculate__cylinder_absorb_corrections(ws_to_correct, multiple_scattering, sample_details_obj):
+def _calculate__cylinder_absorb_corrections(ws_to_correct, multiple_scattering, sample_details_obj, is_vanadium):
     """
     Calculates vanadium absorption corrections for the specified workspace. The workspace
     should have any monitor spectra masked before being passed into this method. Additionally
@@ -71,9 +73,18 @@ def _calculate__cylinder_absorb_corrections(ws_to_correct, multiple_scattering,
     :param multiple_scattering: True if the effects of multiple scattering should be accounted for, else False
     :param sample_details_obj: The SampleDetails object in a checked state which describes the sample
     to ensure a none elemental formula has associated number density
+    :param is_vanadium: Whether the sample is a vanadium
     :return: The workspace with corrections applied
     """
+    _setup_sample_for_cylinder_absorb_corrections(ws_to_correct=ws_to_correct,
+                                                  sample_details_obj=sample_details_obj)
+    ws_to_correct = _do_cylinder_absorb_corrections(ws_to_correct=ws_to_correct,
+                                                    multiple_scattering=multiple_scattering,
+                                                    is_vanadium=is_vanadium)
+    return ws_to_correct
 
+
+def _setup_sample_for_cylinder_absorb_corrections(ws_to_correct, sample_details_obj):
     geometry_json = {'Shape': 'Cylinder',
                      'Height': sample_details_obj.height, 'Radius': sample_details_obj.radius,
                      'Center': sample_details_obj.center}
@@ -89,17 +100,22 @@ def _calculate__cylinder_absorb_corrections(ws_to_correct, multiple_scattering,
 
     mantid.SetSample(InputWorkspace=ws_to_correct, Geometry=geometry_json, Material=material_json)
 
+
+def _do_cylinder_absorb_corrections(ws_to_correct, multiple_scattering, is_vanadium):
     previous_units = ws_to_correct.getAxis(0).getUnit().unitID()
     ws_units = common_enums.WORKSPACE_UNITS
 
     # Mayers Sample correction must be completed in TOF, convert if needed. Then back to original units afterwards
     if previous_units != ws_units.tof:
-        ws_to_correct = mantid.ConvertUnits(InputWorkspace=ws_to_correct, OutputWorkspace=ws_to_correct,
-                                            Target=ws_units.tof)
-    ws_to_correct = mantid.MayersSampleCorrection(InputWorkspace=ws_to_correct, OutputWorkspace=ws_to_correct,
-                                                  MultipleScattering=multiple_scattering)
+        ws_to_correct = mantid.ConvertUnits(InputWorkspace=ws_to_correct, Target=ws_units.tof)
+
+    if is_vanadium:
+        ws_to_correct = mantid.MayersSampleCorrection(InputWorkspace=ws_to_correct,
+                                                      MultipleScattering=multiple_scattering)
+    else:
+        # Ensure we never do multiple scattering if the sample is not isotropic (e.g. not a Vanadium)
+        ws_to_correct = mantid.MayersSampleCorrection(InputWorkspace=ws_to_correct,
+                                                      MultipleScattering=False)
     if previous_units != ws_units.tof:
-        ws_to_correct = mantid.ConvertUnits(InputWorkspace=ws_to_correct, OutputWorkspace=ws_to_correct,
-                                            Target=previous_units)
-
+        ws_to_correct = mantid.ConvertUnits(InputWorkspace=ws_to_correct, Target=previous_units)
     return ws_to_correct
diff --git a/scripts/Diffraction/isis_powder/routines/common_enums.py b/scripts/Diffraction/isis_powder/routines/common_enums.py
index 1d11a1f7f303869b07b5a792fa9bc3cd5b668272..8b8aa2a43defc08887fb39c5efb48e13a5645ec7 100644
--- a/scripts/Diffraction/isis_powder/routines/common_enums.py
+++ b/scripts/Diffraction/isis_powder/routines/common_enums.py
@@ -13,3 +13,4 @@ class WORKSPACE_UNITS(object):
     enum_friendly_name = "workspace units"
     d_spacing = "dSpacing"
     tof = "TOF"
+    wavelength = "Wavelength"
diff --git a/scripts/Diffraction/isis_powder/routines/focus.py b/scripts/Diffraction/isis_powder/routines/focus.py
index 71b3098f619124009bb03ba73b57128b5c232db5..c131aff4e1dc324dc788f023ff179fc1c95a8d16 100644
--- a/scripts/Diffraction/isis_powder/routines/focus.py
+++ b/scripts/Diffraction/isis_powder/routines/focus.py
@@ -36,14 +36,14 @@ def _focus_one_ws(ws, run_number, instrument, perform_vanadium_norm, absorb):
     # Crop to largest acceptable TOF range
     input_workspace = instrument._crop_raw_to_expected_tof_range(ws_to_crop=input_workspace)
 
-    # Align
-    aligned_ws = mantid.AlignDetectors(InputWorkspace=input_workspace,
-                                       CalibrationFile=run_details.offset_file_path)
-
     # Correct for absorption / multiple scattering if required
     if absorb:
         input_workspace = instrument._apply_absorb_corrections(run_details=run_details, ws_to_correct=input_workspace)
 
+    # Align
+    aligned_ws = mantid.AlignDetectors(InputWorkspace=input_workspace,
+                                       CalibrationFile=run_details.offset_file_path)
+
     # Focus the spectra into banks
     focused_ws = mantid.DiffractionFocussing(InputWorkspace=aligned_ws,
                                              GroupingFileName=run_details.grouping_file_path)
diff --git a/scripts/HFIRPowderReduction/HfirPDReductionControl.py b/scripts/HFIRPowderReduction/HfirPDReductionControl.py
index e826905c598351da8115edb8f4b9f314c8d72ab0..e61547b1baa3b131661dd3ebf27a914ab80f84d0 100644
--- a/scripts/HFIRPowderReduction/HfirPDReductionControl.py
+++ b/scripts/HFIRPowderReduction/HfirPDReductionControl.py
@@ -5,11 +5,17 @@
 # Key Words: FUTURE
 #
 ############################################################################
+from __future__ import (absolute_import, division, print_function)
 import os
-import urllib.request
-import urllib.error
-import urllib.parse
+try: # python3
+    from urllib.request import urlopen
+    from urllib.error import HTTPError
+except ImportError:
+    from urllib2 import urlopen
+    from urllib2 import HTTPError
+
 import math
+from six.moves import range
 
 import numpy
 
@@ -1114,9 +1120,9 @@ def downloadFile(url, localfilepath):
     """
     # open URL
     try:
-        response = urllib.request.urlopen(url)
+        response = urlopen(url)
         wbuf = response.read()
-    except urllib.error.HTTPError as e:
+    except HTTPError as e:
         # Unable to download file
         if str(e).count('HTTP Error 404') == 1:
             return (False, str(e))
diff --git a/scripts/HFIRPowderReduction/HfirPDReductionGUI.py b/scripts/HFIRPowderReduction/HfirPDReductionGUI.py
index 286b1d71836f2c8430cf46e8431d9d771844bd92..31fa2722c954c0dcf379c0121e4e618c4aaef79c 100644
--- a/scripts/HFIRPowderReduction/HfirPDReductionGUI.py
+++ b/scripts/HFIRPowderReduction/HfirPDReductionGUI.py
@@ -4,10 +4,17 @@
 # Key word for future developing: FUTURE, NEXT, REFACTOR, RELEASE 2.0
 ################################################################################
 
+from __future__ import (absolute_import, division, print_function)
+from six.moves import range
 import numpy
 import os
+try:
+    import urllib.request as urllib
+except ImportError:
+    import  urllib
+
 
-from ui_MainWindow import Ui_MainWindow #import line for the UI python class
+from .ui_MainWindow import Ui_MainWindow #import line for the UI python class
 from PyQt4 import QtCore, QtGui
 try:
     _fromUtf8 = QtCore.QString.fromUtf8
@@ -17,7 +24,7 @@ except AttributeError:
 
 import mantid
 import mantidqtpython as mqt
-from HfirPDReductionControl import *
+from . import HfirPDReductionControl
 
 #----- default configuration ---------------
 DEFAULT_SERVER = 'http://neutron.ornl.gov/user_data'
@@ -354,7 +361,7 @@ class MainWindow(QtGui.QMainWindow):
         self._currUnit = '2theta'
 
         # Workspaces
-        self._myControl = HFIRPDRedControl()
+        self._myControl = HfirPDReductionControl.HFIRPDRedControl()
 
         # Interactive graphics
         self._viewMerge_X = None
@@ -465,7 +472,7 @@ class MainWindow(QtGui.QMainWindow):
             return
 
         # Parse det exclusion file
-        print "Detector exclusion file name is %s." % (excldetfname)
+        print("Detector exclusion file name is %s." % (excldetfname))
         excludedetlist, errmsg = self._myControl.parseExcludedDetFile('HB2A', excldetfname)
         if len(errmsg) > 0:
             self._logError(errmsg)
@@ -492,8 +499,8 @@ class MainWindow(QtGui.QMainWindow):
         useserver = self.ui.radioButton_useServer.isChecked()
         uselocal = self.ui.radioButton_useLocal.isChecked()
 
-        print "Use Server: ", useserver
-        print "Use Local : ", uselocal
+        print("Use Server: ", useserver)
+        print("Use Local : ", uselocal)
 
         if (useserver is True and uselocal is True) or \
                 (useserver is False and uselocal is False):
@@ -580,7 +587,7 @@ class MainWindow(QtGui.QMainWindow):
         clearcache = self.ui.checkBox_delCache.isChecked()
 
         if clearcache is True:
-            delAllFile(self._cache)
+            urllib.delAllFile(self._cache)
 
         self.close()
 
@@ -599,10 +606,10 @@ class MainWindow(QtGui.QMainWindow):
             self.assistantProcess.close()
             self.assistantProcess.waitForFinished()
             self.assistantProcess.start(helpapp, args)
-            print "Show help from (app) ", helpapp
+            print("Show help from (app) ", helpapp)
         else:
             mqt.MantidQt.API.MantidDesktopServices.openUrl(QtCore.QUrl(self.externalUrl))
-            print "Show help from (url)", QtCore.QUrl(self.externalUrl)
+            print("Show help from (url)", QtCore.QUrl(self.externalUrl))
 
         return
 
@@ -615,7 +622,7 @@ class MainWindow(QtGui.QMainWindow):
         # Kick away unsupported tabs
         itab = self.ui.tabWidget.currentIndex()
         tabtext = str(self.ui.tabWidget.tabText(itab))
-        print "[DB] Current active tab is No. %d as %s." % (itab, tabtext)
+        print("[DB] Current active tab is No. %d as %s." % (itab, tabtext))
 
         # Rule out unsupported tab
         if itab == 5:
@@ -719,7 +726,7 @@ class MainWindow(QtGui.QMainWindow):
             allowedwavelengths = [2.41, 1.54, 1.12]
             numitems = self.ui.comboBox_wavelength.count()
             good = False
-            for ic in xrange(numitems-1):
+            for ic in range(numitems-1):
                 if abs(autowavelength - allowedwavelengths[ic]) < 0.01:
                     good = True
                     self.ui.comboBox_wavelength.setCurrentIndex(ic)
@@ -753,7 +760,7 @@ class MainWindow(QtGui.QMainWindow):
             if vancorrfname is not None:
                 detefftablews, errmsg = self._myControl.parseDetEffCorrFile('HB2A', vancorrfname)
                 if detefftablews is None:
-                    print "Parsing detectors efficiency file error: %s." % (errmsg)
+                    print("Parsing detectors efficiency file error: %s." % (errmsg))
             else:
                 detefftablews = None
             # ENDIF
@@ -765,7 +772,7 @@ class MainWindow(QtGui.QMainWindow):
 
         # Parse SPICE data to MDEventWorkspaces
         try:
-            print "Det Efficiency Table WS: ", str(detefftablews)
+            print("Det Efficiency Table WS: ", str(detefftablews))
             execstatus = self._myControl.parseSpiceData(expno, scanno, detefftablews)
             if execstatus is False:
                 cause = "Parse data failed."
@@ -896,7 +903,7 @@ class MainWindow(QtGui.QMainWindow):
         # Load data
         self.ui.lineEdit_scanNo.setText(str(scanno))
         execstatus = self.doLoadData()
-        print "[DB] Load data : ", execstatus
+        print("[DB] Load data : ", execstatus)
 
         # Reduce data
         self._uiReducePlotNoramlized(self._currUnit)
@@ -919,7 +926,7 @@ class MainWindow(QtGui.QMainWindow):
         try:
             wl_list = []
             for scanno in scanlist:
-                print "Exp %d Scan %d. Wavelength = %s." % (expno, scanno, str(self._myControl.getWavelength(expno, scanno)))
+                print("Exp %d Scan %d. Wavelength = %s." % (expno, scanno, str(self._myControl.getWavelength(expno, scanno))))
                 wl_list.append(float(self._myControl.getWavelength(expno, scanno)))
 
             wl_list = sorted(wl_list)
@@ -1062,10 +1069,10 @@ class MainWindow(QtGui.QMainWindow):
             status, detidlist = self._getIntArray(self.ui.lineEdit_detID.text())
             if status is False:
                 errmsg = detidlist
-                print "Unable to parse detector IDs due to %s."%(errmsg)
+                print("Unable to parse detector IDs due to %s."%(errmsg))
                 return
             else:
-                print "[DB] Detectors to plot: %s"%(detidlist)
+                print("[DB] Detectors to plot: %s"%(detidlist))
         except EmptyError:
             self._logError("Detector ID must be specified for plotting individual detector.")
             return
@@ -1228,7 +1235,7 @@ class MainWindow(QtGui.QMainWindow):
             ptNo = None
 
         # plot
-        print "[DB] Plot Raw Detector: PlotMode = %s." % (plotmode)
+        print("[DB] Plot Raw Detector: PlotMode = %s." % (plotmode))
         execstatus = self._plotRawDetSignal(expno, scanno, plotmode, ptNo, doOverPlot)
 
         # set global values if good
@@ -1238,7 +1245,7 @@ class MainWindow(QtGui.QMainWindow):
             self._rawDetScanNo = scanno
             self._rawDetPlotMode = plotmode
         else:
-            print "[Error] Execution fails with signal %s. " % (str(execstatus))
+            print("[Error] Execution fails with signal %s. " % (str(execstatus)))
 
         return
 
@@ -1572,7 +1579,7 @@ class MainWindow(QtGui.QMainWindow):
         """
         index = self.ui.comboBox_wavelength.currentIndex()
 
-        print "Update wavelength to ", index
+        print("Update wavelength to ", index)
 
         if index == 0:
             wavelength = 2.41
@@ -1607,7 +1614,7 @@ class MainWindow(QtGui.QMainWindow):
             # mouse is clicked within graph
             if button == 1:
                 msg = "Mouse 1: You've clicked on a bar with coords:\n %f, %f\n and button %d" % (x, y, button)
-                print msg
+                print(msg)
             elif button == 2:
                 msg = "Mouse 2: You've clicked on a bar with coords:\n %f, %f\n and button %d" % (x, y, button)
                 QtGui.QMessageBox.information(self, "Click!", msg)
@@ -1654,7 +1661,7 @@ class MainWindow(QtGui.QMainWindow):
         """
         """
         # FUTURE - Need to implement how to deal with this
-        print "Add scan back to merge"
+        print("Add scan back to merge")
 
         return
 
@@ -1662,7 +1669,7 @@ class MainWindow(QtGui.QMainWindow):
         """
         """
         # FUTURE - Need to implement how to deal with this
-        print "Remove a scan from merged data."
+        print("Remove a scan from merged data.")
 
         return
 
@@ -1793,7 +1800,7 @@ class MainWindow(QtGui.QMainWindow):
     def _plotPeakIndicators(self, canvas, peakposlist):
         """ Plot indicators for peaks
         """
-        print "[DB] Peak indicators are at ", peakposlist
+        print("[DB] Peak indicators are at ", peakposlist)
 
         rangey = canvas.getYLimit()
         rangex = canvas.getXLimit()
@@ -2121,7 +2128,7 @@ class MainWindow(QtGui.QMainWindow):
                 self._serverAddress += '/'
             fullurl = "%s%s/exp%d/Datafiles/%s_exp%04d_scan%04d.dat" % (self._serverAddress,
                                                                         self._instrument.lower(), exp, self._instrument.upper(), exp, scan)
-            print "URL: ", fullurl
+            print("URL: ", fullurl)
 
             cachedir = str(self.ui.lineEdit_cache.text()).strip()
             if os.path.exists(cachedir) is False:
@@ -2133,7 +2140,7 @@ class MainWindow(QtGui.QMainWindow):
 
             filename = '%s_exp%04d_scan%04d.dat' % (self._instrument.upper(), exp, scan)
             srcFileName = os.path.join(cachedir, filename)
-            status, errmsg = downloadFile(fullurl, srcFileName)
+            status, errmsg = urllib.downloadFile(fullurl, srcFileName)
             if status is False:
                 self._logError(errmsg)
                 srcFileName = None
@@ -2245,7 +2252,7 @@ class MainWindow(QtGui.QMainWindow):
         # scans = [startscan, endscan] + [others] - [excluded]
         status, extrascanlist = self._getIntArray(str(self.ui.lineEdit_extraScans.text()))
         if status is False:
-            raise RuntimeError(extrascanlsit)
+            raise RuntimeError(extrascanlist)
 
         status, excludedlist = self._getIntArray(str(self.ui.lineEdit_exclScans.text()))
         self._logDebug("Excluded list: %s" %(str(excludedlist)))
@@ -2253,7 +2260,7 @@ class MainWindow(QtGui.QMainWindow):
             self._logError(excludedlist)
             return
 
-        scanslist = range(startscan, endscan+1)
+        scanslist = list(range(startscan, endscan+1))
         scanslist.extend(extrascanlist)
         scanslist = list(set(scanslist))
         for scan in excludedlist:
@@ -2270,7 +2277,7 @@ class MainWindow(QtGui.QMainWindow):
 
         # check binning
         same = True
-        for i in xrange(3):
+        for i in range(3):
             par_0 = binparams[i]
             par_1 = newbinparams[i]
 
@@ -2287,12 +2294,12 @@ class MainWindow(QtGui.QMainWindow):
 
         change = not same
         if change is True:
-            print "[D...............B]",
-            print "%s vs %s "  % (str(xmin), str(self._tabBinParamDict[itab][0])),
-            print "%s vs %s "  % (str(xmax), str(self._tabBinParamDict[itab][2])),
-            print "%s vs %s "  % (str(binsize), str(self._tabBinParamDict[itab][1]))
+            print("[D...............B]", end=' ')
+            print("%s vs %s "  % (str(xmin), str(self._tabBinParamDict[itab][0])), end=' ')
+            print("%s vs %s "  % (str(xmax), str(self._tabBinParamDict[itab][2])), end=' ')
+            print("%s vs %s "  % (str(binsize), str(self._tabBinParamDict[itab][1])))
         else:
-            print "[DB] Rebin = False"
+            print("[DB] Rebin = False")
 
         return change
 
@@ -2401,7 +2408,7 @@ class MainWindow(QtGui.QMainWindow):
     def _logDebug(self, dbinfo):
         """ Log debug information
         """
-        print dbinfo
+        print(dbinfo)
 
     def _logError(self, errinfo):
         """ Log error information
@@ -2412,7 +2419,7 @@ class MainWindow(QtGui.QMainWindow):
         """ Log error information
         """
         msg = '[Notice] %s' % loginfo
-        print msg
+        print(msg)
         # QtGui.QMessageBox.information(self, "Click!", msg)
 
     def _logWarning(self, warning_info):
@@ -2493,7 +2500,7 @@ class MainWindow(QtGui.QMainWindow):
                 # Integer range
                 twoterms = level0term.split("-")
                 templist = []
-                for i in xrange(2):
+                for i in range(2):
                     valuestr = twoterms[i]
                     try:
                         intvalue = int(valuestr)
@@ -2515,7 +2522,7 @@ class MainWindow(QtGui.QMainWindow):
             else:
                 # Undefined siutation
                 returnstatus = False
-                errmsg = "Term %s contains more than 1 dash." % (level0terms)
+                errmsg = "Term %s contains more than 1 dash." % (level0term)
             # ENDIFELSE
 
             # break loop if something is wrong
diff --git a/scripts/HFIRPowderReduction/HfirUtility.py b/scripts/HFIRPowderReduction/HfirUtility.py
index 7bd3d815aaba75d551f2ca01477bf3374f5400b8..816b19f76ca1cd90e67284151aaae28d15a78dc7 100644
--- a/scripts/HFIRPowderReduction/HfirUtility.py
+++ b/scripts/HFIRPowderReduction/HfirUtility.py
@@ -5,6 +5,8 @@
 #
 ################################################################################
 
+from __future__ import (absolute_import, division, print_function)
+
 
 def makeHB2ADetEfficiencyFileName(expno, m1, colltrans):
     """ Fabricate the detector's efficiency file name for HB2A
diff --git a/scripts/HFIRPowderReduction/MainWindow.ui b/scripts/HFIRPowderReduction/MainWindow.ui
index 19387104a892bc27c6102ad5b8a27211bbbb18fe..36cf466aa8c8ae9ebf7a5e502c238f5cf2fe20a9 100644
--- a/scripts/HFIRPowderReduction/MainWindow.ui
+++ b/scripts/HFIRPowderReduction/MainWindow.ui
@@ -2276,7 +2276,7 @@
   <customwidget>
    <class>MplFigureCanvas</class>
    <extends>QGraphicsView</extends>
-   <header>MplFigureCanvas.h</header>
+   <header>HFIRPowderReduction/MplFigureCanvas.h</header>
   </customwidget>
  </customwidgets>
  <resources/>
diff --git a/scripts/HFIRPowderReduction/MplFigureCanvas.py b/scripts/HFIRPowderReduction/MplFigureCanvas.py
index 8dec8eb971f1395630d4b7fe4bece760559f8e3c..61a6e5dcd656f8ecd7712474384c07b0c5db1981 100644
--- a/scripts/HFIRPowderReduction/MplFigureCanvas.py
+++ b/scripts/HFIRPowderReduction/MplFigureCanvas.py
@@ -1,4 +1,5 @@
 #pylint: disable=invalid-name,too-many-public-methods,too-many-arguments,non-parent-init-called, too-many-branches
+from __future__ import (absolute_import, division, print_function)
 import os
 import numpy as np
 
@@ -191,7 +192,7 @@ class MplFigureCanvas(QtGui.QWidget):
         # process marker if it has information
         if marker.count(' (') > 0:
             marker = marker.split(' (')[0]
-        print "[DB] Print line %d: marker = %s, color = %s" % (self._myLineMarkerColorIndex, marker, color)
+        print("[DB] Print line %d: marker = %s, color = %s" % (self._myLineMarkerColorIndex, marker, color))
 
         # update the index
         self._myLineMarkerColorIndex += 1
@@ -336,11 +337,11 @@ class Qt4MplCanvas(FigureCanvas):
             # regular line
             self._lineDict[self._lineIndex] = r[0]
         else:
-            print "Impoooooooooooooooosible! Number of returned tuple is %d"%(len(r))
+            print("Impoooooooooooooooosible! Number of returned tuple is %d"%(len(r)))
             dbmsg = ''
             for sub_r in r:
                 dbmsg += 'Type: %s, Value: %s\n' % (str(type(sub_r)), str(sub_r))
-            print dbmsg
+            print(dbmsg)
         self._lineIndex += 1
 
         # Flush/commit
@@ -362,16 +363,16 @@ class Qt4MplCanvas(FigureCanvas):
         # yticks = [1, 4, 23, 24, 30]
         # self.axes.set_yticks(yticks)
 
-        print "[DBNOW] Before imshow(), number of axes = %d" % (len(self.fig.axes))
+        print("[DBNOW] Before imshow(), number of axes = %d" % (len(self.fig.axes)))
 
         # show image
         imgplot = self.axes.imshow(array2d, extent=[xmin,xmax,ymin,ymax], interpolation='none')
-        print "[DBNOW] After imshow(), number of axes = %d" % (len(self.fig.axes))
+        print("[DBNOW] After imshow(), number of axes = %d" % (len(self.fig.axes)))
 
         # set y ticks as an option:
         if yticklabels is not None:
             # it will always label the first N ticks even image is zoomed in
-            print "--------> [FixMe]: Set up the Y-axis ticks is erroreous"
+            print("--------> [FixMe]: Set up the Y-axis ticks is erroreous")
             #self.axes.set_yticklabels(yticklabels)
 
         # explicitly set aspect ratio of the image
@@ -384,7 +385,7 @@ class Qt4MplCanvas(FigureCanvas):
             self.colorBar = self.fig.colorbar(imgplot)
         else:
             self.colorBar.update_bruteforce(imgplot)
-        print "[DBNOW] After colorbar is added, number of axes = %d" % (len(self.fig.axes))
+        print("[DBNOW] After colorbar is added, number of axes = %d" % (len(self.fig.axes)))
 
         # Flush...
         self._flush()
@@ -427,8 +428,8 @@ class Qt4MplCanvas(FigureCanvas):
                 try:
                     self.axes.lines.remove(plot)
                 except ValueError as e:
-                    print "[Error] Plot %s is not in axes.lines which has %d lines. Error mesage: %s" % (
-                        str(plot), len(self.axes.lines), str(e))
+                    print("[Error] Plot %s is not in axes.lines which has %d lines. Error mesage: %s" % (
+                        str(plot), len(self.axes.lines), str(e)))
                 self._lineDict[ikey] = None
             else:
                 # error bar
@@ -472,7 +473,7 @@ class Qt4MplCanvas(FigureCanvas):
             # Re-create subplot
             self.axes = self.fig.add_subplot(111)
         if len(self.fig.axes) > 0:
-            print "[DBNOW] Type of axes[0] = %s" % (str(type(self.fig.axes[0])))
+            print("[DBNOW] Type of axes[0] = %s" % (str(type(self.fig.axes[0]))))
 
         # flush/commit
         self._flush()
@@ -530,11 +531,11 @@ class Qt4MplCanvas(FigureCanvas):
         """
         # self._lineDict[ikey].remove()
         lines = self.axes.lines
-        print str(type(lines)), lines
-        print "ikey = ", ikey, self._lineDict[ikey]
+        print(str(type(lines)), lines)
+        print("ikey = ", ikey, self._lineDict[ikey])
         self.axes.lines.remove(self._lineDict[ikey])
         #self.axes.remove(self._lineDict[ikey])
-        print self._lineDict[ikey]
+        print(self._lineDict[ikey])
         self._lineDict[ikey] = None
 
         return
@@ -593,9 +594,9 @@ class Qt4MplCanvas(FigureCanvas):
         nummarkers = len(MplLineMarkers)
         numcolors = len(MplBasicColors)
 
-        for i in xrange(nummarkers):
+        for i in range(nummarkers):
             marker = MplLineMarkers[i]
-            for j in xrange(numcolors):
+            for j in range(numcolors):
                 color = MplBasicColors[j]
                 combolist.append( (marker, color) )
             # ENDFOR (j)
diff --git a/scripts/HFIR_4Circle_Reduction.py b/scripts/HFIR_4Circle_Reduction.py
index 9f8dfa0fd02bc2ac2742703f1f702fbd56ddabe4..686695ad4590cfb61276c49b678563d543df5df1 100644
--- a/scripts/HFIR_4Circle_Reduction.py
+++ b/scripts/HFIR_4Circle_Reduction.py
@@ -1,4 +1,5 @@
 #pylint: disable=invalid-name
+from __future__ import (absolute_import, division, print_function)
 from HFIR_4Circle_Reduction import reduce4circleGUI
 from PyQt4 import QtGui, QtCore
 import sys
diff --git a/scripts/HFIR_4Circle_Reduction/FindUBUtility.py b/scripts/HFIR_4Circle_Reduction/FindUBUtility.py
index a41ba3cac87001777582d4b00ed43d9470fa31b3..31ad7583713a5c3c74b9c058f9295ca3b90577f7 100644
--- a/scripts/HFIR_4Circle_Reduction/FindUBUtility.py
+++ b/scripts/HFIR_4Circle_Reduction/FindUBUtility.py
@@ -1,11 +1,12 @@
 """
 Containing a set of classes used for finding (calculating and refining) UB matrix
 """
+from __future__ import (absolute_import, division, print_function)
 import os
 
-import ui_AddUBPeaksDialog
-import ui_UBSelectPeaksDialog
-import guiutility
+from . import ui_AddUBPeaksDialog
+from . import ui_UBSelectPeaksDialog
+from . import guiutility
 
 from PyQt4 import QtGui, QtCore
 
diff --git a/scripts/HFIR_4Circle_Reduction/MainWindow.ui b/scripts/HFIR_4Circle_Reduction/MainWindow.ui
index 8d8c0e94c60d05cd64fe56367869dd1aea5571ce..d7a7e30670ef02ee8ae625ed95e97f1f1d9692ff 100644
--- a/scripts/HFIR_4Circle_Reduction/MainWindow.ui
+++ b/scripts/HFIR_4Circle_Reduction/MainWindow.ui
@@ -5893,42 +5893,42 @@ p, li { white-space: pre-wrap; }
   <customwidget>
    <class>UBMatrixPeakTable</class>
    <extends>QTableWidget</extends>
-   <header>hfctables.h</header>
+   <header>HFIR_4Circle_Reduction/hfctables.h</header>
   </customwidget>
   <customwidget>
    <class>UBMatrixTable</class>
    <extends>QTableWidget</extends>
-   <header>hfctables.h</header>
+   <header>HFIR_4Circle_Reduction/hfctables.h</header>
   </customwidget>
   <customwidget>
    <class>ProcessTableWidget</class>
    <extends>QTableWidget</extends>
-   <header>hfctables.h</header>
+   <header>HFIR_4Circle_Reduction/hfctables.h</header>
   </customwidget>
   <customwidget>
    <class>ScanSurveyTable</class>
    <extends>QTableWidget</extends>
-   <header>hfctables.h</header>
+   <header>HFIR_4Circle_Reduction/hfctables.h</header>
   </customwidget>
   <customwidget>
    <class>IntegratedPeakView</class>
    <extends>QGraphicsView</extends>
-   <header>integratedpeakview.h</header>
+   <header>HFIR_4Circle_Reduction/integratedpeakview.h</header>
   </customwidget>
   <customwidget>
    <class>Detector2DView</class>
    <extends>QGraphicsView</extends>
-   <header>detector2dview.h</header>
+   <header>HFIR_4Circle_Reduction/detector2dview.h</header>
   </customwidget>
   <customwidget>
    <class>KShiftTableWidget</class>
    <extends>QTableWidget</extends>
-   <header>hfctables.h</header>
+   <header>HFIR_4Circle_Reduction/hfctables.h</header>
   </customwidget>
   <customwidget>
    <class>MatrixTable</class>
    <extends>QTableWidget</extends>
-   <header>hfctables.h</header>
+   <header>HFIR_4Circle_Reduction/hfctables.h</header>
   </customwidget>
  </customwidgets>
  <resources/>
diff --git a/scripts/HFIR_4Circle_Reduction/NTableWidget.py b/scripts/HFIR_4Circle_Reduction/NTableWidget.py
index e8e65036197ad3487e5bd1f67116502c3d1d9be5..49b736234e141202d33365091ce209744b63a52b 100644
--- a/scripts/HFIR_4Circle_Reduction/NTableWidget.py
+++ b/scripts/HFIR_4Circle_Reduction/NTableWidget.py
@@ -1,5 +1,7 @@
 #pylint: disable=C0103,R0904
 # N(DAV)TableWidget
+from __future__ import (absolute_import, division, print_function)
+from six.moves import range
 import csv
 from PyQt4 import QtGui, QtCore
 
@@ -60,7 +62,7 @@ class NTableWidget(QtGui.QTableWidget):
         self.insertRow(row_number)
 
         # Set values
-        for i_col in xrange(min(len(row_value_list), self.columnCount())):
+        for i_col in range(min(len(row_value_list), self.columnCount())):
             item = QtGui.QTableWidgetItem()
             if row_value_list[i_col] is None:
                 item_value = ''
@@ -191,7 +193,7 @@ class NTableWidget(QtGui.QTableWidget):
             raise IndexError('Index of row (%d) is out of range.' % row_index)
 
         ret_list = list()
-        for i_col in xrange(len(self._myColumnTypeList)):
+        for i_col in range(len(self._myColumnTypeList)):
             c_type = self._myColumnTypeList[i_col]
 
             if c_type == 'checkbox':
@@ -233,7 +235,7 @@ class NTableWidget(QtGui.QTableWidget):
 
         # loop over all the rows
         row_index_list = list()
-        for i_row in xrange(self.rowCount()):
+        for i_row in range(self.rowCount()):
             # check status
             is_checked = self.get_cell_value(i_row, index_status)
             if is_checked == status:
@@ -287,7 +289,7 @@ class NTableWidget(QtGui.QTableWidget):
         :return:
         """
         num_rows = self.rowCount()
-        for i_row in xrange(1, num_rows+1):
+        for i_row in range(1, num_rows+1):
             self.removeRow(num_rows - i_row)
 
         return
@@ -346,7 +348,7 @@ class NTableWidget(QtGui.QTableWidget):
 
         # Loop over all rows. If any row's status is not same as target status, then set it
         num_rows = self.rowCount()
-        for row_index in xrange(num_rows):
+        for row_index in range(num_rows):
             if self.get_cell_value(row_index, status_col_index) != status:
                 self.update_cell_value(row_index, status_col_index, status)
         # END-FOR
@@ -503,7 +505,7 @@ class NTableWidget(QtGui.QTableWidget):
         # get rows
         num_rows = self.rowCount()
         row_content_dict = dict()
-        for i_row in xrange(num_rows):
+        for i_row in range(num_rows):
             row_items = self.get_row_value(i_row)
             key_value = self.get_cell_value(i_row, column_index)
             row_content_dict[key_value] = row_items
diff --git a/scripts/HFIR_4Circle_Reduction/PeakIntegrationSpreadSheet.ui b/scripts/HFIR_4Circle_Reduction/PeakIntegrationSpreadSheet.ui
index 52b42acd4794a7881ad1f193fa38529654dde1b2..422f105e2d6a49e640457a766447dddf177a08e6 100644
--- a/scripts/HFIR_4Circle_Reduction/PeakIntegrationSpreadSheet.ui
+++ b/scripts/HFIR_4Circle_Reduction/PeakIntegrationSpreadSheet.ui
@@ -70,7 +70,7 @@
   <customwidget>
    <class>PeaksIntegrationSpreadSheet</class>
    <extends>QTableWidget</extends>
-   <header>hfctables.h</header>
+   <header>HFIR_4Circle_Reduction/hfctables.h</header>
   </customwidget>
  </customwidgets>
  <resources/>
diff --git a/scripts/HFIR_4Circle_Reduction/PeaksIntegrationReport.py b/scripts/HFIR_4Circle_Reduction/PeaksIntegrationReport.py
index a5f13cd30770defd2d6bc40553934c2efd92fa51..def4b05f0095737f9658e624028615f86743490d 100644
--- a/scripts/HFIR_4Circle_Reduction/PeaksIntegrationReport.py
+++ b/scripts/HFIR_4Circle_Reduction/PeaksIntegrationReport.py
@@ -1,7 +1,8 @@
+from __future__ import (absolute_import, division, print_function)
 import os
 
 from PyQt4 import QtGui, QtCore
-import ui_PeakIntegrationSpreadSheet
+from . import ui_PeakIntegrationSpreadSheet
 
 
 class PeaksIntegrationReportDialog(QtGui.QDialog):
@@ -68,13 +69,13 @@ class PeaksIntegrationReportDialog(QtGui.QDialog):
         assert isinstance(peak_integration_summary, dict)
 
         if len(peak_integration_summary) == 0:
-            print '[WARNING] There is no peak integration summary given for the report.'
+            print('[WARNING] There is no peak integration summary given for the report.')
             return
 
         scan_number_list = sorted(peak_integration_summary.keys())
         for scan_number in scan_number_list:
-            print '[DB...BAT] Scan {0} Peak integration report keys: {1}' \
-                  ''.format(scan_number, peak_integration_summary[scan_number].keys())
+            print('[DB...BAT] Scan {0} Peak integration report '
+                  'keys: {1}'.format(scan_number, peak_integration_summary[scan_number].keys()))
 
             spice_hkl = peak_integration_summary[scan_number]['SPICE HKL']
             calculated_hkl = peak_integration_summary[scan_number]['Mantid HKL']
diff --git a/scripts/HFIR_4Circle_Reduction/View3DWidget.ui b/scripts/HFIR_4Circle_Reduction/View3DWidget.ui
index e18cc0d3c34da5a7c30c27763e1ddf9ed5badef0..8a693e4611b26f6f1a68c868be32068e5dc8e7c5 100644
--- a/scripts/HFIR_4Circle_Reduction/View3DWidget.ui
+++ b/scripts/HFIR_4Circle_Reduction/View3DWidget.ui
@@ -401,7 +401,7 @@
   <customwidget>
    <class>MplPlot3dCanvas</class>
    <extends>QGraphicsView</extends>
-   <header>mplgraphicsview3d.h</header>
+   <header>HFIR_4Circle_Reduction/mplgraphicsview3d.h</header>
   </customwidget>
  </customwidgets>
  <resources/>
diff --git a/scripts/HFIR_4Circle_Reduction/absorption.py b/scripts/HFIR_4Circle_Reduction/absorption.py
index 78c87c9b36853cbfc937aa56cf8b7c405123b190..e01e24da25d5d0a7cb33d2221f2a4a71df29d190 100644
--- a/scripts/HFIR_4Circle_Reduction/absorption.py
+++ b/scripts/HFIR_4Circle_Reduction/absorption.py
@@ -1,10 +1,12 @@
 #pylint: disable=R0913,W0403,R0903,C0103
+from __future__ import (absolute_import, division, print_function)
+from six.moves import range
 import numpy
 import numpy.linalg
 import math
 from mantid.api import AnalysisDataService
 
-import fourcircle_utility as util4
+import HFIR_4Circle_Reduction.fourcircle_utility as util4
 
 # Do absorption correction
 
diff --git a/scripts/HFIR_4Circle_Reduction/detector2dview.py b/scripts/HFIR_4Circle_Reduction/detector2dview.py
index b2bdd80c789faa0b530b6db397c1750c691c9f2f..ef6bd205e5ab3fc948f76ef3580bf696ea198efa 100644
--- a/scripts/HFIR_4Circle_Reduction/detector2dview.py
+++ b/scripts/HFIR_4Circle_Reduction/detector2dview.py
@@ -1,7 +1,8 @@
 #pylint: disable=W0403,R0902,R0903,R0904,W0212
+from __future__ import (absolute_import, division, print_function)
 import os
 import numpy as np
-import mpl2dgraphicsview
+from HFIR_4Circle_Reduction import mpl2dgraphicsview
 
 
 class Detector2DView(mpl2dgraphicsview.Mpl2dGraphicsView):
@@ -111,9 +112,9 @@ class Detector2DView(mpl2dgraphicsview.Mpl2dGraphicsView):
             file_name = '{0}_axis_{1}.dat'.format(base_file_name, axis)
 
             wbuf = ''
-            vec_x = np.array(range(len(array1d))) + start_index
-            for i in range(len(array1d)):
-                wbuf += '{0} \t{1}\n'.format(vec_x[i], array1d[i])
+            vec_x = np.arange(len(array1d)) + start_index
+            for x, d in zip(vec_x, array1d):
+                wbuf += '{0} \t{1}\n'.format(x, d)
 
             ofile = open(file_name, 'w')
             ofile.write(wbuf)
@@ -136,16 +137,16 @@ class Detector2DView(mpl2dgraphicsview.Mpl2dGraphicsView):
         ur_row = max(self._roiStart[0], self._roiEnd[0])
         ur_col = max(self._roiStart[1], self._roiEnd[1])
 
-        # print 'Row: {0} : {1}  Col: {2} : {3}'.format(ll_row, ur_row, ll_col, ur_col)
+        # print('Row: {0} : {1}  Col: {2} : {3}'.format(ll_row, ur_row, ll_col, ur_col))
 
         roi_matrix = matrix[ll_col:ur_col, ll_row:ur_row]
 
         sum_0 = roi_matrix.sum(0)
-        #  print sum_0
+        #  print(sum_0)
         sum_1 = roi_matrix.sum(1)
-        #  print sum_1
-        print '[SUM 0] Dimension: {0}'.format(sum_0.shape)
-        print '[SUM 1] Dimension: {0}'.format(sum_1.shape)
+        #  print(sum_1)
+        print('[SUM 0] Dimension: {0}'.format(sum_0.shape))
+        print('[SUM 1] Dimension: {0}'.format(sum_1.shape))
 
         # write to file
         base_name = os.path.join(output_dir, 'Exp{0}_Scan{1}_Pt{2}'.format(exp_number, scan_number, pt_number))
diff --git a/scripts/HFIR_4Circle_Reduction/fourcircle_utility.py b/scripts/HFIR_4Circle_Reduction/fourcircle_utility.py
index 2043bfe2316793c9cc36d58f4756f5a184d20ace..575d8f0b4ac6567d071b0cf4ba66af4cfab09513 100644
--- a/scripts/HFIR_4Circle_Reduction/fourcircle_utility.py
+++ b/scripts/HFIR_4Circle_Reduction/fourcircle_utility.py
@@ -1,6 +1,13 @@
 #pylint: disable=W0633,R0913,too-many-branches
+from __future__ import (absolute_import, division, print_function)
+from six.moves import range
 import os
-import urllib2
+try: # python3
+    from urllib.request import urlopen
+    from urllib.error import URLError
+except ImportError:
+    from urllib2 import urlopen
+    from urllib2 import URLError
 import socket
 import numpy
 import math
@@ -22,12 +29,12 @@ def check_url(url, read_lines=False):
     lines = None
     try:
         # Access URL
-        url_stream = urllib2.urlopen(url, timeout=2)
+        url_stream = urlopen(url, timeout=2)
 
         # Read lines
         if read_lines is True:
             lines = url_stream.readlines()
-    except urllib2.URLError as url_error:
+    except URLError as url_error:
         url_stream = url_error
     except socket.timeout:
         return False, 'Time out. Try again!'
@@ -95,7 +102,7 @@ def generate_mask_file(file_path, ll_corner, ur_corner, rectangular=True, num_de
     if rectangular is False:
         raise RuntimeError('Non-rectangular detector is not supported yet.')
 
-    print '[INFO] Mask from %s to %s.' % (str(ll_corner), str(ur_corner))
+    print('[INFO] Mask from %s to %s.' % (str(ll_corner), str(ur_corner)))
 
     # part 1
     xml_str = '<?xml version="1.0"?>\n'
@@ -127,13 +134,13 @@ def generate_mask_file(file_path, ll_corner, ur_corner, rectangular=True, num_de
 
     det_sub_xml = ''
     if False:
-        for col_number in xrange(start_col, end_col+1):
+        for col_number in range(start_col, end_col+1):
             start_det_id = 1 + col_number * NUM_DET_ROW + start_row
             end_det_id = 1 + col_number * NUM_DET_ROW + end_row
             det_sub_xml += '%d-%d,' % (start_det_id, end_det_id)
     else:
-        # print '[DB...BAT] Row numbers from {0} to {1}'.format(start_row, end_row)
-        # print '[DB...BAT] Col numbers from {0} to {1}'.format(start_col, end_col)
+        # print('[DB...BAT] Row numbers from {0} to {1}'.format(start_row, end_row))
+        # print('[DB...BAT] Col numbers from {0} to {1}'.format(start_col, end_col))
         for row_number in range(start_row, end_row+1):
             start_det_id = 1 + row_number * num_det_row + start_col
             end_det_id = 1 + row_number * num_det_row + end_col
@@ -325,7 +332,7 @@ def parse_int_array(int_array_str):
             # Integer range
             two_terms = level0_term.split("-")
             temp_list = []
-            for i in xrange(2):
+            for i in range(2):
                 value_str = two_terms[i]
                 try:
                     int_value = int(value_str)
@@ -664,7 +671,7 @@ def load_hb3a_md_data(file_name):
     intensities = numpy.zeros((len(raw_lines), ))
 
     # parse
-    for i in xrange(len(raw_lines)):
+    for i in range(len(raw_lines)):
         line = raw_lines[i].strip()
 
         # skip empty line
@@ -673,7 +680,7 @@ def load_hb3a_md_data(file_name):
 
         # set value
         terms = line.split(',')
-        for j in xrange(3):
+        for j in range(3):
             xyz_points[i][j] = float(terms[j])
         intensities[i] = float(terms[3])
     # END-FOR
diff --git a/scripts/HFIR_4Circle_Reduction/fputility.py b/scripts/HFIR_4Circle_Reduction/fputility.py
index 2c94f404153d299bd950d05c5c2edb8c4bdfebf3..9a3f1402897b35940178624ffd09ee90a3ef7e5c 100644
--- a/scripts/HFIR_4Circle_Reduction/fputility.py
+++ b/scripts/HFIR_4Circle_Reduction/fputility.py
@@ -1,5 +1,6 @@
 #pylint: disable=R0914,R0912,R0913
 # Utility methods for Fullprof
+from __future__ import (absolute_import, division, print_function)
 import os
 import sys
 import math
@@ -70,7 +71,7 @@ def load_scd_fullprof_intensity_file(file_name):
         if line_index == 0:
             # line 1 as header
             header = line
-            print '[INFO] Header: %s' % header
+            print('[INFO] Header:', header)
         elif line.startswith('('):
             # line 2 format line, skip
             continue
@@ -279,8 +280,8 @@ def main(argv):
     """
     # get input
     if len(argv) < 4:
-        print 'Calculate the difference of two measurements:\n'
-        print '> %s [intensity file 1]  [intensity file 2]  [output intensity file]' % argv[0]
+        print('Calculate the difference of two measurements:\n')
+        print('> %s [intensity file 1]  [intensity file 2]  [output intensity file]' % argv[0])
         return
     else:
         int_file_1 = argv[1]
@@ -291,9 +292,9 @@ def main(argv):
     intensity_dict2, wave_length2, error_message2 = load_scd_fullprof_intensity_file(int_file_2)
 
     if len(error_message1) == 0:
-        print '[Error] %s: %s' % (int_file_1, error_message1)
+        print('[Error] %s: %s' % (int_file_1, error_message1))
     if len(error_message2) == 0:
-        print '[Error] %s: %s' % (int_file_2, error_message2)
+        print('[Error] %s: %s' % (int_file_2, error_message2))
 
     diff_dict = calculate_intensity_difference(intensity_dict1, intensity_dict2)
     diff_peak_list = convert_to_peak_dict_list(diff_dict)
diff --git a/scripts/HFIR_4Circle_Reduction/guiutility.py b/scripts/HFIR_4Circle_Reduction/guiutility.py
index 9ee8918d52e23719041b8200e1415d6cd9e381ce..23db1914fcd0a0c02cf4fd791a2bcaf279f91b07 100644
--- a/scripts/HFIR_4Circle_Reduction/guiutility.py
+++ b/scripts/HFIR_4Circle_Reduction/guiutility.py
@@ -1,6 +1,8 @@
 #
 # GUI Utility Methods
 #
+from __future__ import (absolute_import, division, print_function)
+from six.moves import range
 import math
 import numpy
 import os
@@ -34,8 +36,8 @@ def convert_str_to_matrix(matrix_str, matrix_shape):
     assert matrix_shape[0] * matrix_shape[1] == len(matrix_terms)
     matrix = numpy.ndarray(shape=matrix_shape, dtype='float')
     term_index = 0
-    for i_row in xrange(matrix_shape[0]):
-        for j_col in xrange(matrix_shape[1]):
+    for i_row in range(matrix_shape[0]):
+        for j_col in range(matrix_shape[1]):
             matrix[i_row][j_col] = matrix_terms[term_index]
             term_index += 1
 
@@ -116,7 +118,7 @@ def map_to_color(data_array, base_color, change_color_flag):
 
         color_value_list = [None, None, None]
 
-        for i_color in xrange(3):
+        for i_color in range(3):
             c_flag = change_color_flag[i_color]
             if c_flag:
                 # this color will be changed for color map
@@ -156,7 +158,7 @@ def map_to_color(data_array, base_color, change_color_flag):
     num_steps_color = int(math.pow(float(max(data_array)), 1./num_changes)+0.5)
 
     # calculate
-    for array_index in xrange(array_size):
+    for array_index in range(array_size):
         value = data_array[array_index]
         rgb = convert_value_to_color(base_color, change_color_flag, num_changes, num_steps_color, value)
         color_list[array_index] = rgb
@@ -240,7 +242,7 @@ def parse_integer_list(array_str, expected_size=None):
             else:
                 raise RuntimeError('Unable to parse %s due to value error' % int_str)
 
-            integer_list.extend(xrange(start_value, end_value+1))
+            integer_list.extend(range(start_value, end_value+1))
     # END-FOR
 
     # check size
diff --git a/scripts/HFIR_4Circle_Reduction/hfctables.py b/scripts/HFIR_4Circle_Reduction/hfctables.py
index 16fb17171b4b5a9199e73ae5b7ab1aaee71b9f07..59fb66e84c52ab3a0b8a7a25881729482335e606 100644
--- a/scripts/HFIR_4Circle_Reduction/hfctables.py
+++ b/scripts/HFIR_4Circle_Reduction/hfctables.py
@@ -1,10 +1,12 @@
 #pylint: disable=W0403,C0103,R0901,R0904,R0913,C0302
+from __future__ import (absolute_import, division, print_function)
+from six.moves import range
 import numpy
 import sys
-import fourcircle_utility
-import guiutility
+from HFIR_4Circle_Reduction import fourcircle_utility
+from HFIR_4Circle_Reduction import guiutility
 
-import NTableWidget as tableBase
+import HFIR_4Circle_Reduction.NTableWidget as tableBase
 
 
 class KShiftTableWidget(tableBase.NTableWidget):
@@ -212,7 +214,7 @@ class PeaksIntegrationSpreadSheet(tableBase.NTableWidget):
         row_list = [None] * len(self.Table_Setup)
         status, msg = self.append_row(row_list)
         if not status:
-            print '[ERROR] Unable to append a new row due to {0}.'.format(msg)
+            print('[ERROR] Unable to append a new row due to {0}.'.format(msg))
         else:
             row_list[0] = 123
             row_list[1] = ''
@@ -409,7 +411,7 @@ class PeakIntegrationTableWidget(tableBase.NTableWidget):
         signal = -1
 
         num_rows = len(pt_vec)
-        for i_row in xrange(num_rows):
+        for i_row in range(num_rows):
             pt = int(pt_vec[i_row])
             intensity = intensity_vec[i_row]
             item_list = [pt, hkl, q, signal, intensity]
@@ -428,7 +430,7 @@ class PeakIntegrationTableWidget(tableBase.NTableWidget):
 
         # locate
         index_q_x = self.Table_Setup.index(('Q_x', 'float'))
-        for j in xrange(3):
+        for j in range(3):
             col_index = j + index_q_x
             self.update_cell_value(row_index, col_index, vec_q[j])
         # END-FOR (j)
@@ -469,8 +471,8 @@ class UBMatrixTable(tableBase.NTableWidget):
 
         # Matrix
         self._matrix = numpy.ndarray((3, 3), float)
-        for i in xrange(3):
-            for j in xrange(3):
+        for i in range(3):
+            for j in range(3):
                 self._matrix[i][j] = 0.
 
         return
@@ -480,8 +482,8 @@ class UBMatrixTable(tableBase.NTableWidget):
         Set values in holder '_matrix' to TableWidget
         :return:
         """
-        for i_row in xrange(3):
-            for j_col in xrange(3):
+        for i_row in range(3):
+            for j_col in range(3):
                 self.update_cell_value(i_row, j_col, self._matrix[i_row][j_col])
 
         return
@@ -522,8 +524,8 @@ class UBMatrixTable(tableBase.NTableWidget):
 
         # Set value
         i_array = 0
-        for i in xrange(3):
-            for j in xrange(3):
+        for i in range(3):
+            for j in range(3):
                 self._matrix[i][j] = element_array[i_array]
                 i_array += 1
 
@@ -542,8 +544,8 @@ class UBMatrixTable(tableBase.NTableWidget):
         assert isinstance(matrix, numpy.ndarray), 'Input matrix must be numpy.ndarray, but not %s' % str(type(matrix))
         assert matrix.shape == (3, 3)
 
-        for i in xrange(3):
-            for j in xrange(3):
+        for i in range(3):
+            for j in range(3):
                 self._matrix[i][j] = matrix[i][j]
 
         self._set_to_table()
@@ -557,8 +559,8 @@ class UBMatrixTable(tableBase.NTableWidget):
         """
         # self.init_size(3, 3)
 
-        for i in xrange(3):
-            for j in xrange(3):
+        for i in range(3):
+            for j in range(3):
                 self.set_value_cell(i, j)
 
         self._set_to_table()
@@ -1043,7 +1045,7 @@ class ProcessTableWidget(tableBase.NTableWidget):
             '' % (str(scan_number), type(scan_number))
         num_rows = self.rowCount()
         ret_row_number = None
-        for i_row in xrange(num_rows):
+        for i_row in range(num_rows):
             tmp_scan_no = self.get_cell_value(i_row, self._colIndexScan)
             if scan_number == tmp_scan_no:
                 ret_row_number = i_row
@@ -1069,7 +1071,7 @@ class ProcessTableWidget(tableBase.NTableWidget):
         # Loop around to check
         return_list = list()
         num_rows = self.rowCount()
-        for i_row in xrange(num_rows):
+        for i_row in range(num_rows):
             status_i = self.get_cell_value(i_row, self._colIndexStatus)
             if status_i == target_state:
                 return_list.append(i_row)
@@ -1141,7 +1143,7 @@ class ProcessTableWidget(tableBase.NTableWidget):
         scan_list = list()
         num_rows = self.rowCount()
 
-        for i_row in xrange(num_rows):
+        for i_row in range(num_rows):
             scan_num = self.get_cell_value(i_row, self._colIndexScan)
             if output_row_number:
                 scan_list.append((scan_num, i_row))
@@ -1159,7 +1161,7 @@ class ProcessTableWidget(tableBase.NTableWidget):
         num_rows = self.rowCount()
         col_select_index = self._myColumnNameList.index('Select')
 
-        for i_row in xrange(num_rows):
+        for i_row in range(num_rows):
             if self.get_cell_value(i_row, col_select_index) is True:
                 scan_num = self.get_cell_value(i_row, self._colIndexScan)
                 scan_list.append((scan_num, i_row))
@@ -1395,7 +1397,7 @@ class ScanSurveyTable(tableBase.NTableWidget):
         self._myScanSummaryList = list()
 
         self._currStartScan = 0
-        self._currEndScan = sys.maxint
+        self._currEndScan = sys.maxsize
         self._currMinCounts = 0.
         self._currMaxCounts = sys.float_info.max
 
@@ -1457,7 +1459,7 @@ class ScanSurveyTable(tableBase.NTableWidget):
         self.remove_all_rows()
 
         # go through all rows in the original list and then reconstruct
-        for index in xrange(len(self._myScanSummaryList)):
+        for index in range(len(self._myScanSummaryList)):
             sum_item = self._myScanSummaryList[index]
             # check
             assert isinstance(sum_item, list)
@@ -1561,7 +1563,7 @@ class ScanSurveyTable(tableBase.NTableWidget):
         assert num_rows > 0
         assert len(self._myScanSummaryList) > 0
 
-        for i_ref in xrange(min(num_rows, len(self._myScanSummaryList))):
+        for i_ref in range(min(num_rows, len(self._myScanSummaryList))):
             # get counts
             scan_summary = self._myScanSummaryList[i_ref]
             # check
diff --git a/scripts/HFIR_4Circle_Reduction/integratedpeakview.py b/scripts/HFIR_4Circle_Reduction/integratedpeakview.py
index 6ea8f631586722766915b949116b8c8fe62ac0f0..510ef972bf8f27013e587745e0b2a11d153d030d 100644
--- a/scripts/HFIR_4Circle_Reduction/integratedpeakview.py
+++ b/scripts/HFIR_4Circle_Reduction/integratedpeakview.py
@@ -1,6 +1,7 @@
 #pylint: disable=W0403,R0904,R0903
+from __future__ import (absolute_import, division, print_function)
 import numpy
-import mplgraphicsview
+from HFIR_4Circle_Reduction import mplgraphicsview
 
 
 class IntegratedPeakView(mplgraphicsview.MplGraphicsView):
diff --git a/scripts/HFIR_4Circle_Reduction/message_dialog.py b/scripts/HFIR_4Circle_Reduction/message_dialog.py
index 1e1d7385e1cc40282e117f65547f9c549ccf5cde..1e5cba01e2d1872baa514b0c90b533e13fe316b1 100644
--- a/scripts/HFIR_4Circle_Reduction/message_dialog.py
+++ b/scripts/HFIR_4Circle_Reduction/message_dialog.py
@@ -1,7 +1,9 @@
 # Dialog for message
+from __future__ import (absolute_import, division, print_function)
+from six.moves import range
 from PyQt4 import QtGui, QtCore
 
-import ui_messagebox
+from . import ui_messagebox
 
 
 class MessageDialog(QtGui.QDialog):
diff --git a/scripts/HFIR_4Circle_Reduction/mpl2dgraphicsview.py b/scripts/HFIR_4Circle_Reduction/mpl2dgraphicsview.py
index f49c1e9235fdc23a40511bd6b1caca53d3ba8e61..2ccca8920638a65f44903d42485b1492eb49ceaf 100644
--- a/scripts/HFIR_4Circle_Reduction/mpl2dgraphicsview.py
+++ b/scripts/HFIR_4Circle_Reduction/mpl2dgraphicsview.py
@@ -1,4 +1,5 @@
 #pylint: disable=invalid-name,too-many-public-methods,too-many-arguments,non-parent-init-called,R0901,R0902,too-many-branches,C0302
+from __future__ import (absolute_import, division, print_function)
 import os
 import numpy as np
 
@@ -213,8 +214,7 @@ class Qt4Mpl2dCanvas(FigureCanvas):
             # it will always label the first N ticks even image is zoomed in
             # FUTURE-VZ : The way to set up the Y-axis ticks is wrong!"
             # self.axes.set_yticklabels(yticklabels)
-            print '[Warning] The method to set up the Y-axis ticks to 2D image is ' \
-                  'wrong!'
+            print('[Warning] The method to set up the Y-axis ticks to 2D image is wrong!')
 
         # explicitly set aspect ratio of the image
         self.axes.set_aspect('auto')
diff --git a/scripts/HFIR_4Circle_Reduction/mplgraphicsview.py b/scripts/HFIR_4Circle_Reduction/mplgraphicsview.py
index a9ba39c9dc4e98f96e022d47581a88bb54fce0da..94085f529f4abd23bb00616f74598dee4168df56 100644
--- a/scripts/HFIR_4Circle_Reduction/mplgraphicsview.py
+++ b/scripts/HFIR_4Circle_Reduction/mplgraphicsview.py
@@ -1,4 +1,6 @@
 #pylint: disable=invalid-name,too-many-public-methods,too-many-arguments,non-parent-init-called,R0902,too-many-branches,C0302
+from __future__ import (absolute_import, division, print_function)
+from six.moves import range
 import os
 import numpy as np
 
@@ -1222,7 +1224,7 @@ class Qt4MplCanvas(FigureCanvas):
             self._lineDict[line_key] = r[0]
             self._lineIndex += 1
         else:
-            print "Impoooooooooooooooosible!"
+            print("Impoooooooooooooooosible!")
 
         # Flush/commit
         self.draw()
@@ -1250,7 +1252,7 @@ class Qt4MplCanvas(FigureCanvas):
         # set y ticks as an option:
         if yticklabels is not None:
             # it will always label the first N ticks even image is zoomed in
-            print "--------> [FixMe]: The way to set up the Y-axis ticks is wrong!"
+            print("--------> [FixMe]: The way to set up the Y-axis ticks is wrong!")
             #self.axes.set_yticklabels(yticklabels)
 
         # explicitly set aspect ratio of the image
@@ -1291,7 +1293,7 @@ class Qt4MplCanvas(FigureCanvas):
         contour_plot = self.axes.contourf(grid_x, grid_y, matrix_z, 100)
 
         labels = [item.get_text() for item in self.axes.get_yticklabels()]
-        print '[DB...BAT] Number of Y labels = ', len(labels), ', Number of Y = ', len(vec_y)
+        print('[DB...BAT] Number of Y labels = ', len(labels), ', Number of Y = ', len(vec_y))
 
         # TODO/ISSUE/55: how to make this part more powerful
         if len(labels) == 2*len(vec_y) - 1:
@@ -1350,8 +1352,8 @@ class Qt4MplCanvas(FigureCanvas):
                 try:
                     self.axes.lines.remove(plot)
                 except ValueError as e:
-                    print "[Error] Plot %s is not in axes.lines which has %d lines. Error mesage: %s" % (
-                        str(plot), len(self.axes.lines), str(e))
+                    print("[Error] Plot %s is not in axes.lines which has %d lines. Error mesage: %s" % (
+                        str(plot), len(self.axes.lines), str(e)))
                 del self._lineDict[ikey]
             else:
                 # error bar
@@ -1571,7 +1573,7 @@ class Qt4MplCanvas(FigureCanvas):
         """
         line = self._lineDict[ikey]
         if line is None:
-            print '[ERROR] Line (key = %d) is None. Unable to update' % ikey
+            print('[ERROR] Line (key = %d) is None. Unable to update' % ikey)
             return
 
         if vecx is not None and vecy is not None:
@@ -1640,9 +1642,9 @@ class Qt4MplCanvas(FigureCanvas):
         num_markers = len(MplLineMarkers)
         num_colors = len(MplBasicColors)
 
-        for i in xrange(num_markers):
+        for i in range(num_markers):
             marker = MplLineMarkers[i]
-            for j in xrange(num_colors):
+            for j in range(num_colors):
                 color = MplBasicColors[j]
                 combo_list.append((marker, color))
             # ENDFOR (j)
@@ -1797,7 +1799,7 @@ class MyNavigationToolbar(NavigationToolbar2):
             # into pan mode
             self._myMode = MyNavigationToolbar.NAVIGATION_MODE_PAN
 
-        print 'PANNED'
+        print('PANNED')
 
         return
 
diff --git a/scripts/HFIR_4Circle_Reduction/mplgraphicsview3d.py b/scripts/HFIR_4Circle_Reduction/mplgraphicsview3d.py
index da1b11b1872f77403bf9f25f08c06b7a7a9e7b87..f8a561b39a7e6cf96e22467dfed4aa41faa2a859 100644
--- a/scripts/HFIR_4Circle_Reduction/mplgraphicsview3d.py
+++ b/scripts/HFIR_4Circle_Reduction/mplgraphicsview3d.py
@@ -1,4 +1,6 @@
 #pylint: disable=R0901,R0902,R0904
+from __future__ import (absolute_import, division, print_function)
+from six.moves import range
 import numpy as np
 import os
 
@@ -108,7 +110,7 @@ class MplPlot3dCanvas(FigureCanvas):
         intensities = np.zeros((len(raw_lines), ))
 
         # parse
-        for i in xrange(len(raw_lines)):
+        for i in range(len(raw_lines)):
             line = raw_lines[i].strip()
 
             # skip empty line
@@ -117,7 +119,7 @@ class MplPlot3dCanvas(FigureCanvas):
 
             # set value
             terms = line.split(',')
-            for j in xrange(3):
+            for j in range(3):
                 xyz_points[i][j] = float(terms[j])
             intensities[i] = float(terms[3])
         # END-FOR
@@ -175,15 +177,15 @@ class MplPlot3dCanvas(FigureCanvas):
             x_min = min(points[:, 0])
             x_max = max(points[:, 0])
             d_x = x_max - x_min
-            # print x_min, x_max
+            # print(x_min, x_max)
             y_min = min(points[:, 1])
             y_max = max(points[:, 1])
             d_y = y_max - y_min
-            # print y_min, y_max
+            # print(y_min, y_max)
             z_min = min(points[:, 2])
             z_max = max(points[:, 2])
             d_z = z_max - z_min
-            print z_min, z_max
+            print(z_min, z_max)
 
             # use default setup
             self._myAxes.set_xlim(x_min-d_x, x_max+d_x)
@@ -208,7 +210,7 @@ class MplPlot3dCanvas(FigureCanvas):
             b_list = b_list/diff
 
             num_points = len(points[:, 2])
-            for index in xrange(num_points):
+            for index in range(num_points):
                 color_tup = (color_r, color_g, b_list[index])
                 color_list.append(color_tup)
         else:
@@ -224,7 +226,7 @@ class MplPlot3dCanvas(FigureCanvas):
         Plot surface
         :return:
         """
-        print 'Number of surf = ', len(self._currSurfaceList)
+        print('Number of surf = ', len(self._currSurfaceList))
         for surf in self._currSurfaceList:
             plt = self._myAxes.plot_surface(surf["xx"], surf["yy"], surf["val"],
                                             rstride=5, cstride=5,  # color map??? cmap=cm.jet,
@@ -317,16 +319,16 @@ def get_auto_xyz_limit(points):
     x_max = max(points[:, 0])
     d_x = x_max - x_min
 
-    # print x_min, x_max
+    # print(x_min, x_max)
     y_min = min(points[:, 1])
     y_max = max(points[:, 1])
     d_y = y_max - y_min
 
-    # print y_min, y_max
+    # print(y_min, y_max)
     z_min = min(points[:, 2])
     z_max = max(points[:, 2])
     d_z = z_max - z_min
-    print z_min, z_max
+    print(z_min, z_max)
 
     # use default setup
     x_lim = (x_min-d_x, x_max+d_x)
diff --git a/scripts/HFIR_4Circle_Reduction/multi_threads_helpers.py b/scripts/HFIR_4Circle_Reduction/multi_threads_helpers.py
index 5fd1e648ba1c729c9026be73b734131da09c6a5a..9c52e63cd10b9c2307b2c795b5ee2401b56891cc 100644
--- a/scripts/HFIR_4Circle_Reduction/multi_threads_helpers.py
+++ b/scripts/HFIR_4Circle_Reduction/multi_threads_helpers.py
@@ -1,9 +1,10 @@
 #pylint: disable=W0403,R0913,R0902
+from __future__ import (absolute_import, division, print_function)
 from PyQt4 import QtCore
 from PyQt4.QtCore import QThread
 
-import reduce4circleControl as r4c
-import peak_integration_utility
+import HFIR_4Circle_Reduction.reduce4circleControl as r4c
+from HFIR_4Circle_Reduction import peak_integration_utility
 
 
 class AddPeaksThread(QThread):
diff --git a/scripts/HFIR_4Circle_Reduction/optimizelatticewindow.py b/scripts/HFIR_4Circle_Reduction/optimizelatticewindow.py
index 5fc178a07ee8fe0aa392f0b9b934e7931a58aac2..49557483869f56263b3e6aa9aa1c91efef7b7e55 100644
--- a/scripts/HFIR_4Circle_Reduction/optimizelatticewindow.py
+++ b/scripts/HFIR_4Circle_Reduction/optimizelatticewindow.py
@@ -1,7 +1,8 @@
 #pylint: disable=C0103
+from __future__ import (absolute_import, division, print_function)
 from PyQt4 import QtGui, QtCore
 
-import ui_OptimizeLattice
+from . import ui_OptimizeLattice
 
 
 class OptimizeLatticeWindow(QtGui.QMainWindow):
diff --git a/scripts/HFIR_4Circle_Reduction/peak_integration_utility.py b/scripts/HFIR_4Circle_Reduction/peak_integration_utility.py
index ef5464087af3f60d518061adb381bbdb609df17d..c7e8234801001e547ef186a02a7930f16e1bfb17 100644
--- a/scripts/HFIR_4Circle_Reduction/peak_integration_utility.py
+++ b/scripts/HFIR_4Circle_Reduction/peak_integration_utility.py
@@ -1,4 +1,6 @@
 # Utility methods to do peak integration
+from __future__ import (absolute_import, division, print_function)
+from six.moves import range
 import numpy
 import math
 from scipy.optimize import curve_fit
@@ -28,8 +30,8 @@ def calculate_lorentz_correction_factor(q_sample, wavelength, motor_step):
     theta = math.asin(sin_theta)
     factor = numpy.sin(2 * theta) * motor_step
 
-    # print '[DB...BAT Lorentz] Q-sample = {0}, wavelength = {1}, motor step = {2}, theta = {3} --> factor = {4}.' \
-    #       ''.format(q_sample, wavelength, motor_step, theta, factor)
+    # print('[DB...BAT Lorentz] Q-sample = {0}, wavelength = {1}, motor step = {2}, theta = {3} --> factor = {4}.' \
+    #       ''.format(q_sample, wavelength, motor_step, theta, factor))
 
     return factor
 
@@ -175,11 +177,11 @@ def fit_gaussian_linear_background(vec_x, vec_y, vec_e, start_value_list=None, f
     assert isinstance(vec_y, numpy.ndarray), 'Input vec_y must be a numpy.ndarray but not a {0}.'.format(vec_y)
     assert isinstance(vec_e, numpy.ndarray), 'Input vec_e must be a numpy.ndarray but not a {0}.'.format(vec_e)
 
-    # print '[DB] Vec X: ', vec_x
-    # print '[DB] Vec Y: ', vec_y
-    # print '[DB] Vec e: ', vec_e
-    # print '[DB] Start values: ', start_value_list
-    # print '[DB] Find start value by fit: ', find_start_value_by_fit
+    # print('[DB] Vec X: ', vec_x)
+    # print('[DB] Vec Y: ', vec_y)
+    # print('[DB] Vec e: ', vec_e)
+    # print('[DB] Start values: ', start_value_list)
+    # print('[DB] Find start value by fit: ', find_start_value_by_fit)
 
     # starting value
     if isinstance(start_value_list, list):
@@ -192,13 +194,13 @@ def fit_gaussian_linear_background(vec_x, vec_y, vec_e, start_value_list=None, f
         # get result
         start_value_list = [start_x0, start_sigma, start_a, 0.0]
 
-        # print '[DB] Start value by fit: ', start_value_list
+        # print('[DB] Start value by fit: ', start_value_list)
 
     else:
         # guess starting value via observation
         start_value_list = find_gaussian_start_values_by_observation(vec_x, vec_y)
 
-        # print '[DB] Start value by observation: ', start_value_list
+        # print('[DB] Start value by observation: ', start_value_list)
     # END-IF-ELSE
 
     """
@@ -216,7 +218,7 @@ def fit_gaussian_linear_background(vec_x, vec_y, vec_e, start_value_list=None, f
     x0, sigma, a, b = fit2_coeff
     model_vec_y = gaussian_linear_background(vec_x, x0, sigma, a, b)
 
-    print 'Covariance matrix: ', fit2_cov_matrix
+    print('Covariance matrix: ', fit2_cov_matrix)
 
     cost = calculate_penalty(model_vec_y, vec_y)
 
@@ -264,9 +266,9 @@ def fit_motor_intensity_model(motor_pos_dict, integrated_pt_dict):
 
     # fit
     gauss_error, gauss_parameters, cov_matrix = fit_gaussian_linear_background(vec_x, vec_y, vec_e)
-    # print '[DB] Overall Gaussian error = ', gauss_error
-    # print '[DB] Gaussian fitted parameters = ', gauss_parameters
-    # print '[DB] Gaussian covariance matrix = ', cov_matrix
+    # print('[DB] Overall Gaussian error = ', gauss_error)
+    # print('[DB] Gaussian fitted parameters = ', gauss_parameters)
+    # print('[DB] Gaussian covariance matrix = ', cov_matrix)
 
     # function parameters (in order): x0, sigma, a, b
     # construct parameter dictionary and error dictionary
@@ -377,7 +379,7 @@ def gaussian_linear_background(x, x0, sigma, a, b):
     """
     # gaussian + linear background
 
-    # print '[DB] Input x0 = ', x0, ', sigma = ', sigma, ', a = ', a, ', b = ', b
+    # print('[DB] Input x0 = ', x0, ', sigma = ', sigma, ', a = ', a, ', b = ', b)
     return a * numpy.exp(-(x - x0) ** 2 / (2. * sigma ** 2)) + b
 
 
@@ -411,7 +413,7 @@ def gaussian_peak_intensity(parameter_dict, error_dict):
 
     # I = A\times s\times\sqrt{2 pi}
     peak_intensity = gauss_a * gauss_sigma * numpy.sqrt(2. * numpy.pi)
-    # print '[DB] Gaussian Peak Intensity: A * S * sqrt(2 Pi) == ', gauss_a, gauss_sigma, ' --> peak intensity = ', peak_intensity
+    # print('[DB] Gaussian Peak Intensity: A * S * sqrt(2 Pi) == ', gauss_a, gauss_sigma, ' --> peak intensity = ', peak_intensity)
 
     # calculate error
     # \sigma_I^2 = 2\pi (A^2\cdot \sigma_s^2 + \sigma_A^2\cdot s^2 + 2\cdot A\cdot s\cdot \sigma_{As})
@@ -546,7 +548,7 @@ def integrate_single_scan_peak(merged_scan_workspace_name, integrated_peak_ws_na
     out_peak_ws = AnalysisDataService.retrieve(integrated_peak_ws_name)
     num_peaks = out_peak_ws.rowCount()
 
-    for i_peak in xrange(num_peaks):
+    for i_peak in range(num_peaks):
         peak_i = out_peak_ws.getPeak(i_peak)
         run_number_i = peak_i.getRunNumber() % 1000
         intensity_i = peak_i.getIntensity()
@@ -756,7 +758,7 @@ def simple_integrate_peak(pt_intensity_dict, bg_value, motor_step_dict, peak_cen
 
         used_pt_list.append(pt)
 
-        # print '[DB...BAT] Motor step size {0} = {1}'.format(pt, motor_step_i)
+        # print('[DB...BAT] Motor step size {0} = {1}'.format(pt, motor_step_i))
     # END-FOR
 
     # error = sqrt(sum I_i) * delta
diff --git a/scripts/HFIR_4Circle_Reduction/peakprocesshelper.py b/scripts/HFIR_4Circle_Reduction/peakprocesshelper.py
index a418d0158086db36f200cd9e31a9054a0c1c8743..a69a2c19c6e8cd9b97ad3cfe677bf49682356d4f 100644
--- a/scripts/HFIR_4Circle_Reduction/peakprocesshelper.py
+++ b/scripts/HFIR_4Circle_Reduction/peakprocesshelper.py
@@ -1,7 +1,9 @@
 #pylint: disable=W0403,R0902
+from __future__ import (absolute_import, division, print_function)
+from six.moves import range
 import time
 import random
-from fourcircle_utility import *
+from HFIR_4Circle_Reduction.fourcircle_utility import *
 from mantid.api import AnalysisDataService
 from mantid.kernel import V3D
 
@@ -66,8 +68,8 @@ class PeakProcessRecord(object):
         # Figure print
         self._fingerPrint = '{0:.7f}.{1}'.format(time.time(), random.randint(0, 10000000))
 
-        # print '[DB...BAT] Create PeakProcessRecord for Exp {0} Scan {1} ({2} | {3}).' \
-        #       ''.format(self._myExpNumber, self._myScanNumber, self._fingerPrint, hex(id(self)))
+        # print('[DB...BAT] Create PeakProcessRecord for Exp {0} Scan {1} ({2} | {3}).' \
+        #       ''.format(self._myExpNumber, self._myScanNumber, self._fingerPrint, hex(id(self))))
         return
 
     def calculate_peak_center(self, allow_bad_monitor=True):
@@ -91,7 +93,7 @@ class PeakProcessRecord(object):
         q_sample_sum = numpy.array([0., 0., 0.])
         weight_sum = 0.
 
-        for i_peak in xrange(num_found_peaks):
+        for i_peak in range(num_found_peaks):
             # get peak
             peak_i = peak_ws.getPeak(i_peak)
             run_number = peak_i.getRunNumber()
@@ -100,7 +102,7 @@ class PeakProcessRecord(object):
             # get row number and then detector counts and monitor counts
             if pt_number not in pt_spice_row_dict:
                 # skip
-                print '[Error] Scan %d Peak %d Pt %d cannot be located.' % (self._myScanNumber, i_peak, pt_number)
+                print('[Error] Scan %d Peak %d Pt %d cannot be located.' % (self._myScanNumber, i_peak, pt_number))
                 continue
 
             row_index = pt_spice_row_dict[pt_number]
@@ -116,7 +118,7 @@ class PeakProcessRecord(object):
             q_i = peak_i.getQSampleFrame()
             q_array = numpy.array([q_i.X(), q_i.Y(), q_i.Z()])
             # calculate weight
-            print '[DB] Peak {0}: detector counts = {1}, Monitor counts = {2}.'.format(i_peak, det_counts, monitor_counts)
+            print('[DB] Peak {0}: detector counts = {1}, Monitor counts = {2}.'.format(i_peak, det_counts, monitor_counts))
             weight_i = float(det_counts)/float(monitor_counts)
             # contribute to total
             weight_sum += weight_i
@@ -126,7 +128,7 @@ class PeakProcessRecord(object):
         # END-FOR (i_peak)
 
         try:
-            print '[DB] calculate value error: sum(Q-sample) = {0}, sum(weight) = {1}.'.format(q_sample_sum, weight_sum)
+            print('[DB] calculate value error: sum(Q-sample) = {0}, sum(weight) = {1}.'.format(q_sample_sum, weight_sum))
             self._avgPeakCenter = q_sample_sum/weight_sum
         except Exception as e:
             raise RuntimeError('Unable to calculate average peak center due to value error as {0}.'.format(e))
@@ -138,8 +140,8 @@ class PeakProcessRecord(object):
         generate a dictionary for this PeakInfo
         :return:
         """
-        # print '[DB...BAT] PeakInfo (Scan: {0}, ID: {1}) generate report.  Spice HKL: {2}' \
-        #       ''.format(self._myScanNumber, hex(id(self)), self._spiceHKL)
+        # print('[DB...BAT] PeakInfo (Scan: {0}, ID: {1}) generate report.  Spice HKL: {2}' \
+        #       ''.format(self._myScanNumber, hex(id(self)), self._spiceHKL))
 
         report = dict()
 
@@ -280,8 +282,8 @@ class PeakProcessRecord(object):
             self.retrieve_hkl_from_spice_table()
             ret_hkl = self._spiceHKL
 
-            # print '[DB...BAT] PeakInfo (Scan: {0}, ID: {1}) SPICE HKL: {2}' \
-            #       ''.format(self._myScanNumber, hex(id(self)), self._spiceHKL)
+            # print('[DB...BAT] PeakInfo (Scan: {0}, ID: {1}) SPICE HKL: {2}' \
+            #       ''.format(self._myScanNumber, hex(id(self)), self._spiceHKL))
 
         return ret_hkl
 
@@ -319,7 +321,7 @@ class PeakProcessRecord(object):
         peak_center_list = list()
         peak_intensity_list = list()
         num_peaks = peak_ws.getNumberPeaks()
-        for i_peak in xrange(num_peaks):
+        for i_peak in range(num_peaks):
             peak_i = peak_ws.getPeak(i_peak)
             center_i = peak_i.getQSampleFrame()
             intensity_i = peak_i.getIntensity()
@@ -363,8 +365,8 @@ class PeakProcessRecord(object):
         assert isinstance(factor, float), 'Lorentz correction factor'
         self._lorenzFactor = factor
 
-        # print '[DB...BAT] Exp {0} Scan {1}  ({2} | {3}) has Lorentz factor set up.' \
-        #       ''.format(self._myExpNumber, self._myScanNumber, self._fingerPrint, hex(id(self)))
+        # print('[DB...BAT] Exp {0} Scan {1}  ({2} | {3}) has Lorentz factor set up.' \
+        #       ''.format(self._myExpNumber, self._myScanNumber, self._fingerPrint, hex(id(self))))
 
         return
 
@@ -405,7 +407,7 @@ class PeakProcessRecord(object):
         hkl = numpy.array([0., 0., 0.])
 
         num_rows = spice_table_ws.rowCount()
-        for row_index in xrange(num_rows):
+        for row_index in range(num_rows):
             mi_h = spice_table_ws.cell(row_index, h_col_index)
             mi_k = spice_table_ws.cell(row_index, k_col_index)
             mi_l = spice_table_ws.cell(row_index, l_col_index)
@@ -517,8 +519,8 @@ class PeakProcessRecord(object):
             'Integrated peak information {0} must be given by a dictionary but not a {1}.' \
             ''.format(peak_integration_dict, type(peak_integration_dict))
 
-        # print '[DB...BAT] Exp {0} Scan {1}  ({2} | {3}) has integrated dictionary set up.' \
-        #       ''.format(self._myExpNumber, self._myScanNumber, self._fingerPrint, hex(id(self)))
+        # print('[DB...BAT] Exp {0} Scan {1}  ({2} | {3}) has integrated dictionary set up.' \
+        #       ''.format(self._myExpNumber, self._myScanNumber, self._fingerPrint, hex(id(self))))
 
         self._integrationDict = peak_integration_dict
 
@@ -556,7 +558,7 @@ def build_pt_spice_table_row_map(spice_table_ws):
     num_rows = spice_table_ws.rowCount()
     pt_col_index = spice_table_ws.getColumnNames().index('Pt.')
 
-    for i_row in xrange(num_rows):
+    for i_row in range(num_rows):
         pt_number = int(spice_table_ws.cell(i_row, pt_col_index))
         pt_spice_row_dict[pt_number] = i_row
 
diff --git a/scripts/HFIR_4Circle_Reduction/plot3dwindow.py b/scripts/HFIR_4Circle_Reduction/plot3dwindow.py
index 3a63a60899e0b80681c2b70309f6e26d90478b12..efea413836d5c09a135731b414f82730489bc514 100644
--- a/scripts/HFIR_4Circle_Reduction/plot3dwindow.py
+++ b/scripts/HFIR_4Circle_Reduction/plot3dwindow.py
@@ -1,10 +1,12 @@
 #pylint: disable=C0103,W0403
+from __future__ import (absolute_import, division, print_function)
+from six.moves import range
 import sys
 import numpy as np
 from PyQt4 import QtGui, QtCore
 
-import ui_View3DWidget
-import guiutility
+from . import ui_View3DWidget
+from HFIR_4Circle_Reduction import guiutility
 
 __author__ = 'wzz'
 
@@ -110,7 +112,7 @@ class Plot3DWindow(QtGui.QMainWindow):
         if threshold_lower is None:
             threshold_lower = 0
         if threshold_upper is None:
-            threshold_upper = sys.maxint
+            threshold_upper = sys.maxsize
         assert 0 <= threshold_lower < threshold_upper
 
         # get data key
@@ -123,7 +125,7 @@ class Plot3DWindow(QtGui.QMainWindow):
         assert points is not None
         num_within_threshold = 0
         array_size = len(intensity_array)
-        for index in xrange(array_size):
+        for index in range(array_size):
             if threshold_lower <= intensity_array[index] <= threshold_upper:
                 num_within_threshold += 1
         # END-FOR
@@ -199,7 +201,7 @@ class Plot3DWindow(QtGui.QMainWindow):
         if thresholds[0] is None:
             thresholds[0] = 0
         if thresholds[1] is None:
-            thresholds[1] = sys.maxint
+            thresholds[1] = sys.maxsize
         assert 0 <= thresholds[0] < thresholds[1]
 
         # data key
@@ -258,7 +260,7 @@ class Plot3DWindow(QtGui.QMainWindow):
 
         # Format intensity to color map
         color_list = guiutility.map_to_color(intensities, base_color, change_color)
-        # print color_list
+        # print(color_list)
         assert len(color_list) == len(points)
 
         # self.ui.graphicsView.plot_scatter(data_key, base_color)
@@ -306,7 +308,7 @@ def filter_points_by_intensity(points, intensities, lower_boundary, upper_bounda
     # calculate data size
     raw_array_size = len(intensities)
     new_array_size = 0
-    for index in xrange(raw_array_size):
+    for index in range(raw_array_size):
         if lower_boundary <= intensities[index] <= upper_boundary:
             new_array_size += 1
     # END-FOR
@@ -315,7 +317,7 @@ def filter_points_by_intensity(points, intensities, lower_boundary, upper_bounda
     new_points = np.ndarray(shape=(new_array_size, 3), dtype='float')
     new_intensities = np.ndarray(shape=(new_array_size,), dtype='float')
     new_index = 0
-    for raw_index in xrange(raw_array_size):
+    for raw_index in range(raw_array_size):
         if lower_boundary <= intensities[raw_index] <= upper_boundary:
             assert new_index < new_array_size
             new_points[new_index] = points[raw_index]
diff --git a/scripts/HFIR_4Circle_Reduction/project_manager.py b/scripts/HFIR_4Circle_Reduction/project_manager.py
index 656a158e8e6d92b81944520aa3553752e3a51ed8..ed3e86cd74f33501ee235912dafb89ee1b337ba8 100644
--- a/scripts/HFIR_4Circle_Reduction/project_manager.py
+++ b/scripts/HFIR_4Circle_Reduction/project_manager.py
@@ -1,3 +1,4 @@
+from __future__ import (absolute_import, division, print_function)
 import os
 
 import mantid.simpleapi as mantidsimple
@@ -76,7 +77,7 @@ class ProjectManager(object):
         # create workspace directory
         self.create_workspace_directory()
 
-        print '[INFO] Saving {0} MDEventWorkspaces to {1}.'.format(len(self._wsList), self._wsDir)
+        print('[INFO] Saving {0} MDEventWorkspaces to {1}.'.format(len(self._wsList), self._wsDir))
 
         # save MDs
         for ws_name in self._wsList:
@@ -85,9 +86,9 @@ class ProjectManager(object):
                 try:
                     mantidsimple.SaveMD(InputWorkspace=ws_name, Filename=md_file_name)
                 except RuntimeError as run_err:
-                    print '[ERROR] Unable to save {0} due to RuntimeError {1}.'.format(ws_name, run_err)
+                    print('[ERROR] Unable to save {0} due to RuntimeError {1}.'.format(ws_name, run_err))
                 except Exception as arb_err:
-                    print '[ERROR] Unable to save {0} due to arbitrary exception {1}.'.format(ws_name, arb_err)
+                    print('[ERROR] Unable to save {0} due to arbitrary exception {1}.'.format(ws_name, arb_err))
             # END-IF
         # END-FOR (ws_name)
 
@@ -113,11 +114,11 @@ class ProjectManager(object):
             try:
                 mantidsimple.LoadMD(Filename=md_file_path, OutputWorkspace=ws_name)
             except RuntimeError as run_err:
-                print '[DB] Unable to load file {0} due to RuntimeError {1}.'.format(md_file_path, run_err)
+                print('[DB] Unable to load file {0} due to RuntimeError {1}.'.format(md_file_path, run_err))
             except OSError as run_err:
-                print '[DB] Unable to load file {0} due to OSError {1}.'.format(md_file_path, run_err)
+                print('[DB] Unable to load file {0} due to OSError {1}.'.format(md_file_path, run_err))
             except IOError as run_err:
-                print '[DB] Unable to load file {0} due to IOError {1}.'.format(md_file_path, run_err)
+                print('[DB] Unable to load file {0} due to IOError {1}.'.format(md_file_path, run_err))
         # END-FOR
 
         return
diff --git a/scripts/HFIR_4Circle_Reduction/reduce4circleControl.py b/scripts/HFIR_4Circle_Reduction/reduce4circleControl.py
index 0df9b5082a500e2c32d2e7dca38ac2cdba5d6029..ede9ab68266c41517fa96418efaa62d5254767ca 100644
--- a/scripts/HFIR_4Circle_Reduction/reduce4circleControl.py
+++ b/scripts/HFIR_4Circle_Reduction/reduce4circleControl.py
@@ -8,16 +8,18 @@
 # - Download from internet to cache (download-mode)
 #
 ################################################################################
+from __future__ import (absolute_import, division, print_function)
+from six.moves import range
 import csv
 import random
 import os
 
-from fourcircle_utility import *
-from peakprocesshelper import PeakProcessRecord
-import fputility
-import project_manager
-import peak_integration_utility
-import absorption
+from HFIR_4Circle_Reduction.fourcircle_utility import *
+from HFIR_4Circle_Reduction.peakprocesshelper import PeakProcessRecord
+from HFIR_4Circle_Reduction import fputility
+from HFIR_4Circle_Reduction import project_manager
+from HFIR_4Circle_Reduction import peak_integration_utility
+from HFIR_4Circle_Reduction import absorption
 
 import mantid
 import mantid.simpleapi as mantidsimple
@@ -680,8 +682,8 @@ class CWSCDReductionControl(object):
 
                 if intensity < std_dev:
                     # error is huge, very likely bad gaussian fit
-                    print '[INFO] Integration Type {0}: Scan {1} Intensity {2} < Std Dev {2} Excluded from exporting.' \
-                          ''.format(algorithm_type, scan_number, intensity, std_dev)
+                    print('[INFO] Integration Type {0}: Scan {1} Intensity {2} < Std Dev {2} '
+                          'Excluded from exporting.'.format(algorithm_type, scan_number, intensity, std_dev))
                     continue
                 # END-IF
 
@@ -783,7 +785,7 @@ class CWSCDReductionControl(object):
 
         pt_number_list = []
         num_rows = table_ws.rowCount()
-        for i in xrange(num_rows):
+        for i in range(num_rows):
             pt_number = table_ws.cell(i, i_pt)
             pt_number_list.append(pt_number)
 
@@ -805,8 +807,8 @@ class CWSCDReductionControl(object):
         # Convert to numpy array
         det_shape = (self._detectorSize[0], self._detectorSize[1])
         array2d = numpy.ndarray(shape=det_shape, dtype='float')
-        for i in xrange(det_shape[0]):
-            for j in xrange(det_shape[1]):
+        for i in range(det_shape[0]):
+            for j in range(det_shape[1]):
                 array2d[i][j] = raw_ws.readY(j * det_shape[0] + i)[0]
 
         # Flip the 2D array to look detector from sample
@@ -924,8 +926,8 @@ class CWSCDReductionControl(object):
                                                                 'it is of type %s now.' % (str(pt_number),
                                                                                            type(pt_number))
 
-        # print '[DB...BAT] Retrieve: Exp {0} Scan {1} Peak Info Object. Current keys are {0}.' \
-        #       ''.format(exp_number, scan_number, self._myPeakInfoDict.keys())
+        # print('[DB...BAT] Retrieve: Exp {0} Scan {1} Peak Info Object. Current keys are {0}.' \
+        #       ''.format(exp_number, scan_number, self._myPeakInfoDict.keys()))
 
         # construct key
         if pt_number is None:
@@ -936,8 +938,8 @@ class CWSCDReductionControl(object):
         # Check for existence
         if p_key in self._myPeakInfoDict:
             ret_value = self._myPeakInfoDict[p_key]
-            # print '[DB...BAT] Retrieved: Exp {0} Scan {1} Peak Info Object {2}.'.format(exp_number, scan_number,
-            #                                                                             hex(id(ret_value)))
+            # print('[DB...BAT] Retrieved: Exp {0} Scan {1} Peak Info Object {2}.'.format(exp_number, scan_number,
+            #                                                                             hex(id(ret_value))))
         else:
             ret_value = None
 
@@ -973,7 +975,7 @@ class CWSCDReductionControl(object):
         array_size = num_peaks
         vec_x = numpy.ndarray(shape=(array_size,))
         vec_y = numpy.ndarray(shape=(array_size,))
-        for index in xrange(array_size):
+        for index in range(array_size):
             peak_i = int_peak_ws.getPeak(index)
             # Note: run number in merged workspace is a combination of pt number and scan number
             #       so it should have 1000 divided for the correct pt number
@@ -1223,7 +1225,7 @@ class CWSCDReductionControl(object):
         assert isinstance(scale_factor, float) or isinstance(scale_factor, int),\
             'Scale factor {0} must be a float or integer but not a {1}.'.format(scale_factor, type(scale_factor))
         assert len(peak_centre) == 3, 'Peak center {0} must have 3 elements for (Qx, Qy, Qz).'.format(peak_centre)
-        # print '[DB...BAT] Background tuple {0} is of type {1}.'.format(background_pt_tuple, type(background_pt_tuple))
+        # print('[DB...BAT] Background tuple {0} is of type {1}.'.format(background_pt_tuple, type(background_pt_tuple)))
         assert len(background_pt_tuple) == 2, 'Background tuple {0} must be of length 2.'.format(background_pt_tuple)
 
         # get input MDEventWorkspace name for merged scan
@@ -1877,9 +1879,9 @@ class CWSCDReductionControl(object):
             error_message = None
             try:
                 result = urllib2.urlopen(self._myServerURL)
-            except urllib2.HTTPError, err:
+            except urllib2.HTTPError as err:
                 error_message = str(err.code)
-            except urllib2.URLError, err:
+            except urllib2.URLError as err:
                 error_message = str(err.args)
             else:
                 is_url_good = True
@@ -2183,7 +2185,7 @@ class CWSCDReductionControl(object):
 
         # add peak
         num_peak_info = len(peak_info_list)
-        for i_peak_info in xrange(num_peak_info):
+        for i_peak_info in range(num_peak_info):
             # Set HKL as optional
             peak_info_i = peak_info_list[i_peak_info]
             peak_ws_i = peak_info_i.get_peak_workspace()
@@ -2345,12 +2347,12 @@ class CWSCDReductionControl(object):
         # check whether there is a redundant creation of PeakProcessRecord for the same (exp, scan) combination
         if (exp_number, scan_number) in self._myPeakInfoDict:
             peak_info = self._myPeakInfoDict[(exp_number, scan_number)]
-            print '[ERROR] PeakProcessRecord for Exp {0} Scan {1} shall not be created twice!' \
-                  ''.format(exp_number, scan_number)
-            print '[CONTINUE] New PeaksWorkspace = {0} vs Existing PeaksWorkspace = {1}.' \
-                  ''.format(peak_ws_name, peak_info.peaks_workspace)
-            print '[CONTINUE] New MDEventWorkspace = {0} vs Existing MDEventWorkspace = {1}.' \
-                  ''.format(md_ws_name, peak_info.md_workspace)
+            print('[ERROR] PeakProcessRecord for Exp {0} Scan {1} shall not '
+                  'be created twice!'.format(exp_number, scan_number))
+            print('[CONTINUE] New PeaksWorkspace = {0} vs Existing '
+                  'PeaksWorkspace = {1}.'.format(peak_ws_name, peak_info.peaks_workspace))
+            print('[CONTINUE] New MDEventWorkspace = {0} vs Existing '
+                  'MDEventWorkspace = {1}.'.format(md_ws_name, peak_info.md_workspace))
             return False, peak_info
         # END-IF
 
@@ -2413,7 +2415,7 @@ class CWSCDReductionControl(object):
         """
         numrows = spice_table_ws.rowCount()
         ptlist = []
-        for irow in xrange(numrows):
+        for irow in range(numrows):
             ptno = int(spice_table_ws.cell(irow, 0))
             ptlist.append(ptno)
 
@@ -2495,8 +2497,8 @@ class CWSCDReductionControl(object):
                 try:
                     mantidsimple.DownloadFile(Address=spice_file_url, Filename=spice_file_name)
                 except RuntimeError as download_error:
-                    print '[ERROR] Unable to download scan %d from %s due to %s.' % (scan_number,spice_file_url,
-                                                                                     str(download_error))
+                    print('[ERROR] Unable to download scan %d from %s due to %s.' % (scan_number,spice_file_url,
+                                                                                     str(download_error)))
                     break
             else:
                 spice_file_name = get_spice_file_name(self._instrumentName, exp_number, scan_number)
@@ -2535,7 +2537,7 @@ class CWSCDReductionControl(object):
 
                 two_theta = m1 = -1
 
-                for i_row in xrange(num_rows):
+                for i_row in range(num_rows):
                     det_count = spice_table_ws.cell(i_row, 5)
                     if det_count > max_count:
                         max_count = det_count
@@ -2556,7 +2558,7 @@ class CWSCDReductionControl(object):
                 wavelength = get_hb3a_wavelength(m1)
                 if wavelength is None:
                     q_range = 0.
-                    print '[ERROR] Scan number {0} has invalid m1 for wavelength.'.format(scan_number)
+                    print('[ERROR] Scan number {0} has invalid m1 for wavelength.'.format(scan_number))
                 else:
                     q_range = 4.*math.pi*math.sin(two_theta/180.*math.pi*0.5)/wavelength
 
@@ -2572,7 +2574,7 @@ class CWSCDReductionControl(object):
         # END-FOR (scan_number)
 
         if error_message != '':
-            print '[Error]\n%s' % error_message
+            print('[Error]\n%s' % error_message)
 
         self._scanSummaryList = scan_sum_list
 
@@ -2609,7 +2611,7 @@ class CWSCDReductionControl(object):
         assert isinstance(project_file_name, str), 'Project file name must be a string but not of type ' \
                                                    '%s.' % type(project_file_name)
 
-        print '[INFO] Load project from %s.' % project_file_name
+        print('[INFO] Load project from %s.' % project_file_name)
 
         # instantiate a project manager instance and load the project
         saved_project = project_manager.ProjectManager(mode='import', project_file_path=project_file_name)
@@ -2636,13 +2638,13 @@ def convert_spice_ub_to_mantid(spice_ub):
     """
     mantid_ub = numpy.ndarray((3, 3), 'float')
     # row 0
-    for i in xrange(3):
+    for i in range(3):
         mantid_ub[0][i] = spice_ub[0][i]
     # row 1
-    for i in xrange(3):
+    for i in range(3):
         mantid_ub[1][i] = spice_ub[2][i]
     # row 2
-    for i in xrange(3):
+    for i in range(3):
         mantid_ub[2][i] = -1.*spice_ub[1][i]
 
     return mantid_ub
diff --git a/scripts/HFIR_4Circle_Reduction/reduce4circleGUI.py b/scripts/HFIR_4Circle_Reduction/reduce4circleGUI.py
index d40ab566cd03f5ce842531c0021bbe674096083c..3ec89d534d35ccb29c778f89e42d7188b9bb24b1 100644
--- a/scripts/HFIR_4Circle_Reduction/reduce4circleGUI.py
+++ b/scripts/HFIR_4Circle_Reduction/reduce4circleGUI.py
@@ -4,6 +4,9 @@
 # MainWindow application for reducing HFIR 4-circle
 #
 ################################################################################
+from __future__ import (absolute_import, division, print_function)
+from six.moves import range
+import six
 import os
 import sys
 import csv
@@ -11,8 +14,25 @@ import time
 import datetime
 import random
 import numpy
+import HFIR_4Circle_Reduction.guiutility as gutil
+import HFIR_4Circle_Reduction.peakprocesshelper as peak_util
+import HFIR_4Circle_Reduction.fourcircle_utility as hb3a_util
+from HFIR_4Circle_Reduction import plot3dwindow
+from HFIR_4Circle_Reduction.multi_threads_helpers import *
+import HFIR_4Circle_Reduction.optimizelatticewindow as ol_window
+from HFIR_4Circle_Reduction import viewspicedialog
+from HFIR_4Circle_Reduction import peak_integration_utility
+from HFIR_4Circle_Reduction import FindUBUtility
+from HFIR_4Circle_Reduction import message_dialog
+
+# import line for the UI python class
+from HFIR_4Circle_Reduction.ui_MainWindow import Ui_MainWindow
 
 from PyQt4 import QtCore, QtGui
+
+if six.PY3:
+    unicode = str
+
 try:
     _fromUtf8 = QtCore.QString.fromUtf8
 except AttributeError:
@@ -26,20 +46,6 @@ except ImportError as e:
 else:
     NO_SCROLL = False
 
-import guiutility as gutil
-import peakprocesshelper as peak_util
-import fourcircle_utility as hb3a_util
-import plot3dwindow
-from multi_threads_helpers import *
-import optimizelatticewindow as ol_window
-import viewspicedialog
-import peak_integration_utility
-import FindUBUtility
-import message_dialog
-
-# import line for the UI python class
-from ui_MainWindow import Ui_MainWindow
-
 
 # define constants
 IndexFromSpice = 'From Spice (pre-defined)'
@@ -514,11 +520,11 @@ class MainWindow(QtGui.QMainWindow):
             yes = gutil.show_message(self, 'Project file %s does exist. This is supposed to be '
                                            'an incremental save.' % project_file_name)
             if yes:
-                print '[INFO] Save project in incremental way.'
+                print('[INFO] Save project in incremental way.')
             else:
-                print '[INFO] Saving activity is cancelled.'
+                print('[INFO] Saving activity is cancelled.')
         else:
-            print '[INFO] Saving current project to %s.' % project_file_name
+            print('[INFO] Saving current project to %s.' % project_file_name)
 
         # gather some useful information
         ui_dict = dict()
@@ -556,7 +562,7 @@ class MainWindow(QtGui.QMainWindow):
         # TODO/NOW/TODAY - Implement a pop-up dialog for this
         information = 'Project has been saved to {0}\n'.format(project_file_name),
         information += 'Including dictionary keys: {0}'.format(ui_dict)
-        print '[INFO]\n{0}'.format(information)
+        print('[INFO]\n{0}'.format(information))
 
         return
 
@@ -604,7 +610,7 @@ class MainWindow(QtGui.QMainWindow):
                 self.do_apply_setup()
                 self.do_set_experiment()
             except KeyError:
-                print '[Error] Some field cannot be found.'
+                print('[Error] Some field cannot be found.')
 
         return
 
@@ -854,7 +860,7 @@ class MainWindow(QtGui.QMainWindow):
         try:
             self._myControl.set_roi(exp_number, scan_number, lower_left_c, upper_right_c)
         except AssertionError as ass_err:
-            print '[ERROR] Unable to set ROI due to {0}.'.format(ass_err)
+            print('[ERROR] Unable to set ROI due to {0}.'.format(ass_err))
 
         return
 
@@ -983,7 +989,7 @@ class MainWindow(QtGui.QMainWindow):
         peak_info_list = list()
         status, exp_number = gutil.parse_integers_editors(self.ui.lineEdit_exp)
         assert status
-        for i_row in xrange(num_rows):
+        for i_row in range(num_rows):
             if self.ui.tableWidget_peaksCalUB.is_selected(i_row) is True:
                 scan_num, pt_num = self.ui.tableWidget_peaksCalUB.get_exp_info(i_row)
                 if pt_num < 0:
@@ -1107,7 +1113,7 @@ class MainWindow(QtGui.QMainWindow):
         :return:
         """
         num_rows = self.ui.tableWidget_peaksCalUB.rowCount()
-        row_number_list = range(num_rows)
+        row_number_list = list(range(num_rows))
         self.ui.tableWidget_peaksCalUB.delete_rows(row_number_list)
 
         return
@@ -1265,7 +1271,7 @@ class MainWindow(QtGui.QMainWindow):
         info_str = '# Selected scans: \n'
         info_str += '{0}'.format(scan_number_list)
 
-        print '[TEMP] Selected scans:\n{0}'.format(info_str)
+        print('[TEMP] Selected scans:\n{0}'.format(info_str))
 
         return
 
@@ -1347,7 +1353,7 @@ class MainWindow(QtGui.QMainWindow):
             start_scan_number = 0
         end_scan_number = ret_obj[1]
         if end_scan_number is None:
-            end_scan_number = sys.maxint
+            end_scan_number = sys.maxsize
 
         status, ret_obj = gutil.parse_float_editors([self.ui.lineEdit_filterCountsLower,
                                                      self.ui.lineEdit_filterCountsUpper],
@@ -1441,14 +1447,14 @@ class MainWindow(QtGui.QMainWindow):
         # plot calculated motor position (or Pt.) - integrated intensity per Pts.
         motor_pos_vec = int_peak_dict['motor positions']
         pt_intensity_vec = int_peak_dict['pt intensities']
-        # print '[DB...BAT] motor position vector: {0} of type {1}'.format(motor_pos_vec, type(motor_pos_vec))
+        # print('[DB...BAT] motor position vector: {0} of type {1}'.format(motor_pos_vec, type(motor_pos_vec)))
         motor_std = motor_pos_vec.std()
         if motor_std > 0.005:
             self.ui.graphicsView_integratedPeakView.plot_raw_data(motor_pos_vec, pt_intensity_vec)
         else:
             # motor position fixed
             # KEEP-IN-MIND:  Make this an option from
-            self.ui.graphicsView_integratedPeakView.plot_raw_data(numpy.array(range(1, len(pt_intensity_vec)+1)),
+            self.ui.graphicsView_integratedPeakView.plot_raw_data(numpy.arange(1, len(pt_intensity_vec)+1),
                                                                   pt_intensity_vec)
 
         if self._mySinglePeakIntegrationDialog is None:
@@ -1486,7 +1492,7 @@ class MainWindow(QtGui.QMainWindow):
             raise RuntimeError('Peak integration result dictionary has keys {0}. Error is caused by {1}.'
                                ''.format(int_peak_dict.keys(), key_err))
         except ValueError as value_err:
-            print '[ERROR] Unable to fit by Gaussian due to {0}.'.format(value_err)
+            print('[ERROR] Unable to fit by Gaussian due to {0}.'.format(value_err))
         else:
             self.plot_model_data(motor_pos_vec, fit_gauss_dict)
 
@@ -1638,12 +1644,12 @@ class MainWindow(QtGui.QMainWindow):
         """
         # Get UB matrix
         ub_matrix = self.ui.tableWidget_ubMatrix.get_matrix()
-        print '[Info] Get UB matrix from table ', ub_matrix
+        print('[Info] Get UB matrix from table ', ub_matrix)
 
         # Index all peaks
         num_peaks = self.ui.tableWidget_peaksCalUB.rowCount()
         err_msg = ''
-        for i_peak in xrange(num_peaks):
+        for i_peak in range(num_peaks):
             scan_no = self.ui.tableWidget_peaksCalUB.get_exp_info(i_peak)[0]
             status, ret_obj = self._myControl.index_peak(ub_matrix, scan_number=scan_no)
             if status is True:
@@ -2162,7 +2168,7 @@ class MainWindow(QtGui.QMainWindow):
             self.do_set_experiment()
 
         except KeyError:
-            print '[Error] Some field cannot be found.'
+            print('[Error] Some field cannot be found.')
 
         # set experiment configurations
         # set sample distance
@@ -2186,7 +2192,7 @@ class MainWindow(QtGui.QMainWindow):
             self._myControl.set_detector_center(exp_number, center_row, center_col)
 
         # TODO/ISSUE/NOW/TODAY - Shall pop out a dialog to notify the completion
-        print '[INFO] Project from file {0} is loaded.'.format(project_file_name)
+        print('[INFO] Project from file {0} is loaded.'.format(project_file_name))
 
         return
 
@@ -2214,10 +2220,10 @@ class MainWindow(QtGui.QMainWindow):
         # get the UB matrix value
         ub_src_tab = self._refineConfigWindow.get_ub_source()
         if ub_src_tab == 3:
-            print '[INFO] UB matrix comes from tab "Calculate UB".'
+            print('[INFO] UB matrix comes from tab "Calculate UB".')
             ub_matrix = self.ui.tableWidget_ubMatrix.get_matrix_str()
         elif ub_src_tab == 4:
-            print '[INFO] UB matrix comes from tab "UB Matrix".'
+            print('[INFO] UB matrix comes from tab "UB Matrix".')
             ub_matrix = self.ui.tableWidget_ubInUse.get_matrix_str()
         else:
             self.pop_one_button_dialog('UB source tab %s is not supported.' % str(ub_src_tab))
@@ -2319,7 +2325,7 @@ class MainWindow(QtGui.QMainWindow):
 
         # reset all rows back to SPICE HKL
         num_rows = self.ui.tableWidget_peaksCalUB.rowCount()
-        for i_row in xrange(num_rows):
+        for i_row in range(num_rows):
             scan, pt = self.ui.tableWidget_peaksCalUB.get_scan_pt(i_row)
             if pt < 0:
                 pt = None
@@ -2399,8 +2405,8 @@ class MainWindow(QtGui.QMainWindow):
 
         # construct string
         ub_str = '# UB matrix\n# %s\n' % str(self.ui.label_ubInfoLabel.text())
-        for i_row in xrange(3):
-            for j_col in xrange(3):
+        for i_row in range(3):
+            for j_col in range(3):
                 ub_str += '%.15f  ' % in_use_ub[i_row][j_col]
             ub_str += '\n'
 
@@ -2637,8 +2643,8 @@ class MainWindow(QtGui.QMainWindow):
                 self.ui.tableWidget_peaksCalUB.set_hkl(row_index, peak_indexing, is_spice, round_error)
             except RuntimeError as run_err:
                 scan_number, pt_number = self.ui.tableWidget_peaksCalUB.get_scan_pt(row_index)
-                print '[ERROR] Unable to convert HKL to integer for scan {0} due to {1}.' \
-                      ''.format(scan_number, run_err)
+                print('[ERROR] Unable to convert HKL to integer for scan '
+                      '{0} due to {1}.'.format(scan_number, run_err))
         # END-FOR
 
         # disable the set to integer button and enable the revert/undo button
@@ -2670,8 +2676,8 @@ class MainWindow(QtGui.QMainWindow):
                 intensity2, error2 = peak_info_obj.get_intensity(integrate_type, True)
                 self.ui.tableWidget_mergeScans.set_peak_intensity(i_row, intensity1, intensity2, error2, integrate_type)
             except RuntimeError as run_err:
-                print '[ERROR] Unable to get peak intensity of scan {0} due to {1}.' \
-                      ''.format(self.ui.tableWidget_mergeScans.get_scan_number(i_row), run_err)
+                print('[ERROR] Unable to get peak intensity of scan'
+                      ' {0} due to {1}.'.format(self.ui.tableWidget_mergeScans.get_scan_number(i_row), run_err))
         # END-FOR
 
         return
@@ -2725,7 +2731,7 @@ class MainWindow(QtGui.QMainWindow):
                 try:
                     ub_matrix = self._myControl.get_ub_matrix(exp_number)
                 except KeyError as key_err:
-                    print '[Error] unable to get UB matrix: %s' % str(key_err)
+                    print('[Error] unable to get UB matrix: %s' % str(key_err))
                     self.pop_one_button_dialog('Unable to get UB matrix.\nCheck whether UB matrix is set.')
                     return
                 index_status, ret_tup = self._myControl.index_peak(ub_matrix, scan_i, allow_magnetic=True)
@@ -2993,8 +2999,8 @@ class MainWindow(QtGui.QMainWindow):
         ub_matrix = self.ui.tableWidget_ubInUse.get_matrix()
 
         text = ''
-        for i in xrange(3):
-            for j in xrange(3):
+        for i in range(3):
+            for j in range(3):
                 text += '%.7f, ' % ub_matrix[i][j]
             text += '\n'
 
@@ -3184,7 +3190,7 @@ class MainWindow(QtGui.QMainWindow):
         if self._my3DWindow is None:
             self._my3DWindow = plot3dwindow.Plot3DWindow(self)
 
-        print '[INFO] Write file to %s' % md_file_name
+        print('[INFO] Write file to %s' % md_file_name)
         self._my3DWindow.add_plot_by_file(md_file_name)
         self._my3DWindow.add_plot_by_array(weight_peak_centers, weight_peak_intensities)
         self._my3DWindow.add_plot_by_array(avg_peak_centre, avg_peak_intensity)
@@ -3217,8 +3223,8 @@ class MainWindow(QtGui.QMainWindow):
 
         pt_peak_centre_array = numpy.ndarray(shape=(num_pt_peaks, 3), dtype='float')
         pt_peak_intensity_array = numpy.ndarray(shape=(num_pt_peaks,), dtype='float')
-        for i_pt in xrange(num_pt_peaks):
-            for j in xrange(3):
+        for i_pt in range(num_pt_peaks):
+            for j in range(3):
                 pt_peak_centre_array[i_pt][j] = weight_peak_centers[i_pt][j]
             pt_peak_intensity_array[i_pt] = weight_peak_intensities[i_pt]
 
@@ -3271,7 +3277,7 @@ class MainWindow(QtGui.QMainWindow):
         # get values
         try:
             scan_num, pt_num = self.ui.tableWidget_surveyTable.get_selected_run_surveyed()
-        except RuntimeError, err:
+        except RuntimeError as err:
             self.pop_one_button_dialog(str(err))
             return
 
@@ -3319,13 +3325,13 @@ class MainWindow(QtGui.QMainWindow):
 
         # collection all the information
         report_dict = dict()
-        print '[DB] Selected rows: {0}'.format(row_number_list)
+        print('[DB] Selected rows: {0}'.format(row_number_list))
         for row_number in row_number_list:
             scan_number = self.ui.tableWidget_mergeScans.get_scan_number(row_number)
             peak_info = self._myControl.get_peak_info(exp_number, scan_number)
             peak_integrate_dict = peak_info.generate_integration_report()
             report_dict[scan_number] = peak_integrate_dict
-            print '[DB] Report Scan {0}. Keys: {1}'.format(scan_number, peak_integrate_dict.keys())
+            print('[DB] Report Scan {0}. Keys: {1}'.format(scan_number, peak_integrate_dict.keys()))
         # END-FOR
 
         return report_dict
@@ -3400,7 +3406,7 @@ class MainWindow(QtGui.QMainWindow):
         self._myControl.set_working_directory(str(self.ui.lineEdit_workDir.text()))
         self._myControl.set_server_url(str(self.ui.lineEdit_url.text()))
 
-        print '[INFO] Session {0} has been loaded.'.format(filename)
+        print('[INFO] Session {0} has been loaded.'.format(filename))
 
         return
 
@@ -3718,7 +3724,7 @@ class MainWindow(QtGui.QMainWindow):
         else:
             error_msg = roi
             # self.pop_one_button_dialog(error_msg)
-            print '[Error] %s' % error_msg
+            print('[Error] %s' % error_msg)
         # END-IF
 
         # Information
diff --git a/scripts/HFIR_4Circle_Reduction/refineubfftsetup.py b/scripts/HFIR_4Circle_Reduction/refineubfftsetup.py
index bd7ab38d027c5fad1599ae52bd8df6504feb1928..dae6a895b83685976165f1efe3aabe96d07326bd 100644
--- a/scripts/HFIR_4Circle_Reduction/refineubfftsetup.py
+++ b/scripts/HFIR_4Circle_Reduction/refineubfftsetup.py
@@ -1,3 +1,4 @@
+from __future__ import (absolute_import, division, print_function)
 import ui_RefineUbFftDialog
 
 from PyQt4 import QtCore, QtGui
diff --git a/scripts/HFIR_4Circle_Reduction/viewspicedialog.py b/scripts/HFIR_4Circle_Reduction/viewspicedialog.py
index 2d303c0e3fe0fbf0fcb2deaf6c27707b6dcab9be..e6dcdd4a68bafd8255b0c68439cb84e07f7d6b58 100644
--- a/scripts/HFIR_4Circle_Reduction/viewspicedialog.py
+++ b/scripts/HFIR_4Circle_Reduction/viewspicedialog.py
@@ -1,4 +1,5 @@
-import ui_SpiceViewerDialog
+from __future__ import (absolute_import, division, print_function)
+from . import ui_SpiceViewerDialog
 from PyQt4 import QtGui, QtCore
 
 
diff --git a/scripts/HFIR_Powder_Diffraction_Reduction.py b/scripts/HFIR_Powder_Diffraction_Reduction.py
index b17c6487f2bad086a63e3eef8c532addabe6d276..1b9f4bf13452023b8096dd89e5f984f095a10e1d 100644
--- a/scripts/HFIR_Powder_Diffraction_Reduction.py
+++ b/scripts/HFIR_Powder_Diffraction_Reduction.py
@@ -2,6 +2,7 @@
 """
     Script used to start the DGS reduction GUI from MantidPlot
 """
+from __future__ import (absolute_import, division, print_function)
 import sys
 
 from HFIRPowderReduction import HfirPDReductionGUI
diff --git a/scripts/ISIS_Reflectometry_Old.py b/scripts/ISIS_Reflectometry_Old.py
index f06283585df5580a8de29167d2bb9c8b7bf0f0b7..ef54cc21fe4f75544db062d1ffe83bec7c90853b 100644
--- a/scripts/ISIS_Reflectometry_Old.py
+++ b/scripts/ISIS_Reflectometry_Old.py
@@ -2,6 +2,7 @@
 """
     Script used to start the ISIS Reflectomery GUI from MantidPlot
 """
+from __future__ import (absolute_import, division, print_function)
 from ui.reflectometer import refl_gui
 
 ui = refl_gui.ReflGui()
diff --git a/scripts/ISIS_SANS_v2_experimental.py b/scripts/ISIS_SANS_v2_experimental.py
new file mode 100644
index 0000000000000000000000000000000000000000..91f86da56e18e73d718d317f09c411ca6d2a9c90
--- /dev/null
+++ b/scripts/ISIS_SANS_v2_experimental.py
@@ -0,0 +1,29 @@
+#pylint: disable=invalid-name
+"""
+    Script used to start the Test Interface from MantidPlot
+"""
+from ui.sans_isis import sans_data_processor_gui
+from sans.gui_logic.presenter.main_presenter import MainPresenter
+from sans.common.enums import SANSFacility
+
+# -----------------------------------------------
+# Create presenter
+# -----------------------------------------------
+main_presenter = MainPresenter(SANSFacility.ISIS)
+
+# -------------------------------------------------
+# Create view
+# Note that the view owns the presenter, but only
+# uses it for the setup.
+# ------------------------------------------------
+ui = sans_data_processor_gui.SANSDataProcessorGui(main_presenter)
+
+# -----------------------------------------------
+# Set view on the presenter.
+# The presenter delegates the view.
+# -----------------------------------------------
+main_presenter.set_view(ui)
+
+# Show
+if ui.setup_layout():
+    ui.show()
diff --git a/scripts/Inelastic/CrystalField/normalisation.py b/scripts/Inelastic/CrystalField/normalisation.py
index e56dbe5b8602348796787f65ac1df8fca7b13cce..cd2f9178697fbb906f32440c10419028d70c6ef1 100644
--- a/scripts/Inelastic/CrystalField/normalisation.py
+++ b/scripts/Inelastic/CrystalField/normalisation.py
@@ -2,6 +2,7 @@ from __future__ import (absolute_import, division, print_function)
 import numpy as np
 from CrystalField.energies import energies as CFEnergy
 from six import iteritems
+from six import string_types
 
 
 def _get_normalisation(nre, bnames):
@@ -169,7 +170,7 @@ def split2range(*args, **kwargs):
         argin[argnames[ia]] = args[ia]
     # Further arguments beyond the first 3 are treated as crystal field parameter names
     for ia in range(3, len(args)):
-        if isinstance(args[ia], basestring) and args[ia].startswith('B'):
+        if isinstance(args[ia], string_types) and args[ia].startswith('B'):
             argin['Parameters'].append(args[ia])
     # Parses the keyword arguments
     for key, value in iteritems(kwargs):
diff --git a/scripts/Inelastic/Direct/CommonFunctions.py b/scripts/Inelastic/Direct/CommonFunctions.py
index 9fb5d17b27df5064e4ed4e68d2509ef8ca907716..4924b1249b57ce04396fc1fc3aa1be7548aae0fb 100644
--- a/scripts/Inelastic/Direct/CommonFunctions.py
+++ b/scripts/Inelastic/Direct/CommonFunctions.py
@@ -1,3 +1,6 @@
+from __future__ import (absolute_import, division, print_function)
+
+
 class switch(object):
     """ Helper class providing nice switch statement"""
 
diff --git a/scripts/Inelastic/Direct/PropertiesDescriptors.py b/scripts/Inelastic/Direct/PropertiesDescriptors.py
index 2cc58aa0567b55996d54b8c101518b29c2458144..cff1c45d41f2584d3324ad0fec9ef01bdee78ca7 100644
--- a/scripts/Inelastic/Direct/PropertiesDescriptors.py
+++ b/scripts/Inelastic/Direct/PropertiesDescriptors.py
@@ -279,6 +279,10 @@ class IncidentEnergy(PropDescriptor):
 
     #
 
+    # Python 3 compatibility
+    def __next__(self):
+        return self.next()
+
     def next(self):
         if isinstance(self._incident_energy, list):
             self._cur_iter_en += 1
diff --git a/scripts/Inelastic/IndirectBayes.py b/scripts/Inelastic/IndirectBayes.py
index 92b59b798976fffa0c28dc3e9a3c6dfc736a02a2..334e803b3a206d1bb3623519c9f84c7c2a04ffd5 100644
--- a/scripts/Inelastic/IndirectBayes.py
+++ b/scripts/Inelastic/IndirectBayes.py
@@ -7,6 +7,7 @@ Input : the Python list is padded to Fortrans length using procedure PadArray
 Output : the Fortran numpy array is sliced to Python length using dataY = yout[:ny]
 """
 
+from __future__ import (absolute_import, division, print_function)
 from IndirectImport import *
 if is_supported_f2py_platform(): # noqa
     QLr     = import_f2py("QLres")
@@ -83,9 +84,9 @@ def ResNormRun(vname,rname,erange,nbin,Plot='None',Save=False):
     nvan,ntc = CheckHistZero(vname)
     theta = GetThetaQ(vname)[0]
     efix = getEfixed(vname)
-    print "begining erange calc"
+    print("begining erange calc")
     nout,bnorm,Xdat,Xv,Yv,Ev = CalcErange(vname,0,erange,nbin)
-    print "end of erange calc"
+    print("end of erange calc")
     Ndat = nout[0]
     Imin = nout[1]
     Imax = nout[2]
diff --git a/scripts/Inelastic/IndirectImport.py b/scripts/Inelastic/IndirectImport.py
index 7a5ddc5b19d3d3b4860f288400aa292142d59539..f57122e700aeb83ca017bf74eaad7eb4bf4405d1 100644
--- a/scripts/Inelastic/IndirectImport.py
+++ b/scripts/Inelastic/IndirectImport.py
@@ -5,6 +5,7 @@ the Indirect scripts depending on platform and numpy package version.
 We also deal with importing the mantidplot module outside of MantidPlot here.
 """
 
+from __future__ import (absolute_import, division, print_function)
 import numpy
 import platform
 import sys
diff --git a/scripts/Inelastic/IndirectMuscat.py b/scripts/Inelastic/IndirectMuscat.py
index a7664d1cc7f68ab8ee967e61b8b2d2ed6b4f23e8..ba232682fa109c355dc04362dcb40edfb49aa41e 100644
--- a/scripts/Inelastic/IndirectMuscat.py
+++ b/scripts/Inelastic/IndirectMuscat.py
@@ -4,6 +4,7 @@
 MUSIC : Version of Minus for MIDAS
 """
 
+from __future__ import (absolute_import, division, print_function)
 from IndirectImport import *
 if is_supported_f2py_platform(): # noqa
     muscat = import_f2py("muscat")
diff --git a/scripts/Inelastic/IndirectNeutron.py b/scripts/Inelastic/IndirectNeutron.py
index 1cd73dc7321f70fda66d59d290f80df1ea371de4..76b64a45b0e1c3a4e5bc3d4954cb704cdeb23b4f 100644
--- a/scripts/Inelastic/IndirectNeutron.py
+++ b/scripts/Inelastic/IndirectNeutron.py
@@ -4,6 +4,7 @@
 Force for ILL backscattering raw
 """
 
+from __future__ import (absolute_import, division, print_function)
 from IndirectImport import *
 from mantid.simpleapi import *
 from mantid import config, logger, mtd, FileFinder
@@ -23,7 +24,7 @@ def Iblock(a, first):  # read Ascii block of Integers
     line2 = a[first + 1]
     val = ExtractInt(line2)
     numb = val[0]
-    lines = numb / 10
+    lines = numb // 10
     last = numb - 10 * lines
     if line1.startswith('I'):
         error = ''
@@ -50,7 +51,7 @@ def Fblock(a, first):  # read Ascii block of Floats
     line2 = a[first + 1]
     val = ExtractInt(line2)
     numb = val[0]
-    lines = numb / 5
+    lines = numb // 5
     last = numb - 5 * lines
     if line1.startswith('F'):
         error = ''
@@ -175,7 +176,7 @@ def IbackStart(instr, run, ana, refl, rejectZ, useM, mapPath, Plot, Save):  # As
     # raw spectra
     val = ExtractInt(asc[next + 3])
     npt = val[0]
-    lgrp = 5 + npt / 10
+    lgrp = 5 + npt // 10
     val = ExtractInt(asc[next + 1])
     if instr == 'IN10':
         nsp = int(val[2])
@@ -198,7 +199,7 @@ def IbackStart(instr, run, ana, refl, rejectZ, useM, mapPath, Plot, Save):  # As
             imax = m
             ymax = ym[m]
     new = imax - imin
-    imid = new / 2 + 1
+    imid = new // 2 + 1
     if instr == 'IN10':
         DRV = 18.706  # fast drive
         vmax = freq * DRV
diff --git a/scripts/Inelastic/vesuvio/commands.py b/scripts/Inelastic/vesuvio/commands.py
index fd1982b85a02b3161020359b90ea07c742e3ac57..0d4dcdc244f47cadc09c2d221b8f034e048b8aaf 100644
--- a/scripts/Inelastic/vesuvio/commands.py
+++ b/scripts/Inelastic/vesuvio/commands.py
@@ -152,8 +152,9 @@ def fit_tof_iteration(sample_data, container_data, runs, flags):
         ms.DeleteWorkspace(corrections_fit_name)
         corrections_args['FitParameters'] = pre_correction_pars_name
 
-        # Add the multiple scattering arguments
-        corrections_args.update(flags['ms_flags'])
+        if flags.get('ms_enabled', True):
+            # Add the multiple scattering arguments
+            corrections_args.update(flags['ms_flags'])
 
         corrected_data_name = runs + "_tof_corrected" + suffix
         linear_correction_fit_params_name = runs + "_correction_fit_scale" + suffix
@@ -173,7 +174,7 @@ def fit_tof_iteration(sample_data, container_data, runs, flags):
                               Masses=mass_values,
                               MassProfiles=profiles,
                               IntensityConstraints=intensity_constraints,
-                              MultipleScattering=True,
+                              MultipleScattering=flags.get('ms_enabled', True),
                               GammaBackgroundScale=flags.get('fixed_gamma_scaling', 0.0),
                               ContainerScale=flags.get('fixed_container_scaling', 0.0),
                               **corrections_args)
diff --git a/scripts/Interface/reduction_gui/reduction/diffraction/diffraction_adv_setup_script.py b/scripts/Interface/reduction_gui/reduction/diffraction/diffraction_adv_setup_script.py
index 2d2c07c8ae8815b57a13d066198e2079f1bbcda1..e57bdd7835370493a4470cf6d5ad15d966dfd655 100644
--- a/scripts/Interface/reduction_gui/reduction/diffraction/diffraction_adv_setup_script.py
+++ b/scripts/Interface/reduction_gui/reduction/diffraction/diffraction_adv_setup_script.py
@@ -199,7 +199,7 @@ class AdvancedSetupScript(BaseScriptElement):
                                                    AdvancedSetupScript.filterbadpulses)
 
             self.bkgdsmoothpars = BaseScriptElement.getStringElement(instrument_dom,
-                                                                     "bkgdsmoothpars", default=AdvancedSetupScript.bkgdsmoothpars)
+                                                                     "backgroundsmoothparams", default=AdvancedSetupScript.bkgdsmoothpars)
 
             self.pushdatapositive = BaseScriptElement.getStringElement(instrument_dom,
                                                                        "pushdatapositive", default=AdvancedSetupScript.pushdatapositive)
diff --git a/scripts/Interface/reduction_gui/reduction/diffraction/diffraction_run_setup_script.py b/scripts/Interface/reduction_gui/reduction/diffraction/diffraction_run_setup_script.py
index 38000e67baee57a81d3ce23a375deeec5a055203..7f7a0d948b3f6ed6eef00a3249b406db201deb0e 100644
--- a/scripts/Interface/reduction_gui/reduction/diffraction/diffraction_run_setup_script.py
+++ b/scripts/Interface/reduction_gui/reduction/diffraction/diffraction_run_setup_script.py
@@ -13,15 +13,16 @@ class RunSetupScript(BaseScriptElement):
     """ Run setup script for tab 'Run Setup'
     """
     # Class static variables
-    runnumbers = ""
-    calibfilename = ""
+    runnumbers = ''
+    calibfilename = ''
+    groupfilename = ''
     exp_ini_file_name = ''
-    charfilename = ""
+    charfilename = ''
     dosum = False
     binning = -0.0001
     doresamplex = False
-    tofmin = ""
-    tofmax = ""
+    tofmin = ''
+    tofmax = ''
     resamplex = 0
     binindspace = True
     saveas = "NeXus"
@@ -55,25 +56,26 @@ class RunSetupScript(BaseScriptElement):
         """ Create a list of parameter names for SNSPowderReductionPlus()
         """
         self.parnamelist = []
-        self.parnamelist.append("RunNumber")
-        self.parnamelist.append("Sum")
-        self.parnamelist.append("CalibrationFile")
-        self.parnamelist.append("CharacterizationRunsFile")
+        self.parnamelist.append('RunNumber')
+        self.parnamelist.append('Sum')
+        self.parnamelist.append('CalibrationFile')
+        self.parnamelist.append('GroupingFile')
+        self.parnamelist.append('CharacterizationRunsFile')
         self.parnamelist.append('ExpIniFilename')
-        self.parnamelist.append("Binning")
-        self.parnamelist.append("ResampleX")
-        self.parnamelist.append("BinInDspace")
-        self.parnamelist.append("SaveAs")
-        self.parnamelist.append("OutputDirectory")
-        self.parnamelist.append("FinalDataUnits")
-        self.parnamelist.append("BackgroundNumber")
-        self.parnamelist.append("VanadiumNumber")
-        self.parnamelist.append("VanadiumNoiseNumber")
-        self.parnamelist.append("VanadiumBackgroundNumber")
-        self.parnamelist.append("DisableBackgroundCorrection")
-        self.parnamelist.append("DisableVanadiumCorrection")
-        self.parnamelist.append("DisableVanadiumBackgroundCorrection")
-        self.parnamelist.append("DoReSampleX")
+        self.parnamelist.append('Binning')
+        self.parnamelist.append('ResampleX')
+        self.parnamelist.append('BinInDspace')
+        self.parnamelist.append('SaveAs')
+        self.parnamelist.append('OutputDirectory')
+        self.parnamelist.append('FinalDataUnits')
+        self.parnamelist.append('BackgroundNumber')
+        self.parnamelist.append('VanadiumNumber')
+        self.parnamelist.append('VanadiumNoiseNumber')
+        self.parnamelist.append('VanadiumBackgroundNumber')
+        self.parnamelist.append('DisableBackgroundCorrection')
+        self.parnamelist.append('DisableVanadiumCorrection')
+        self.parnamelist.append('DisableVanadiumBackgroundCorrection')
+        self.parnamelist.append('DoReSampleX')
 
         return
 
@@ -82,11 +84,12 @@ class RunSetupScript(BaseScriptElement):
         """
         pardict = {}
 
-        pardict["RunNumber"] = str(self.runnumbers)
-        pardict["Sum"] = str(int(self.dosum))
-        pardict["CalibrationFile"] = self.calibfilename
+        pardict['RunNumber'] = str(self.runnumbers)
+        pardict['Sum'] = str(int(self.dosum))
+        pardict['CalibrationFile'] = self.calibfilename
+        pardict['GroupingFile'] = self.groupfilename
         pardict['ExpIniFilename'] = self.exp_ini_file_name
-        pardict["CharacterizationRunsFile"] = self.charfilename
+        pardict['CharacterizationRunsFile'] = self.charfilename
         if self.doresamplex is True:
             # ResampleX is used instead binning: resamplex is always bigger than 0
             pardict["ResampleX"] = '%d' % int(self.resamplex)
@@ -185,23 +188,26 @@ class RunSetupScript(BaseScriptElement):
             self.dosum = bool(int(tempbool))
 
             self.calibfilename = BaseScriptElement.getStringElement(instrument_dom,
-                                                                    "calibrationfile", default=RunSetupScript.calibfilename)
+                                                                    'calibrationfile', default=RunSetupScript.calibfilename)
+
+            self.groupfilename = BaseScriptElement.getStringElement(instrument_dom,
+                                                                    'groupingfile', default=RunSetupScript.groupfilename)
 
             self.exp_ini_file_name = BaseScriptElement.getStringElement(instrument_dom,
                                                                         'expinifilename', default=RunSetupScript.exp_ini_file_name)
 
             self.charfilename = BaseScriptElement.getStringElement(instrument_dom,
-                                                                   "characterizationrunsfile", default=RunSetupScript.charfilename)
+                                                                   'characterizationrunsfile', default=RunSetupScript.charfilename)
 
             try:
                 self.binning = BaseScriptElement.getFloatElement(instrument_dom,
-                                                                 "binning", default=RunSetupScript.binning)
+                                                                 'binning', default=RunSetupScript.binning)
             except ValueError:
                 self.binning = ''
 
             try:
                 self.resamplex = BaseScriptElement.getIntElement(instrument_dom,
-                                                                 "resamplex", default=RunSetupScript.resamplex)
+                                                                 'resamplex', default=RunSetupScript.resamplex)
             except ValueError:
                 self.resamplex = 0
 
@@ -256,6 +262,7 @@ class RunSetupScript(BaseScriptElement):
         """
         self.runnumbers = RunSetupScript.runnumbers
         self.calibfilename = RunSetupScript.calibfilename
+        self.groupfilename = RunSetupScript.groupfilename
         self.exp_ini_file_name = RunSetupScript.exp_ini_file_name
         self.charfilename  = RunSetupScript.charfilename
         self.dosum = RunSetupScript.dosum
diff --git a/scripts/Interface/reduction_gui/widgets/diffraction/diffraction_run_setup.py b/scripts/Interface/reduction_gui/widgets/diffraction/diffraction_run_setup.py
index b62c44b3cbcf91bf198a087616233d9a16c997d2..95d268b69923a64b839b58e11beb8686fbdec918 100644
--- a/scripts/Interface/reduction_gui/widgets/diffraction/diffraction_run_setup.py
+++ b/scripts/Interface/reduction_gui/widgets/diffraction/diffraction_run_setup.py
@@ -134,6 +134,8 @@ class RunSetupWidget(BaseWidget):
                      self._calfile_browse)
         self.connect(self._content.charfile_browse, QtCore.SIGNAL("clicked()"),
                      self._charfile_browse)
+        self.connect(self._content.groupfile_browse, QtCore.SIGNAL("clicked()"),
+                     self._groupfile_browse)
         self.connect(self._content.pushButton_browseExpIniFile, QtCore.SIGNAL('clicked()'),
                      self.do_browse_ini_file)
         self.connect(self._content.outputdir_browse, QtCore.SIGNAL("clicked()"),
@@ -177,6 +179,7 @@ class RunSetupWidget(BaseWidget):
         self._content.runnumbers_edit.setValidator(generateRegExpValidator(self._content.runnumbers_edit, r'[\d,-:]*'))
 
         self._content.calfile_edit.setText(state.calibfilename)
+        self._content.groupfile_edit.setText(state.groupfilename)
         self._content.lineEdit_expIniFile.setText(state.exp_ini_file_name)
         self._content.charfile_edit.setText(state.charfilename)
         self._content.sum_checkbox.setChecked(state.dosum)
@@ -257,6 +260,7 @@ class RunSetupWidget(BaseWidget):
             pass
 
         s.calibfilename = self._content.calfile_edit.text()
+        s.groupfilename = self._content.groupfile_edit.text()
         s.exp_ini_file_name = str(self._content.lineEdit_expIniFile.text())
         s.charfilename = self._content.charfile_edit.text()
         s.dosum = self._content.sum_checkbox.isChecked()
@@ -321,9 +325,18 @@ class RunSetupWidget(BaseWidget):
     def _charfile_browse(self):
         """ Event handing for browsing calibrtion file
         """
-        fname = self.data_browse_dialog("*.txt;;*")
+        fname = self.data_browse_dialog("*.txt;;*", multi=True)
         if fname:
-            self._content.charfile_edit.setText(fname)
+            self._content.charfile_edit.setText(','.join(fname))
+
+        return
+
+    def _groupfile_browse(self):
+        ''' Event handling for browsing for a grouping file
+        '''
+        fname = self.data_browse_dialog(data_type='*.xml;;*.h5;;*')
+        if fname:
+            self._content.groupfile_edit.setText(fname)
 
         return
 
diff --git a/scripts/Interface/ui/CMakeLists.txt b/scripts/Interface/ui/CMakeLists.txt
index 5365ff0ca538e31840d922929d34a975b7640fd7..42fa24d1564e6ea02d5259f76b9d691304a5d15a 100644
--- a/scripts/Interface/ui/CMakeLists.txt
+++ b/scripts/Interface/ui/CMakeLists.txt
@@ -3,6 +3,7 @@ add_subdirectory(diffraction)
 add_subdirectory(inelastic)
 add_subdirectory(reflectometer)
 add_subdirectory(sans)
+add_subdirectory(sans_isis)
 add_subdirectory(dataprocessorinterface)
 add_subdirectory(poldi)
 
@@ -26,6 +27,7 @@ add_custom_target(CompileUIUI DEPENDS
   CompileUIInElastic
   CompileUIReflectometer
   CompileUISANS
+  CompileUISANSDataProcessorInterface
   CompileUIDataProcessorInterface
   CompileUIPoldi
 )
@@ -37,4 +39,5 @@ set_property ( TARGET CompileUIInElastic PROPERTY FOLDER "CompilePyUI" )
 set_property ( TARGET CompileUIReflectometer PROPERTY FOLDER "CompilePyUI" )
 set_property ( TARGET CompileUISANS PROPERTY FOLDER "CompilePyUI" )
 set_property ( TARGET CompileUIDataProcessorInterface PROPERTY FOLDER "CompilePyUI" )
+set_property ( TARGET CompileUISANSDataProcessorInterface PROPERTY FOLDER "CompilePyUI" )
 set_property ( TARGET CompileUIPoldi PROPERTY FOLDER "CompilePyUI" )
\ No newline at end of file
diff --git a/scripts/Interface/ui/dataprocessorinterface/data_processor_gui.py b/scripts/Interface/ui/dataprocessorinterface/data_processor_gui.py
index cf85e90e1e2f96f21343001b3fa9a546a1049822..802a1231b522694c3d10b1bfaec07336f7108fd8 100644
--- a/scripts/Interface/ui/dataprocessorinterface/data_processor_gui.py
+++ b/scripts/Interface/ui/dataprocessorinterface/data_processor_gui.py
@@ -4,10 +4,10 @@ try:
 except ImportError:
     canMantidPlot = False
 
-import ui_data_processor_window
 from PyQt4 import QtGui
 from mantid.simpleapi import *
 from mantidqtpython import MantidQt
+from ui.reflectometer.ui_data_processor_window import Ui_DataProcessorWindow
 
 canMantidPlot = True
 
@@ -63,7 +63,7 @@ class MainPresenter(MantidQt.MantidWidgets.DataProcessorMainPresenter):
         self.gui.add_actions_to_menus(workspace_list)
 
 
-class DataProcessorGui(QtGui.QMainWindow, ui_data_processor_window.Ui_DataProcessorWindow):
+class DataProcessorGui(QtGui.QMainWindow, Ui_DataProcessorWindow):
 
     data_processor_table = None
     main_presenter = None
diff --git a/scripts/Interface/ui/diffraction/diffraction_run_setup.ui b/scripts/Interface/ui/diffraction/diffraction_run_setup.ui
index 88c024bbad9f534e9228a208c0561ed72a447f88..020bcbb9da0aa5e3ecfaba73dbcffe35b17d8d91 100644
--- a/scripts/Interface/ui/diffraction/diffraction_run_setup.ui
+++ b/scripts/Interface/ui/diffraction/diffraction_run_setup.ui
@@ -32,7 +32,16 @@
    <number>8</number>
   </property>
   <layout class="QVBoxLayout" name="verticalLayout">
-   <property name="margin">
+   <property name="leftMargin">
+    <number>0</number>
+   </property>
+   <property name="topMargin">
+    <number>0</number>
+   </property>
+   <property name="rightMargin">
+    <number>0</number>
+   </property>
+   <property name="bottomMargin">
     <number>0</number>
    </property>
    <item>
@@ -210,7 +219,7 @@
          <layout class="QVBoxLayout" name="verticalLayout_6">
           <item>
            <layout class="QGridLayout" name="gridLayout_3">
-            <item row="5" column="2">
+            <item row="6" column="2">
              <widget class="QPushButton" name="outputdir_browse">
               <property name="sizePolicy">
                <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
@@ -226,7 +235,7 @@
               </property>
              </widget>
             </item>
-            <item row="6" column="0">
+            <item row="7" column="0">
              <widget class="QLabel" name="label_2">
               <property name="minimumSize">
                <size>
@@ -248,7 +257,7 @@
               </property>
              </widget>
             </item>
-            <item row="6" column="3">
+            <item row="7" column="3">
              <spacer name="horizontalSpacer_10">
               <property name="orientation">
                <enum>Qt::Horizontal</enum>
@@ -264,7 +273,7 @@
               </property>
              </spacer>
             </item>
-            <item row="3" column="2">
+            <item row="4" column="2">
              <widget class="QPushButton" name="charfile_browse">
               <property name="sizePolicy">
                <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
@@ -315,7 +324,7 @@
               </property>
              </widget>
             </item>
-            <item row="6" column="1">
+            <item row="7" column="1">
              <layout class="QHBoxLayout" name="horizontalLayout">
               <item>
                <widget class="QComboBox" name="saveas_combo">
@@ -431,7 +440,7 @@
               </item>
              </layout>
             </item>
-            <item row="3" column="0">
+            <item row="4" column="0">
              <widget class="QLabel" name="characterfile_label">
               <property name="minimumSize">
                <size>
@@ -453,7 +462,7 @@
               </property>
              </widget>
             </item>
-            <item row="5" column="0">
+            <item row="6" column="0">
              <widget class="QLabel" name="outputdir_label">
               <property name="minimumSize">
                <size>
@@ -525,7 +534,7 @@
               </property>
              </widget>
             </item>
-            <item row="5" column="1">
+            <item row="6" column="1">
              <widget class="QLineEdit" name="outputdir_edit">
               <property name="sizePolicy">
                <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
@@ -591,7 +600,7 @@
               </property>
              </widget>
             </item>
-            <item row="3" column="1">
+            <item row="4" column="1">
              <widget class="QLineEdit" name="charfile_edit">
               <property name="minimumSize">
                <size>
@@ -607,16 +616,16 @@
               </property>
              </widget>
             </item>
-            <item row="4" column="0">
+            <item row="5" column="1">
+             <widget class="QLineEdit" name="lineEdit_expIniFile"/>
+            </item>
+            <item row="5" column="0">
              <widget class="QLabel" name="label_expIniFile">
               <property name="text">
                <string>Experiment Ini File</string>
               </property>
              </widget>
             </item>
-            <item row="4" column="1">
-             <widget class="QLineEdit" name="lineEdit_expIniFile"/>
-            </item>
             <item row="2" column="3">
              <spacer name="horizontalSpacer_13">
               <property name="orientation">
@@ -633,13 +642,34 @@
               </property>
              </spacer>
             </item>
-            <item row="4" column="2">
+            <item row="5" column="2">
              <widget class="QPushButton" name="pushButton_browseExpIniFile">
               <property name="text">
                <string>Browse</string>
               </property>
              </widget>
             </item>
+            <item row="3" column="0">
+             <widget class="QLabel" name="groupfile_label">
+              <property name="text">
+               <string>Grouping File</string>
+              </property>
+             </widget>
+            </item>
+            <item row="3" column="1">
+             <widget class="QLineEdit" name="groupfile_edit">
+              <property name="toolTip">
+               <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Override grouping information from calibration file&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+              </property>
+             </widget>
+            </item>
+            <item row="3" column="2">
+             <widget class="QPushButton" name="groupfile_browse">
+              <property name="text">
+               <string>Browse</string>
+              </property>
+             </widget>
+            </item>
            </layout>
           </item>
          </layout>
diff --git a/scripts/Interface/ui/poldi/poldi_gui.py b/scripts/Interface/ui/poldi/poldi_gui.py
index 626c531d1ae7d7bebc5a5989349ba29fe093acbd..b289f2bab670400d1124405dc7c684fd5b8ea01f 100644
--- a/scripts/Interface/ui/poldi/poldi_gui.py
+++ b/scripts/Interface/ui/poldi/poldi_gui.py
@@ -4,10 +4,11 @@ try:
 except ImportError:
     canMantidPlot = False
 
-import ui_poldi_window
 from PyQt4 import QtGui
 from mantid.simpleapi import *
 from mantidqtpython import MantidQt
+from ui.poldi.ui_poldi_window import Ui_PoldiWindow
+
 
 canMantidPlot = True
 
@@ -63,7 +64,7 @@ class MainPresenter(MantidQt.MantidWidgets.DataProcessorMainPresenter):
         self.gui.add_actions_to_menus(workspace_list)
 
 
-class PoldiGui(QtGui.QMainWindow, ui_poldi_window.Ui_PoldiWindow):
+class PoldiGui(QtGui.QMainWindow, Ui_PoldiWindow):
 
     data_processor_table = None
     main_presenter = None
diff --git a/scripts/Interface/ui/reflectometer/refl_choose_col.py b/scripts/Interface/ui/reflectometer/refl_choose_col.py
index fbafa1bdfe19e68f6ea162bedab3cbeafbd38f0a..13e1473f37fc6cefc6c41e3b1a1e80c5aaba68f2 100644
--- a/scripts/Interface/ui/reflectometer/refl_choose_col.py
+++ b/scripts/Interface/ui/reflectometer/refl_choose_col.py
@@ -3,8 +3,8 @@
 #so this file provides any extra GUI tweaks not easily doable in the designer
 #for the time being this also includes non-GUI behaviour
 from __future__ import (absolute_import, division, print_function)
-import ui_refl_columns
 from PyQt4 import QtCore, QtGui
+from ui.reflectometer.ui_refl_columns import Ui_chooseColumnsDialog
 
 try:
     _fromUtf8 = QtCore.QString.fromUtf8
@@ -13,7 +13,7 @@ except AttributeError:
         return s
 
 
-class ReflChoose(QtGui.QDialog, ui_refl_columns.Ui_chooseColumnsDialog):
+class ReflChoose(QtGui.QDialog, Ui_chooseColumnsDialog):
 
     visiblestates = {}
 
diff --git a/scripts/Interface/ui/reflectometer/refl_gui.py b/scripts/Interface/ui/reflectometer/refl_gui.py
index 8057eabfc19dfa2fc99eb4a83da04ffa59799035..38b16362740a05f5873bff0e76e93f1acde6e3de 100644
--- a/scripts/Interface/ui/reflectometer/refl_gui.py
+++ b/scripts/Interface/ui/reflectometer/refl_gui.py
@@ -7,10 +7,6 @@ try:
 except ImportError:
     canMantidPlot = False  #
 
-import ui_refl_window
-import refl_save
-import refl_choose_col
-import refl_options
 import csv
 import os
 import re
@@ -26,6 +22,11 @@ import mantidqtpython
 from mantid.api import Workspace, WorkspaceGroup, CatalogManager, AlgorithmManager
 from mantid import UsageService
 
+from ui.reflectometer.ui_refl_window import Ui_windowRefl
+from ui.reflectometer.refl_save import Ui_SaveWindow
+from ui.reflectometer.refl_choose_col import ReflChoose
+from ui.reflectometer.refl_options import ReflOptions
+
 try:
     _fromUtf8 = QtCore.QString.fromUtf8
 except AttributeError:
@@ -35,7 +36,7 @@ except AttributeError:
 canMantidPlot = True
 
 
-class ReflGui(QtGui.QMainWindow, ui_refl_window.Ui_windowRefl):
+class ReflGui(QtGui.QMainWindow, Ui_windowRefl):
     current_instrument = None
     current_table = None
     current_polarisation_method = None
@@ -1294,7 +1295,7 @@ class ReflGui(QtGui.QMainWindow, ui_refl_window.Ui_windowRefl):
         """
         try:
             Dialog = QtGui.QDialog()
-            u = refl_save.Ui_SaveWindow()
+            u = Ui_SaveWindow()
             u.setupUi(Dialog)
             Dialog.exec_()
         except Exception as ex:
@@ -1307,11 +1308,11 @@ class ReflGui(QtGui.QMainWindow, ui_refl_window.Ui_windowRefl):
         """
         try:
 
-            dialog_controller = refl_options.ReflOptions(def_method=self.live_method, def_freq=self.live_freq,
-                                                         def_alg_use=self.__alg_use,
-                                                         def_icat_download=self.__icat_download,
-                                                         def_group_tof_workspaces=self.__group_tof_workspaces,
-                                                         def_stitch_right=self.__scale_right)
+            dialog_controller = ReflOptions(def_method=self.live_method, def_freq=self.live_freq,
+                                            def_alg_use=self.__alg_use,
+                                            def_icat_download=self.__icat_download,
+                                            def_group_tof_workspaces=self.__group_tof_workspaces,
+                                            def_stitch_right=self.__scale_right)
             if dialog_controller.exec_():
                 # Fetch the settings back off the controller
                 self.live_freq = dialog_controller.frequency()
@@ -1343,7 +1344,7 @@ class ReflGui(QtGui.QMainWindow, ui_refl_window.Ui_windowRefl):
         shows the choose columns dialog for hiding and revealing of columns
         """
         try:
-            dialog = refl_choose_col.ReflChoose(self.shown_cols, self.tableMain)
+            dialog = ReflChoose(self.shown_cols, self.tableMain)
             if dialog.exec_():
                 settings = QtCore.QSettings()
                 settings.beginGroup(self.__column_settings)
diff --git a/scripts/Interface/ui/reflectometer/refl_gui_run.py b/scripts/Interface/ui/reflectometer/refl_gui_run.py
index cdb5ff431062e474bab01a523d203fb0329f68a0..5c243a8efbe17cacda3e3b5d77ccb8730974f7f0 100644
--- a/scripts/Interface/ui/reflectometer/refl_gui_run.py
+++ b/scripts/Interface/ui/reflectometer/refl_gui_run.py
@@ -1,13 +1,13 @@
 #pylint: disable=invalid-name
 from __future__ import (absolute_import, division, print_function)
-import refl_gui
+from ui.reflectometer.refl_gui import ReflGui
 from PyQt4 import QtGui
 
 if __name__ == "__main__":
     import sys
     app = QtGui.QApplication(sys.argv)
     MainWindow = QtGui.QMainWindow()
-    ui = refl_gui.ReflGui()
+    ui = ReflGui()
     ui.setupUi(MainWindow)
     MainWindow.show()
     sys.exit(app.exec_())
diff --git a/scripts/Interface/ui/reflectometer/refl_options.py b/scripts/Interface/ui/reflectometer/refl_options.py
index bc2716d362ef72886775cf248a797f16dd7abf37..ef639db3b807e18765eddb2207eecf97ab514312 100644
--- a/scripts/Interface/ui/reflectometer/refl_options.py
+++ b/scripts/Interface/ui/reflectometer/refl_options.py
@@ -1,7 +1,7 @@
 # pylint: disable=invalid-name
 from __future__ import (absolute_import, division, print_function)
-import ui_refl_options_window
 from PyQt4 import QtCore, QtGui
+from ui.reflectometer.ui_refl_options_window import Ui_OptionsDialog
 
 try:
     _fromUtf8 = QtCore.QString.fromUtf8
@@ -10,7 +10,7 @@ except AttributeError:
         return s
 
 
-class ReflOptions(QtGui.QDialog, ui_refl_options_window.Ui_OptionsDialog):
+class ReflOptions(QtGui.QDialog, Ui_OptionsDialog):
     """
     Member variables
     """
diff --git a/scripts/Interface/ui/sans_isis/CMakeLists.txt b/scripts/Interface/ui/sans_isis/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..bf5f20d465b0ccb6379137c62ff284b423d9d99e
--- /dev/null
+++ b/scripts/Interface/ui/sans_isis/CMakeLists.txt
@@ -0,0 +1,9 @@
+
+# List of UIs to Auto convert
+set( UI_FILES
+sans_data_processor_window.ui
+settings_diagnostic_tab.ui
+masking_table.ui
+ )
+
+UiToPy( UI_FILES CompileUISANSDataProcessorInterface)
diff --git a/scripts/Interface/ui/sans_isis/__init__.py b/scripts/Interface/ui/sans_isis/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..0451af2cb63643b4534f3e5a1a39b58413b706db
--- /dev/null
+++ b/scripts/Interface/ui/sans_isis/__init__.py
@@ -0,0 +1,16 @@
+# Note that this a workaround
+# When introduced? During the Python2 to Python3 conversion
+# Why introduced? The autogenerated file ui_XXX.py contains a line
+#                 from XXXX import YYYY
+#                 which should be
+#                 from .XXXX import YYYY
+#                 for Python3, but since it is autogenerated we cannot change
+#                 this easily.
+import os
+import sys
+
+import mantid
+
+path = mantid.config["pythonscripts.directories"].split(";")[0]
+path = os.path.join(path[:path.index("scripts")], "scripts", "Interface", "ui", "sans_isis")
+sys.path.append(path)
diff --git a/scripts/Interface/ui/sans_isis/icons/run.png b/scripts/Interface/ui/sans_isis/icons/run.png
new file mode 100644
index 0000000000000000000000000000000000000000..b1f5d8cbf86608e29e123efccc7a1e4d1df17301
Binary files /dev/null and b/scripts/Interface/ui/sans_isis/icons/run.png differ
diff --git a/scripts/Interface/ui/sans_isis/icons/settings.png b/scripts/Interface/ui/sans_isis/icons/settings.png
new file mode 100644
index 0000000000000000000000000000000000000000..70914eb398e9cb85d6cc709319583529df029001
Binary files /dev/null and b/scripts/Interface/ui/sans_isis/icons/settings.png differ
diff --git a/scripts/Interface/ui/sans_isis/masking_table.py b/scripts/Interface/ui/sans_isis/masking_table.py
new file mode 100644
index 0000000000000000000000000000000000000000..934438318df0081c3951ccff51aa62b4cf509969
--- /dev/null
+++ b/scripts/Interface/ui/sans_isis/masking_table.py
@@ -0,0 +1,103 @@
+""" View for the masking table.
+
+The view for the masking table displays all available masks for a SANS reduction. It also allows to display the moved
+and masked SANS workspace.
+"""
+
+from __future__ import (absolute_import, division, print_function)
+
+from abc import ABCMeta, abstractmethod
+
+from PyQt4 import QtGui
+from six import with_metaclass
+
+import ui_masking_table
+
+
+class MaskingTable(QtGui.QWidget, ui_masking_table.Ui_MaskingTable):
+    class MaskingTableListener(with_metaclass(ABCMeta, object)):
+        """
+        Defines the elements which a presenter can listen to for the masking table
+        """
+        @abstractmethod
+        def on_row_changed(self):
+            pass
+
+        @abstractmethod
+        def on_update_rows(self):
+            pass
+
+        @abstractmethod
+        def on_display(self):
+            pass
+
+    def __init__(self, parent=None):
+        super(MaskingTable, self).__init__(parent)
+        self.setupUi(self)
+
+        # Hook up signal and slots
+        self.connect_signals()
+        self._masking_tab_listeners = []
+
+    def add_listener(self, listener):
+        if not isinstance(listener, MaskingTable.MaskingTableListener):
+            raise ValueError("The listener ist not of type MaskingTableListener but rather {}".format(type(listener)))
+        self._masking_tab_listeners.append(listener)
+
+    def clear_listeners(self):
+        self._masking_tab_listeners = []
+
+    def _call_masking_tab_listeners(self, target):
+        for listener in self._masking_tab_listeners:
+            target(listener)
+
+    def on_row_changed(self):
+        self._call_masking_tab_listeners(lambda listener: listener.on_row_changed())
+
+    def on_update_rows(self):
+        self._call_masking_tab_listeners(lambda listener: listener.update_rows())
+
+    def on_display(self):
+        self._call_masking_tab_listeners(lambda listener: listener.on_display())
+
+    def connect_signals(self):
+        self.select_row_combo_box.currentIndexChanged.connect(self.on_row_changed)
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Actions
+    # ------------------------------------------------------------------------------------------------------------------
+    def get_current_row(self):
+        value = self.select_row_combo_box.currentText()
+        if not value:
+            value = -1
+        return int(value)
+
+    def set_row(self, index):
+        found_index = self.select_row_combo_box.findText(str(index))
+        if found_index and found_index != -1:
+            self.select_row_combo_box.setCurrentIndex(found_index)
+
+    def update_rows(self, indices):
+        self.select_row_combo_box.blockSignals(True)
+        self.select_row_combo_box.clear()
+        for index in indices:
+            self.select_row_combo_box.addItem(str(index))
+        self.select_row_combo_box.blockSignals(False)
+
+    def set_table(self, table_entries):
+        # Remove all rows
+        for index in reversed(range(self.masking_table.rowCount())):
+            self.masking_table.removeRow(index)
+
+        # Set the number of rows
+        self.masking_table.setRowCount(len(table_entries))
+
+        # Populate the rows
+        for row, table_entry in enumerate(table_entries):
+            entry_type = QtGui.QTableWidgetItem(table_entry.first)
+            entry_detector = QtGui.QTableWidgetItem(table_entry.second)
+            entry_detail = QtGui.QTableWidgetItem(table_entry.third)
+
+            self.masking_table.setItem(row, 0, entry_type)
+            self.masking_table.setItem(row, 1, entry_detector)
+            self.masking_table.setItem(row, 2, entry_detail)
diff --git a/scripts/Interface/ui/sans_isis/masking_table.ui b/scripts/Interface/ui/sans_isis/masking_table.ui
new file mode 100644
index 0000000000000000000000000000000000000000..89ca3dddd0b299ea61072bd16dc300c24763e525
--- /dev/null
+++ b/scripts/Interface/ui/sans_isis/masking_table.ui
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MaskingTable</class>
+ <widget class="QWidget" name="MaskingTable">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>455</width>
+    <height>506</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout_2">
+   <item>
+    <widget class="QGroupBox" name="groupBox">
+     <property name="toolTip">
+      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Gives a summary of the the masking settings.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+     </property>
+     <property name="title">
+      <string>Masking information</string>
+     </property>
+     <layout class="QGridLayout" name="gridLayout">
+      <item row="1" column="0" colspan="6">
+       <widget class="QTableWidget" name="masking_table">
+        <property name="columnCount">
+         <number>3</number>
+        </property>
+        <column>
+         <property name="text">
+          <string>Type</string>
+         </property>
+        </column>
+        <column>
+         <property name="text">
+          <string>Detector</string>
+         </property>
+        </column>
+        <column>
+         <property name="text">
+          <string>Details</string>
+         </property>
+        </column>
+       </widget>
+      </item>
+      <item row="0" column="0">
+       <widget class="QLabel" name="label">
+        <property name="text">
+         <string>Select  row:</string>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="1">
+       <widget class="QComboBox" name="select_row_combo_box">
+        <property name="toolTip">
+         <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Selects the row for which the masking information is to be shown&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+        </property>
+       </widget>
+      </item>
+      <item row="0" column="2">
+       <widget class="QPushButton" name="select_row_push_button">
+        <property name="toolTip">
+         <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Updates the available rows, after the number of rows has changed either via a manual change or after having loaded a new batch file.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+        </property>
+        <property name="text">
+         <string>Update Rows</string>
+        </property>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/scripts/Interface/ui/sans_isis/sans_data_processor_gui.py b/scripts/Interface/ui/sans_isis/sans_data_processor_gui.py
new file mode 100644
index 0000000000000000000000000000000000000000..65a022009059b962bc7f3a84ac9082c36066ccf2
--- /dev/null
+++ b/scripts/Interface/ui/sans_isis/sans_data_processor_gui.py
@@ -0,0 +1,1536 @@
+""" Main view for the ISIS SANS reduction interface.
+"""
+
+from __future__ import (absolute_import, division, print_function)
+
+import os
+from abc import ABCMeta, abstractmethod
+from inspect import isclass
+
+from six import with_metaclass
+from PyQt4 import QtGui, QtCore
+
+from mantid.kernel import (Logger, config)
+from mantidqtpython import MantidQt
+try:
+    from mantidplot import *
+    canMantidPlot = True
+except ImportError:
+    canMantidPlot = False
+
+from . import ui_sans_data_processor_window as ui_sans_data_processor_window
+from sans.common.enums import (ReductionDimensionality, OutputMode, SaveType, SANSInstrument,
+                               RangeStepType, SampleShape, ReductionMode, FitType)
+from sans.gui_logic.gui_common import (get_reduction_mode_from_gui_selection,
+                                       get_string_for_gui_from_reduction_mode)
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# Free Functions
+# ----------------------------------------------------------------------------------------------------------------------
+def open_file_dialog(line_edit, filter_text, directory):
+    dlg = QtGui.QFileDialog()
+    dlg.setFileMode(QtGui.QFileDialog.AnyFile)
+    dlg.setFilter(filter_text)
+    dlg.setDirectory(directory)
+    if dlg.exec_():
+        file_names = dlg.selectedFiles()
+        if file_names:
+            line_edit.setText(file_names[0])
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# Gui Classes
+# ----------------------------------------------------------------------------------------------------------------------
+class SANSDataProcessorGui(QtGui.QMainWindow, ui_sans_data_processor_window.Ui_SansDataProcessorWindow):
+    data_processor_table = None
+    INSTRUMENTS = None
+
+    class RunTabListener(with_metaclass(ABCMeta, object)):
+        """
+        Defines the elements which a presenter can listen to in this View
+        """
+        @abstractmethod
+        def on_user_file_load(self):
+            pass
+
+        @abstractmethod
+        def on_batch_file_load(self):
+            pass
+
+        @abstractmethod
+        def on_processed_clicked(self):
+            pass
+
+        @abstractmethod
+        def on_processing_finished(self):
+            pass
+
+    def __init__(self, main_presenter):
+        """
+        Initialise the interface
+        """
+        super(QtGui.QMainWindow, self).__init__()
+        self.setupUi(self)
+
+        # Main presenter
+        self._main_presenter = main_presenter
+
+        # Algorithm configuration
+        self._gui_algorithm_name = self._main_presenter.get_gui_algorithm_name()
+        self._white_list_entries = self._main_presenter.get_white_list()
+        self._black_list = self._main_presenter.get_black_list()
+
+        # Listeners allow us to to notify all presenters
+        self._settings_listeners = []
+
+        # Q Settings
+        self.__generic_settings = "Mantid/ISISSANS"
+        self.__path_key = "sans_path"
+        self.__instrument_name = "sans_instrument"
+
+        # Logger
+        self.gui_logger = Logger("SANS GUI LOGGER")
+
+        # Instrument
+        SANSDataProcessorGui.INSTRUMENTS = ",".join([SANSInstrument.to_string(item)
+                                                     for item in [SANSInstrument.SANS2D,
+                                                                  SANSInstrument.LOQ,
+                                                                  SANSInstrument.LARMOR]])
+        settings = QtCore.QSettings()
+        settings.beginGroup(self.__generic_settings)
+        instrument_name = settings.value(self.__instrument_name,
+                                         SANSInstrument.to_string(SANSInstrument.NoInstrument),
+                                         type=str)
+        settings.endGroup()
+        self._instrument = SANSInstrument.from_string(instrument_name)
+
+        # Attach validators
+        self._attach_validators()
+
+    def add_listener(self, listener):
+        if not isinstance(listener, SANSDataProcessorGui.RunTabListener):
+            raise ValueError("The listener ist not of type RunTabListener but rather {}".format(type(listener)))
+        self._settings_listeners.append(listener)
+
+    def clear_listeners(self):
+        self._settings_listeners = []
+
+    def _call_settings_listeners(self, target):
+        for listener in self._settings_listeners:
+            target(listener)
+
+    def set_current_page(self, index):
+        self.main_stacked_widget.setCurrentIndex(index)
+
+    def setup_layout(self):
+        """
+        Do further setup that could not be done in the designer.
+        So far only two menus have been added, we need to add the processing table manually.
+        """
+        # --------------------------------------------------------------------------------------------------------------
+        # Tab selection
+        # --------------------------------------------------------------------------------------------------------------
+        # QtGui.QWi
+        self.tab_choice_list.setAlternatingRowColors(True)
+        self.tab_choice_list.setSpacing(10)
+        self.tab_choice_list.currentRowChanged.connect(self.set_current_page)
+        self.set_current_page(0)
+
+        path = os.path.dirname(__file__)
+        runs_icon_path = os.path.join(path, "icons", "run.png")
+        runs_icon = QtGui.QIcon(runs_icon_path)
+        _ = QtGui.QListWidgetItem(runs_icon, "Runs", self.tab_choice_list)  # noqa
+
+        settings_icon_path = os.path.join(path, "icons", "settings.png")
+        settings_icon = QtGui.QIcon(settings_icon_path)
+        _ = QtGui.QListWidgetItem(settings_icon, "Settings", self.tab_choice_list)  # noqa
+
+        # --------------------------------------------------------------------------------------------------------------
+        # Algorithm setup
+        # --------------------------------------------------------------------------------------------------------------
+        # Setup white list
+        white_list = MantidQt.MantidWidgets.DataProcessorWhiteList()
+        for entry in self._white_list_entries:
+            # If there is a column name specified, then it is a white list entry.
+            if entry.column_name:
+                white_list.addElement(entry.column_name, entry.algorithm_property, entry.description,
+                                      entry.show_value, entry.prefix)
+
+        # Setup the black list, ie the properties which should not appear in the Options column
+
+        # Processing algorithm (mandatory)
+        alg = MantidQt.MantidWidgets.DataProcessorProcessingAlgorithm(self._gui_algorithm_name, 'unused_',
+                                                                      self._black_list)
+
+        # --------------------------------------------------------------------------------------------------------------
+        # Main Tab
+        # --------------------------------------------------------------------------------------------------------------
+        self.data_processor_table = MantidQt.MantidWidgets.QDataProcessorWidget(white_list, alg, self)
+        self.data_processor_table.setForcedReProcessing(True)
+        self._setup_main_tab()
+
+        # --------------------------------------------------------------------------------------------------------------
+        # Settings tabs
+        # --------------------------------------------------------------------------------------------------------------
+        self.reset_all_fields_to_default()
+        self.pixel_adjustment_det_1_push_button.clicked.connect(self._on_load_pixel_adjustment_det_1)
+        self.pixel_adjustment_det_2_push_button.clicked.connect(self._on_load_pixel_adjustment_det_2)
+        self.wavelength_adjustment_det_1_push_button.clicked.connect(self._on_load_wavelength_adjustment_det_1)
+        self.wavelength_adjustment_det_2_push_button.clicked.connect(self._on_load_wavelength_adjustment_det_2)
+
+        # Set the merge settings
+        self.reduction_mode_combo_box.currentIndexChanged.connect(self._on_reduction_mode_selection_has_changed)
+        self._on_reduction_mode_selection_has_changed()  # Disable the merge settings initially
+
+        # Set the q resolution aperture shape settings
+        self.q_resolution_shape_combo_box.currentIndexChanged.connect(self._on_q_resolution_shape_has_changed)
+        self.q_resolution_group_box.toggled.connect(self._on_q_resolution_shape_has_changed)
+        self._on_q_resolution_shape_has_changed()
+
+        # Set the transmission fit selection
+        self.fit_selection_combo_box.currentIndexChanged.connect(self._on_fit_selection_has_changed)
+        self._on_fit_selection_has_changed()
+
+        # Set the transmission polynomial order
+        self.fit_sample_fit_type_combo_box.currentIndexChanged.connect(self._on_transmission_fit_type_has_changed)
+        self.fit_can_fit_type_combo_box.currentIndexChanged.connect(self._on_transmission_fit_type_has_changed)
+        self._on_transmission_fit_type_has_changed()
+
+        # Set the transmission target
+        self.transmission_target_combo_box.currentIndexChanged.connect(self._on_transmission_target_has_changed)
+        self._on_transmission_target_has_changed()
+
+        # Roi and Mask files
+        self.transmission_roi_files_push_button.clicked.connect(self._on_load_transmission_roi_files)
+        self.transmission_mask_files_push_button.clicked.connect(self._on_load_transmission_mask_files)
+
+        # Q Resolution
+        self.q_resolution_moderator_file_push_button.clicked.connect(self._on_load_moderator_file)
+
+        return True
+
+    def _setup_main_tab(self):
+        # --------------------------------------------------------------------------------------------------------------
+        # Header setup
+        # --------------------------------------------------------------------------------------------------------------
+        self.user_file_button.clicked.connect(self._on_user_file_load)
+        self.batch_button.clicked.connect(self._on_batch_file_load)
+
+        # --------------------------------------------------------------------------------------------------------------
+        # Table setup
+        # --------------------------------------------------------------------------------------------------------------
+        # Add the presenter to the data processor
+        self.data_processor_table.accept(self._main_presenter)
+
+        # Set the list of available instruments in the widget and the default instrument
+        instrument_name = SANSInstrument.to_string(self._instrument)
+        self.data_processor_table.setInstrumentList(SANSDataProcessorGui.INSTRUMENTS, instrument_name)
+
+        # The widget will emit a 'runAsPythonScript' signal to run python code
+        self.data_processor_table.runAsPythonScript.connect(self._run_python_code)
+        self.data_processor_table.processButtonClicked.connect(self._processed_clicked)
+        self.data_processor_table.processingFinished.connect(self._processing_finished)
+        self.data_processor_widget_layout.addWidget(self.data_processor_table)
+
+        self.data_processor_table.instrumentHasChanged.connect(self._handle_instrument_change)
+
+    def _processed_clicked(self):
+        """
+        Process runs
+        """
+        self._call_settings_listeners(lambda listener: listener.on_processed_clicked())
+
+    def _processing_finished(self):
+        """
+        Clean up
+        """
+        self._call_settings_listeners(lambda listener: listener.on_processing_finished())
+
+    def _on_user_file_load(self):
+        """
+        Load the user file
+        """
+        # Load the user file
+        self._load_file(self.user_file_line_edit, "*.*", self.__generic_settings, self.__path_key,
+                        self.get_user_file_path)
+
+        # Notify presenters
+        self._call_settings_listeners(lambda listener: listener.on_user_file_load())
+
+    def _on_batch_file_load(self):
+        """
+        Load the batch file
+        """
+        self._load_file(self.batch_line_edit, "*.*", self.__generic_settings, self.__path_key,
+                        self.get_batch_file_path)
+        self._call_settings_listeners(lambda listener: listener.on_batch_file_load())
+
+    def _set_mantid_instrument(self, instrument_string):
+        # Add the instrument to the settings
+        settings = QtCore.QSettings()
+        settings.beginGroup(self.__generic_settings)
+        settings.setValue(self.__instrument_name, instrument_string)
+        settings.endGroup()
+
+        # Set the default instrument on Mantid
+        config.setFacility("ISIS")
+        config.setString("default.instrument", instrument_string)
+
+    def _handle_instrument_change(self):
+        instrument_string = str(self.data_processor_table.getCurrentInstrument())
+        self._set_mantid_instrument(instrument_string)
+
+    def get_user_file_path(self):
+        return str(self.user_file_line_edit.text())
+
+    def get_batch_file_path(self):
+        return str(self.batch_line_edit.text())
+
+    @staticmethod
+    def _load_file(line_edit_field, filter_for_dialog, q_settings_group_key, q_settings_key, func):
+        # Get the last location of the user file
+        settings = QtCore.QSettings()
+        settings.beginGroup(q_settings_group_key)
+        last_path = settings.value(q_settings_key, "", type=str)
+        settings.endGroup()
+
+        # Open the dialog
+        open_file_dialog(line_edit_field, filter_for_dialog, last_path)
+
+        # Save the new location
+        new_path, _ = os.path.split(func())
+        if new_path:
+            settings = QtCore.QSettings()
+            settings.beginGroup(q_settings_group_key)
+            settings.setValue(q_settings_key, new_path)
+            settings.endGroup()
+
+    def _on_load_pixel_adjustment_det_1(self):
+        self._load_file(self.pixel_adjustment_det_1_line_edit, "*.*", self.__generic_settings,
+                        self.__path_key,  self.get_pixel_adjustment_det_1)
+
+    def get_pixel_adjustment_det_1(self):
+        return str(self.pixel_adjustment_det_1_line_edit.text())
+
+    def _on_load_pixel_adjustment_det_2(self):
+        self._load_file(self.pixel_adjustment_det_2_line_edit, "*.*", self.__generic_settings,
+                        self.__path_key,  self.get_pixel_adjustment_det_2)
+
+    def get_pixel_adjustment_det_2(self):
+        return str(self.pixel_adjustment_det_2_line_edit.text())
+
+    def _on_load_wavelength_adjustment_det_1(self):
+        self._load_file(self.wavelength_adjustment_det_1_line_edit, "*.*", self.__generic_settings,
+                        self.__path_key,  self.get_wavelength_adjustment_det_1)
+
+    def get_wavelength_adjustment_det_1(self):
+        return str(self.wavelength_adjustment_det_1_line_edit.text())
+
+    def _on_load_wavelength_adjustment_det_2(self):
+        self._load_file(self.wavelength_adjustment_det_2_line_edit, "*.*", self.__generic_settings,
+                        self.__path_key,  self.get_wavelength_adjustment_det_2)
+
+    def get_wavelength_adjustment_det_2(self):
+        return str(self.wavelength_adjustment_det_2_line_edit.text())
+
+    def _on_reduction_mode_selection_has_changed(self):
+        selection = self.reduction_mode_combo_box.currentText()
+        is_merged = selection == ReductionMode.to_string(ReductionMode.Merged)
+        self.merged_settings.setEnabled(is_merged)
+
+    def _on_q_resolution_shape_has_changed(self):
+        shape_selection = self.q_resolution_shape_combo_box.currentIndex()
+        use_q_resolution = self.q_resolution_group_box.isChecked()
+        has_circular_aperture_been_selected = shape_selection == 0
+
+        enable_circular = has_circular_aperture_been_selected and use_q_resolution
+        enable_rectangular = not has_circular_aperture_been_selected and use_q_resolution
+
+        self.q_resolution_source_a_line_edit.setEnabled(enable_circular)
+        self.q_resolution_sample_a_line_edit.setEnabled(enable_circular)
+        self.q_resolution_source_a_label.setEnabled(enable_circular)
+        self.q_resolution_sample_a_label.setEnabled(enable_circular)
+
+        self.q_resolution_source_h_line_edit.setEnabled(enable_rectangular)
+        self.q_resolution_sample_h_line_edit.setEnabled(enable_rectangular)
+        self.q_resolution_source_w_line_edit.setEnabled(enable_rectangular)
+        self.q_resolution_sample_w_line_edit.setEnabled(enable_rectangular)
+        self.q_resolution_source_h_label.setEnabled(enable_rectangular)
+        self.q_resolution_sample_h_label.setEnabled(enable_rectangular)
+        self.q_resolution_source_w_label.setEnabled(enable_rectangular)
+        self.q_resolution_sample_w_label.setEnabled(enable_rectangular)
+
+    def set_q_resolution_shape_to_rectangular(self, is_rectangular):
+        index = 1 if is_rectangular else 0
+        self.q_resolution_shape_combo_box.setCurrentIndex(index)
+
+    def _on_fit_selection_has_changed(self):
+        fit_selection = self.fit_selection_combo_box.currentIndex()
+        use_settings_for_sample_and_can = fit_selection == 0
+        # If we use the same settings for the sample and the can, then we don't need the inputs for the can, hence
+        # we can hide them, else we need to make sure they are shown.
+        if use_settings_for_sample_and_can:
+            self.fit_sample_label.setText("Sample and Can")
+        else:
+            self.fit_sample_label.setText("Sample               ")
+
+        show_can = not use_settings_for_sample_and_can
+        self.fit_can_label.setVisible(show_can)
+        self.fit_can_use_fit_check_box.setVisible(show_can)
+        self.fit_can_fit_type_combo_box.setVisible(show_can)
+        self.fit_can_wavelength_combo_box.setVisible(show_can)
+        self.fit_can_polynomial_order_spin_box.setVisible(show_can)
+
+    def set_fit_selection(self, use_separate):
+        index = 1 if use_separate else 0
+        self.fit_selection_combo_box.setCurrentIndex(index)
+
+    def use_same_transmission_fit_setting_for_sample_and_can(self):
+        return self.fit_selection_combo_box.currentIndex() == 0
+
+    def _on_transmission_fit_type_has_changed(self):
+        # Check the sample settings
+        fit_type_sample_as_string = self.fit_sample_fit_type_combo_box.currentText().encode('utf-8')
+        fit_type_sample = FitType.from_string(fit_type_sample_as_string)
+        is_sample_polynomial = fit_type_sample is FitType.Polynomial
+        self.fit_sample_polynomial_order_spin_box.setEnabled(is_sample_polynomial)
+
+        # Check the can settings
+        fit_type_can_as_string = self.fit_can_fit_type_combo_box.currentText().encode('utf-8')
+        fit_type_can = FitType.from_string(fit_type_can_as_string)
+        is_can_polynomial = fit_type_can is FitType.Polynomial
+        self.fit_can_polynomial_order_spin_box.setEnabled(is_can_polynomial)
+
+    def _on_transmission_target_has_changed(self):
+        use_monitor = self.transmission_target_combo_box.currentIndex() == 0
+        use_roi = not use_monitor
+
+        self.transmission_monitor_label.setEnabled(use_monitor)
+        self.transmission_m3_radio_button.setEnabled(use_monitor)
+        self.transmission_m4_radio_button.setEnabled(use_monitor)
+        self.transmission_m4_shift_label.setEnabled(use_monitor)
+        self.transmission_m4_shift_line_edit.setEnabled(use_monitor)
+
+        self.transmission_radius_label.setEnabled(use_roi)
+        self.transmission_radius_line_edit.setEnabled(use_roi)
+        self.transmission_roi_files_label.setEnabled(use_roi)
+        self.transmission_roi_files_line_edit.setEnabled(use_roi)
+        self.transmission_roi_files_push_button.setEnabled(use_roi)
+        self.transmission_mask_files_label.setEnabled(use_roi)
+        self.transmission_mask_files_line_edit.setEnabled(use_roi)
+        self.transmission_mask_files_push_button.setEnabled(use_roi)
+
+    def get_transmission_roi_files(self):
+        return str(self.transmission_roi_files_line_edit.text())
+
+    def _on_load_transmission_roi_files(self):
+        self._load_file(self.transmission_roi_files_line_edit, "*.*", self.__generic_settings,
+                        self.__path_key,  self.get_transmission_roi_files)
+
+    def get_transmission_mask_files(self):
+        return str(self.transmission_mask_files_line_edit.text())
+
+    def _on_load_transmission_mask_files(self):
+        self._load_file(self.transmission_mask_files_line_edit, "*.*", self.__generic_settings,
+                        self.__path_key,  self.get_transmission_mask_files)
+
+    def get_moderator_file(self):
+        return str(self.q_resolution_moderator_file_line_edit.text())
+
+    def _on_load_moderator_file(self):
+        self._load_file(self.q_resolution_moderator_file_line_edit, "*.*", self.__generic_settings,
+                        self.__path_key,  self.get_moderator_file)
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Elements which can be set and read by the model
+    # ------------------------------------------------------------------------------------------------------------------
+    def handle_instrument_change(self):
+        # TODO need to read it and set it as the default instrument
+        pass
+
+    def set_instrument_settings(self, instrument):
+        if instrument:
+            self._instrument = instrument
+            instrument_string = SANSInstrument.to_string(instrument)
+            self.data_processor_table.setInstrumentList(SANSDataProcessorGui.INSTRUMENTS, instrument_string)
+            self._set_mantid_instrument(instrument_string)
+
+    def update_gui_combo_box(self, value, expected_type, combo_box):
+        # There are two types of values that can be passed:
+        # Lists: we set the combo box to the values in the list
+        # expected_type: we set the expected type
+        if isinstance(value, list):
+            gui_element = getattr(self, combo_box)
+            gui_element.clear()
+            for element in value:
+                self._add_list_element_to_combo_box(gui_element=gui_element, element=element,
+                                                    expected_type=expected_type)
+        else:
+            # Convert the value to the correct GUI string
+            if issubclass(value, expected_type):
+                gui_element = getattr(self, combo_box)
+                self._set_enum_as_element_in_combo_box(gui_element=gui_element, element=value,
+                                                       expected_type=expected_type)
+            else:
+                raise RuntimeError("Expected an input of type {}, but got {}".format(expected_type, type(value)))
+
+    def _add_list_element_to_combo_box(self, gui_element, element, expected_type=None):
+        if expected_type is not None and isclass(element) and issubclass(element, expected_type):
+            self._set_enum_as_element_in_combo_box(gui_element=gui_element, element=element,
+                                                   expected_type=expected_type)
+        else:
+            gui_element.addItem(element)
+
+    @staticmethod
+    def _set_enum_as_element_in_combo_box(gui_element, element, expected_type):
+        value_as_string = expected_type.to_string(element)
+        index = gui_element.findText(value_as_string)
+        if index != -1:
+            gui_element.setCurrentIndex(index)
+
+    def get_simple_line_edit_field(self, expected_type, line_edit):
+        gui_element = getattr(self, line_edit)
+        value_as_string = gui_element.text()
+        return expected_type(value_as_string) if value_as_string else None
+
+    def update_simple_line_edit_field(self, line_edit, value):
+        if value:
+            gui_element = getattr(self, line_edit)
+            gui_element.setText(str(value))
+
+    # $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
+    # $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
+    # START ACCESSORS
+    # $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
+    # $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
+
+    # ==================================================================================================================
+    # ==================================================================================================================
+    # FRONT TAB
+    # ==================================================================================================================
+    # ==================================================================================================================
+
+    # -----------------------------------------------------------------
+    # Save Options
+    # -----------------------------------------------------------------
+    @property
+    def save_types(self):
+        checked_save_types = []
+        if self.can_sas_checkbox.isChecked():
+            checked_save_types.append(SaveType.CanSAS)
+        if self.nx_can_sas_checkbox.isChecked():
+            checked_save_types.append(SaveType.NXcanSAS)
+        if self.rkh_checkbox.isChecked():
+            checked_save_types.append(SaveType.RKH)
+        if self.nist_qxy_checkbox.isChecked():
+            checked_save_types.append(SaveType.NistQxy)
+        return checked_save_types
+
+    @save_types.setter
+    def save_types(self, values):
+        for value in values:
+            if value is SaveType.CanSAS:
+                self.can_sas_checkbox.setChecked(True)
+            elif value is SaveType.NXcanSAS:
+                self.nx_can_sas_checkbox.setChecked(True)
+            elif value is SaveType.RKH:
+                self.rkh_checkbox.setChecked(True)
+            elif value is SaveType.NistQxy:
+                self.nist_qxy_checkbox.setChecked(True)
+
+    @property
+    def zero_error_free(self):
+        return self.save_zero_error_free.isChecked()
+
+    @zero_error_free.setter
+    def zero_error_free(self, value):
+        self.save_zero_error_free.setChecked(value)
+
+    # -----------------------------------------------------------------
+    # Global options
+    # -----------------------------------------------------------------
+    @property
+    def use_optimizations(self):
+        return self.use_optimizations_checkbox.isChecked()
+
+    @use_optimizations.setter
+    def use_optimizations(self, value):
+        self.use_optimizations_checkbox.setChecked(value)
+
+    @property
+    def output_mode(self):
+        if self.output_mode_memory_radio_button.isChecked():
+            return OutputMode.PublishToADS
+        elif self.output_mode_file_radio_button.isChecked():
+            return OutputMode.SaveToFile
+        elif self.output_mode_both_radio_button.isChecked():
+            return OutputMode.Both
+        else:
+            self.gui_logger.warning("The output format was not specified. Defaulting to saving to memory only.")
+            return OutputMode.PublishToADS
+
+    @output_mode.setter
+    def output_mode(self, value):
+        if value is OutputMode.PublishToADS:
+            self.output_mode_memory_radio_button.setChecked(True)
+        elif value is OutputMode.SaveToFile:
+            self.output_mode_file_radio_button.setChecked(True)
+        elif value is OutputMode.Both:
+            self.output_mode_both_radio_button.setCheck(True)
+
+    @property
+    def compatibility_mode(self):
+        return self.event_binning_group_box.isChecked()
+
+    @compatibility_mode.setter
+    def compatibility_mode(self, value):
+        self.event_binning_group_box.setChecked(value)
+
+    # ==================================================================================================================
+    # ==================================================================================================================
+    # General TAB
+    # ==================================================================================================================
+    # ==================================================================================================================
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # General group
+    # ------------------------------------------------------------------------------------------------------------------
+    @property
+    def reduction_dimensionality(self):
+        return ReductionDimensionality.OneDim if self.reduction_dimensionality_1D.isChecked() \
+            else ReductionDimensionality.TwoDim
+
+    @reduction_dimensionality.setter
+    def reduction_dimensionality(self, value):
+        is_1d = value is ReductionDimensionality.OneDim
+        self.reduction_dimensionality_1D.setChecked(is_1d)
+        self.reduction_dimensionality_2D.setChecked(not is_1d)
+
+    @property
+    def reduction_mode(self):
+        reduction_mode_as_string = self.reduction_mode_combo_box.currentText()
+        return get_reduction_mode_from_gui_selection(reduction_mode_as_string)
+
+    @reduction_mode.setter
+    def reduction_mode(self, value):
+        # There are two types of values that can be passed:
+        # String: we look for string and we set it
+
+        # Convert the value to the correct GUI string
+        reduction_mode_as_string = get_string_for_gui_from_reduction_mode(value, self._instrument)
+        if reduction_mode_as_string:
+            index = self.reduction_mode_combo_box.findText(reduction_mode_as_string)
+            if index != -1:
+                self.reduction_mode_combo_box.setCurrentIndex(index)
+
+    def set_reduction_modes(self, reduction_mode_list):
+        current_index = self.reduction_mode_combo_box.currentIndex()
+        self.reduction_mode_combo_box.clear()
+        for element in reduction_mode_list:
+            self.reduction_mode_combo_box.addItem(element)
+        if current_index != -1:
+            self.reduction_mode_combo_box.setCurrentIndex(current_index)
+
+    @property
+    def merge_scale(self):
+        return self.get_simple_line_edit_field(line_edit="merged_scale_line_edit", expected_type=float)
+
+    @merge_scale.setter
+    def merge_scale(self, value):
+        pass
+
+    @property
+    def merge_shift(self):
+        return self.get_simple_line_edit_field(line_edit="merged_shift_line_edit", expected_type=float)
+
+    @merge_shift.setter
+    def merge_shift(self, value):
+        pass
+
+    @property
+    def merge_scale_fit(self):
+        return self.merged_scale_use_fit_check_box.isChecked()
+
+    @merge_scale_fit.setter
+    def merge_scale_fit(self, value):
+        self.merged_scale_use_fit_check_box.setChecked(value)
+
+    @property
+    def merge_shift_fit(self):
+        return self.merged_shift_use_fit_check_box.isChecked()
+
+    @merge_shift_fit.setter
+    def merge_shift_fit(self, value):
+        self.merged_shift_use_fit_check_box.setChecked(value)
+
+    @property
+    def merge_q_range_start(self):
+        return self.get_simple_line_edit_field(line_edit="merged_q_range_start_line_edit", expected_type=float)
+
+    @merge_q_range_start.setter
+    def merge_q_range_start(self, value):
+        if value is not None:
+            self.update_simple_line_edit_field(line_edit="merged_q_range_start_line_edit", value=value)
+
+    @property
+    def merge_q_range_stop(self):
+        return self.get_simple_line_edit_field(line_edit="merged_q_range_stop_line_edit", expected_type=float)
+
+    @merge_q_range_stop.setter
+    def merge_q_range_stop(self, value):
+        if value is not None:
+            self.update_simple_line_edit_field(line_edit="merged_q_range_stop_line_edit", value=value)
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Event slices group
+    # ------------------------------------------------------------------------------------------------------------------
+    @property
+    def event_slices(self):
+        return str(self.slice_event_line_edit.text())
+
+    @event_slices.setter
+    def event_slices(self, value):
+        self.slice_event_line_edit.setText(value)
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Event slices group
+    # ------------------------------------------------------------------------------------------------------------------
+    @property
+    def event_binning(self):
+        return str(self.event_binning_line_edit.text())
+
+    @event_binning.setter
+    def event_binning(self, value):
+        self.event_binning_line_edit.setText(value)
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Wavelength Group
+    # ------------------------------------------------------------------------------------------------------------------
+    @property
+    def wavelength_step_type(self):
+        step_type_as_string = self.wavelength_step_type_combo_box.currentText().encode('utf-8')
+        return RangeStepType.from_string(step_type_as_string)
+
+    @wavelength_step_type.setter
+    def wavelength_step_type(self, value):
+        self.update_gui_combo_box(value=value, expected_type=RangeStepType, combo_box="wavelength_step_type_combo_box")
+
+    @property
+    def wavelength_min(self):
+        return self.get_simple_line_edit_field(line_edit="wavelength_min_line_edit", expected_type=float)
+
+    @wavelength_min.setter
+    def wavelength_min(self, value):
+        self.update_simple_line_edit_field(line_edit="wavelength_min_line_edit", value=value)
+
+    @property
+    def wavelength_max(self):
+        return self.get_simple_line_edit_field(line_edit="wavelength_max_line_edit", expected_type=float)
+
+    @wavelength_max.setter
+    def wavelength_max(self, value):
+        self.update_simple_line_edit_field(line_edit="wavelength_max_line_edit", value=value)
+
+    @property
+    def wavelength_step(self):
+        return self.get_simple_line_edit_field(line_edit="wavelength_step_line_edit", expected_type=float)
+
+    @wavelength_step.setter
+    def wavelength_step(self, value):
+        self.update_simple_line_edit_field(line_edit="wavelength_step_line_edit", value=value)
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Scale Group
+    # ------------------------------------------------------------------------------------------------------------------
+    @property
+    def sample_shape(self):
+        geometry_as_string = self.geometry_combo_box.currentText().encode('utf-8')
+        # Either the selection is something that can be converted to a SampleShape or we need to read from file
+        try:
+            return SampleShape.from_string(geometry_as_string)
+        except RuntimeError:
+            return None
+
+    @sample_shape.setter
+    def sample_shape(self, value):
+        if value is None:
+            # Set to the default
+            self.geometry_combo_box.setCurrentIndex(0)
+        else:
+            self.update_gui_combo_box(value=value, expected_type=SampleShape, combo_box="geometry_combo_box")
+
+    @property
+    def absolute_scale(self):
+        return self.get_simple_line_edit_field(line_edit="absolute_scale_line_edit", expected_type=float)
+
+    @absolute_scale.setter
+    def absolute_scale(self, value):
+        self.update_simple_line_edit_field(line_edit="absolute_scale_line_edit", value=value)
+
+    @property
+    def sample_height(self):
+        return self.get_simple_line_edit_field(line_edit="height_line_edit", expected_type=float)
+
+    @sample_height.setter
+    def sample_height(self, value):
+        self.update_simple_line_edit_field(line_edit="height_line_edit", value=value)
+
+    @property
+    def sample_width(self):
+        return self.get_simple_line_edit_field(line_edit="width_line_edit", expected_type=float)
+
+    @sample_width.setter
+    def sample_width(self, value):
+        self.update_simple_line_edit_field(line_edit="width_line_edit", value=value)
+
+    @property
+    def sample_thickness(self):
+        return self.get_simple_line_edit_field(line_edit="thickness_line_edit", expected_type=float)
+
+    @sample_thickness.setter
+    def sample_thickness(self, value):
+        self.update_simple_line_edit_field(line_edit="thickness_line_edit", value=value)
+
+    @property
+    def z_offset(self):
+        return self.get_simple_line_edit_field(line_edit="z_offset_line_edit", expected_type=float)
+
+    @z_offset.setter
+    def z_offset(self, value):
+        self.update_simple_line_edit_field(line_edit="z_offset_line_edit", value=value)
+
+    # ==================================================================================================================
+    # ==================================================================================================================
+    # ADJUSTMENT TAB
+    # ==================================================================================================================
+    # ==================================================================================================================
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Monitor normalization
+    # ------------------------------------------------------------------------------------------------------------------
+    @property
+    def normalization_incident_monitor(self):
+        return self.get_simple_line_edit_field(line_edit="monitor_normalization_line_edit", expected_type=int)
+
+    @normalization_incident_monitor.setter
+    def normalization_incident_monitor(self, value):
+        self.update_simple_line_edit_field(line_edit="monitor_normalization_line_edit", value=value)
+
+    @property
+    def normalization_interpolate(self):
+        return self.monitor_normalization_interpolating_rebin_check_box.isChecked()
+
+    @normalization_interpolate.setter
+    def normalization_interpolate(self, value):
+        self.monitor_normalization_interpolating_rebin_check_box.setChecked(value)
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Transmission
+    # ------------------------------------------------------------------------------------------------------------------
+    @property
+    def transmission_incident_monitor(self):
+        return self.get_simple_line_edit_field(line_edit="transmission_line_edit", expected_type=int)
+
+    @transmission_incident_monitor.setter
+    def transmission_incident_monitor(self, value):
+        self.update_simple_line_edit_field(line_edit="transmission_line_edit", value=value)
+
+    @property
+    def transmission_interpolate(self):
+        return self.transmission_interpolating_rebin_check_box.isChecked()
+
+    @transmission_interpolate.setter
+    def transmission_interpolate(self, value):
+        self.transmission_interpolating_rebin_check_box.setChecked(value)
+
+    @property
+    def transmission_roi_files(self):
+        return self.get_simple_line_edit_field(line_edit="transmission_roi_files_line_edit", expected_type=str)
+
+    @transmission_roi_files.setter
+    def transmission_roi_files(self, value):
+        self.update_simple_line_edit_field(line_edit="transmission_roi_files_line_edit", value=value)
+
+    @property
+    def transmission_mask_files(self):
+        return self.get_simple_line_edit_field(line_edit="transmission_mask_files_line_edit", expected_type=str)
+
+    @transmission_mask_files.setter
+    def transmission_mask_files(self, value):
+        self.update_simple_line_edit_field(line_edit="transmission_mask_files_line_edit", value=value)
+
+    @property
+    def transmission_radius(self):
+        return self.get_simple_line_edit_field(line_edit="transmission_radius_line_edit", expected_type=float)
+
+    @transmission_radius.setter
+    def transmission_radius(self, value):
+        self.update_simple_line_edit_field(line_edit="transmission_radius_line_edit", value=value)
+
+    @property
+    def transmission_monitor(self):
+        return 3 if self.transmission_m3_radio_button.isChecked() else 4
+
+    @transmission_monitor.setter
+    def transmission_monitor(self, value):
+        if value == 3:
+            self.transmission_m3_radio_button.setChecked(True)
+        else:
+            self.transmission_m4_radio_button.setChecked(True)
+
+    @property
+    def transmission_m4_shift(self):
+        return self.get_simple_line_edit_field(line_edit="transmission_m4_shift_line_edit", expected_type=float)
+
+    @transmission_m4_shift.setter
+    def transmission_m4_shift(self, value):
+        self.update_simple_line_edit_field(line_edit="transmission_m4_shift_line_edit", value=value)
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Transmission fit
+    # ------------------------------------------------------------------------------------------------------------------
+    @property
+    def transmission_sample_use_fit(self):
+        return self.fit_sample_use_fit_check_box.isChecked()
+
+    @transmission_sample_use_fit.setter
+    def transmission_sample_use_fit(self, value):
+        self.fit_sample_use_fit_check_box.setChecked(value)
+
+    @property
+    def transmission_can_use_fit(self):
+        return self.fit_can_use_fit_check_box.isChecked()
+
+    @transmission_can_use_fit.setter
+    def transmission_can_use_fit(self, value):
+        self.fit_can_use_fit_check_box.setChecked(value)
+
+    @property
+    def transmission_sample_fit_type(self):
+        fit_type_as_string = self.fit_sample_fit_type_combo_box.currentText().encode('utf-8')
+        return FitType.from_string(fit_type_as_string)
+
+    @transmission_sample_fit_type.setter
+    def transmission_sample_fit_type(self, value):
+        if value is None:
+            self.fit_sample_fit_type_combo_box.setCurrentIndex(0)
+        else:
+            self.update_gui_combo_box(value=value, expected_type=FitType, combo_box="fit_sample_fit_type_combo_box")
+
+    @property
+    def transmission_can_fit_type(self):
+        fit_type_as_string = self.fit_can_fit_type_combo_box.currentText().encode('utf-8')
+        return FitType.from_string(fit_type_as_string)
+
+    @transmission_can_fit_type.setter
+    def transmission_can_fit_type(self, value):
+        if value is None:
+            self.fit_sample_fit_type_combo_box.setCurrentIndex(0)
+        else:
+            self.update_gui_combo_box(value=value, expected_type=FitType, combo_box="fit_can_fit_type_combo_box")
+
+    @staticmethod
+    def _set_polynomial_order(spin_box, value):
+        minimum = spin_box.minimum()
+        maximum = spin_box.maximum()
+        if value < minimum or value > maximum:
+            raise ValueError("The value for the polynomial order {} has "
+                             "to be in the range of {} and {}".format(value, minimum, maximum))
+        spin_box.setValue(value)
+
+    @property
+    def transmission_sample_polynomial_order(self):
+        return self.fit_sample_polynomial_order_spin_box.value()
+
+    @transmission_sample_polynomial_order.setter
+    def transmission_sample_polynomial_order(self, value):
+        self._set_polynomial_order(spin_box=self.fit_sample_polynomial_order_spin_box, value=value)
+
+    @property
+    def transmission_can_polynomial_order(self):
+        return self.fit_can_polynomial_order_spin_box.value()
+
+    @transmission_can_polynomial_order.setter
+    def transmission_can_polynomial_order(self, value):
+        self._set_polynomial_order(spin_box=self.fit_can_polynomial_order_spin_box, value=value)
+
+    @property
+    def transmission_sample_wavelength_min(self):
+        return self.get_simple_line_edit_field(line_edit="fit_sample_wavelength_min_line_edit", expected_type=float)
+
+    @transmission_sample_wavelength_min.setter
+    def transmission_sample_wavelength_min(self, value):
+        self.update_simple_line_edit_field(line_edit="fit_sample_wavelength_min_line_edit", value=value)
+
+    @property
+    def transmission_sample_wavelength_max(self):
+        return self.get_simple_line_edit_field(line_edit="fit_sample_wavelength_max_line_edit", expected_type=float)
+
+    @transmission_sample_wavelength_max.setter
+    def transmission_sample_wavelength_max(self, value):
+        self.update_simple_line_edit_field(line_edit="fit_sample_wavelength_max_line_edit", value=value)
+
+    @property
+    def transmission_can_wavelength_min(self):
+        return self.get_simple_line_edit_field(line_edit="fit_can_wavelength_min_line_edit", expected_type=float)
+
+    @transmission_can_wavelength_min.setter
+    def transmission_can_wavelength_min(self, value):
+        self.update_simple_line_edit_field(line_edit="fit_can_wavelength_min_line_edit", value=value)
+
+    @property
+    def transmission_can_wavelength_max(self):
+        return self.get_simple_line_edit_field(line_edit="fit_can_wavelength_max_line_edit", expected_type=float)
+
+    @transmission_can_wavelength_max.setter
+    def transmission_can_wavelength_max(self, value):
+        self.update_simple_line_edit_field(line_edit="fit_can_wavelength_max_line_edit", value=value)
+
+    @property
+    def transmission_sample_use_wavelength(self):
+        return self.fit_sample_wavelength_combo_box.isChecked()
+
+    @transmission_sample_use_wavelength.setter
+    def transmission_sample_use_wavelength(self, value):
+        self.fit_sample_wavelength_combo_box.setChecked(value)
+
+    @property
+    def transmission_can_use_wavelength(self):
+        return self.fit_can_wavelength_combo_box.isChecked()
+
+    @transmission_can_use_wavelength.setter
+    def transmission_can_use_wavelength(self, value):
+        self.fit_can_wavelength_combo_box.setChecked(value)
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Wavelength- and pixel-adjustment files
+    # ------------------------------------------------------------------------------------------------------------------
+    @property
+    def pixel_adjustment_det_1(self):
+        return self.get_simple_line_edit_field(line_edit="pixel_adjustment_det_1_line_edit", expected_type=str)
+
+    @pixel_adjustment_det_1.setter
+    def pixel_adjustment_det_1(self, value):
+        self.update_simple_line_edit_field(line_edit="pixel_adjustment_det_1_line_edit", value=value)
+
+    @property
+    def pixel_adjustment_det_2(self):
+        return self.get_simple_line_edit_field(line_edit="pixel_adjustment_det_2_line_edit", expected_type=str)
+
+    @pixel_adjustment_det_2.setter
+    def pixel_adjustment_det_2(self, value):
+        self.update_simple_line_edit_field(line_edit="pixel_adjustment_det_2_line_edit", value=value)
+
+    @property
+    def wavelength_adjustment_det_1(self):
+        return self.get_simple_line_edit_field(line_edit="wavelength_adjustment_det_1_line_edit", expected_type=str)
+
+    @wavelength_adjustment_det_1.setter
+    def wavelength_adjustment_det_1(self, value):
+        self.update_simple_line_edit_field(line_edit="wavelength_adjustment_det_1_line_edit", value=value)
+
+    @property
+    def wavelength_adjustment_det_2(self):
+        return self.get_simple_line_edit_field(line_edit="wavelength_adjustment_det_2_line_edit", expected_type=str)
+
+    @wavelength_adjustment_det_2.setter
+    def wavelength_adjustment_det_2(self, value):
+        self.update_simple_line_edit_field(line_edit="wavelength_adjustment_det_2_line_edit", value=value)
+
+    # ==================================================================================================================
+    # ==================================================================================================================
+    # Q TAB
+    # ==================================================================================================================
+    # ==================================================================================================================
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Q limit
+    # ------------------------------------------------------------------------------------------------------------------
+    @property
+    def q_1d_min(self):
+        return self.get_simple_line_edit_field(line_edit="q_1d_min_line_edit", expected_type=float)
+
+    @q_1d_min.setter
+    def q_1d_min(self, value):
+        self.update_simple_line_edit_field(line_edit="q_1d_min_line_edit", value=value)
+
+    @property
+    def q_1d_max(self):
+        return self.get_simple_line_edit_field(line_edit="q_1d_max_line_edit", expected_type=float)
+
+    @q_1d_max.setter
+    def q_1d_max(self, value):
+        self.update_simple_line_edit_field(line_edit="q_1d_max_line_edit", value=value)
+
+    @property
+    def q_1d_step(self):
+        return self.get_simple_line_edit_field(line_edit="q_1d_step_line_edit", expected_type=float)
+
+    @q_1d_step.setter
+    def q_1d_step(self, value):
+        self.update_simple_line_edit_field(line_edit="q_1d_step_line_edit", value=value)
+
+    @property
+    def q_1d_step_type(self):
+        q_1d_step_type_as_string = self.q_1d_step_type_combo_box.currentText().encode('utf-8')
+        # Either the selection is something that can be converted to a SampleShape or we need to read from file
+        try:
+            return RangeStepType.from_string(q_1d_step_type_as_string)
+        except RuntimeError:
+            return None
+
+    @q_1d_step_type.setter
+    def q_1d_step_type(self, value):
+        if value is None:
+            # Set to the default
+            self.q_1d_step_type_combo_box.setCurrentIndex(0)
+        else:
+            self.update_gui_combo_box(value=value, expected_type=RangeStepType, combo_box="q_1d_step_type_combo_box")
+
+    @property
+    def q_xy_max(self):
+        return self.get_simple_line_edit_field(line_edit="q_xy_max_line_edit", expected_type=float)
+
+    @q_xy_max.setter
+    def q_xy_max(self, value):
+        self.update_simple_line_edit_field(line_edit="q_xy_max_line_edit", value=value)
+
+    @property
+    def q_xy_step(self):
+        return self.get_simple_line_edit_field(line_edit="q_xy_step_line_edit", expected_type=float)
+
+    @q_xy_step.setter
+    def q_xy_step(self, value):
+        self.update_simple_line_edit_field(line_edit="q_xy_step_line_edit", value=value)
+
+    @property
+    def q_xy_step_type(self):
+        q_xy_step_type_as_string = self.q_xy_step_type_combo_box.currentText().encode('utf-8')
+        # Either the selection is something that can be converted to a SampleShape or we need to read from file
+        try:
+            return RangeStepType.from_string(q_xy_step_type_as_string)
+        except RuntimeError:
+            return None
+
+    @q_xy_step_type.setter
+    def q_xy_step_type(self, value):
+        if value is None:
+            # Set to the default
+            self.q_xy_step_type_combo_box.setCurrentIndex(0)
+        else:
+            self.update_gui_combo_box(value=value, expected_type=RangeStepType, combo_box="q_xy_step_type_combo_box")
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Gravity
+    # ------------------------------------------------------------------------------------------------------------------
+    @property
+    def gravity_extra_length(self):
+        return self.get_simple_line_edit_field(line_edit="gravity_extra_length_line_edit", expected_type=float)
+
+    @gravity_extra_length.setter
+    def gravity_extra_length(self, value):
+        self.update_simple_line_edit_field(line_edit="gravity_extra_length_line_edit", value=value)
+
+    @property
+    def gravity_on_off(self):
+        return self.gravity_group_box.isChecked()
+
+    @gravity_on_off.setter
+    def gravity_on_off(self, value):
+        self.gravity_group_box.setChecked(value)
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Q Resolution
+    # ------------------------------------------------------------------------------------------------------------------
+    def _get_q_resolution_aperture(self, current_index, line_edit):
+        if self.q_resolution_shape_combo_box.currentIndex() == current_index:
+            return self.get_simple_line_edit_field(line_edit=line_edit, expected_type=float)
+        else:
+            return ""
+
+    @property
+    def use_q_resolution(self):
+        return self.q_resolution_group_box.isChecked()
+
+    @use_q_resolution.setter
+    def use_q_resolution(self, value):
+        self.q_resolution_group_box.setChecked(value)
+
+    @property
+    def q_resolution_source_a(self):
+        # We expected a current index 0 (since this is a circular aperture)
+        return self._get_q_resolution_aperture(current_index=0, line_edit="q_resolution_source_a_line_edit")
+
+    @q_resolution_source_a.setter
+    def q_resolution_source_a(self, value):
+        self.update_simple_line_edit_field(line_edit="q_resolution_source_a_line_edit", value=value)
+
+    @property
+    def q_resolution_sample_a(self):
+        return self._get_q_resolution_aperture(current_index=0, line_edit="q_resolution_sample_a_line_edit")
+
+    @q_resolution_sample_a.setter
+    def q_resolution_sample_a(self, value):
+        self.update_simple_line_edit_field(line_edit="q_resolution_sample_a_line_edit", value=value)
+
+    @property
+    def q_resolution_source_h(self):
+        return self._get_q_resolution_aperture(current_index=1, line_edit="q_resolution_source_h_line_edit")
+
+    @q_resolution_source_h.setter
+    def q_resolution_source_h(self, value):
+        self.update_simple_line_edit_field(line_edit="q_resolution_source_h_line_edit", value=value)
+
+    @property
+    def q_resolution_sample_h(self):
+        return self._get_q_resolution_aperture(current_index=1, line_edit="q_resolution_sample_h_line_edit")
+
+    @q_resolution_sample_h.setter
+    def q_resolution_sample_h(self, value):
+        self.update_simple_line_edit_field(line_edit="q_resolution_sample_h_line_edit", value=value)
+
+    @property
+    def q_resolution_source_w(self):
+        return self._get_q_resolution_aperture(current_index=1, line_edit="q_resolution_source_w_line_edit")
+
+    @q_resolution_source_w.setter
+    def q_resolution_source_w(self, value):
+        self.update_simple_line_edit_field(line_edit="q_resolution_source_w_line_edit", value=value)
+
+    @property
+    def q_resolution_sample_w(self):
+        return self._get_q_resolution_aperture(current_index=1, line_edit="q_resolution_sample_w_line_edit")
+
+    @q_resolution_sample_w.setter
+    def q_resolution_sample_w(self, value):
+        self.update_simple_line_edit_field(line_edit="q_resolution_sample_w_line_edit", value=value)
+
+    @property
+    def q_resolution_delta_r(self):
+        return self.get_simple_line_edit_field(line_edit="q_resolution_delta_r_line_edit", expected_type=float)
+
+    @q_resolution_delta_r.setter
+    def q_resolution_delta_r(self, value):
+        self.update_simple_line_edit_field(line_edit="q_resolution_delta_r_line_edit", value=value)
+
+    @property
+    def q_resolution_collimation_length(self):
+        return self.get_simple_line_edit_field(line_edit="q_resolution_collimation_length_line_edit",
+                                               expected_type=float)
+
+    @q_resolution_collimation_length.setter
+    def q_resolution_collimation_length(self, value):
+        self.update_simple_line_edit_field(line_edit="q_resolution_collimation_length_line_edit", value=value)
+
+    @property
+    def q_resolution_moderator_file(self):
+        return self.get_simple_line_edit_field(line_edit="q_resolution_moderator_file_line_edit", expected_type=str)
+
+    @q_resolution_moderator_file.setter
+    def q_resolution_moderator_file(self, value):
+        self.update_simple_line_edit_field(line_edit="q_resolution_moderator_file_line_edit", value=value)
+
+    # ==================================================================================================================
+    # ==================================================================================================================
+    # MASK TAB
+    # ==================================================================================================================
+    # ==================================================================================================================
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Phi Limit
+    # ------------------------------------------------------------------------------------------------------------------
+    @property
+    def phi_limit_min(self):
+        return self.get_simple_line_edit_field(line_edit="phi_limit_min_line_edit", expected_type=float)
+
+    @phi_limit_min.setter
+    def phi_limit_min(self, value):
+        self.update_simple_line_edit_field(line_edit="phi_limit_min_line_edit", value=value)
+
+    @property
+    def phi_limit_max(self):
+        return self.get_simple_line_edit_field(line_edit="phi_limit_max_line_edit", expected_type=float)
+
+    @phi_limit_max.setter
+    def phi_limit_max(self, value):
+        self.update_simple_line_edit_field(line_edit="phi_limit_max_line_edit", value=value)
+
+    @property
+    def phi_limit_use_mirror(self):
+        return self.phi_limit_use_mirror_check_box.isChecked()
+
+    @phi_limit_use_mirror.setter
+    def phi_limit_use_mirror(self, value):
+        self.phi_limit_use_mirror_check_box.setChecked(value)
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Radius Limit
+    # ------------------------------------------------------------------------------------------------------------------
+    @property
+    def radius_limit_min(self):
+        return self.get_simple_line_edit_field(line_edit="radius_limit_min_line_edit", expected_type=float)
+
+    @radius_limit_min.setter
+    def radius_limit_min(self, value):
+        self.update_simple_line_edit_field(line_edit="radius_limit_min_line_edit", value=value)
+
+    @property
+    def radius_limit_max(self):
+        return self.get_simple_line_edit_field(line_edit="radius_limit_max_line_edit", expected_type=float)
+
+    @radius_limit_max.setter
+    def radius_limit_max(self, value):
+        self.update_simple_line_edit_field(line_edit="radius_limit_max_line_edit", value=value)
+
+    # $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
+    # $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
+    # END ACCESSORS
+    # $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
+    # $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
+
+    def _attach_validators(self):
+        # Setup the list of validators
+        double_validator = QtGui.QDoubleValidator()
+        positive_double_validator = QtGui.QDoubleValidator()
+        positive_double_validator.setBottom(0.0)
+        positive_integer_validator = QtGui.QIntValidator()
+        positive_integer_validator.setBottom(1)
+
+        # -------------------------------
+        # General tab
+        # -------------------------------
+        self.merged_shift_line_edit.setValidator(double_validator)
+        self.merged_scale_line_edit.setValidator(double_validator)
+        self.merged_q_range_start_line_edit.setValidator(double_validator)
+        self.merged_q_range_stop_line_edit.setValidator(double_validator)
+
+        self.wavelength_min_line_edit.setValidator(positive_double_validator)
+        self.wavelength_max_line_edit.setValidator(positive_double_validator)
+        self.wavelength_step_line_edit.setValidator(positive_double_validator)
+
+        self.absolute_scale_line_edit.setValidator(double_validator)
+        self.height_line_edit.setValidator(positive_double_validator)
+        self.width_line_edit.setValidator(positive_double_validator)
+        self.thickness_line_edit.setValidator(positive_double_validator)
+        self.z_offset_line_edit.setValidator(double_validator)
+
+        # --------------------------------
+        # Adjustment tab
+        # --------------------------------
+        self.monitor_normalization_line_edit.setValidator(positive_integer_validator)
+        self.transmission_line_edit.setValidator(positive_integer_validator)
+        self.transmission_radius_line_edit.setValidator(positive_double_validator)
+        self.transmission_m4_shift_line_edit.setValidator(double_validator)
+
+        self.fit_sample_wavelength_min_line_edit.setValidator(positive_double_validator)
+        self.fit_sample_wavelength_max_line_edit.setValidator(positive_double_validator)
+        self.fit_can_wavelength_min_line_edit.setValidator(positive_double_validator)
+        self.fit_can_wavelength_max_line_edit.setValidator(positive_double_validator)
+
+        # --------------------------------
+        # Q tab
+        # --------------------------------
+        self.q_1d_min_line_edit.setValidator(double_validator)
+        self.q_1d_max_line_edit.setValidator(double_validator)
+        self.q_1d_step_line_edit.setValidator(positive_double_validator)
+        self.q_xy_max_line_edit.setValidator(positive_double_validator)  # Yes, this should be positive!
+        self.q_xy_step_line_edit.setValidator(positive_double_validator)
+
+        self.gravity_extra_length_line_edit.setValidator(double_validator)
+
+        self.q_resolution_source_a_line_edit.setValidator(positive_double_validator)
+        self.q_resolution_sample_a_line_edit.setValidator(positive_double_validator)
+        self.q_resolution_source_h_line_edit.setValidator(positive_double_validator)
+        self.q_resolution_sample_h_line_edit.setValidator(positive_double_validator)
+        self.q_resolution_source_w_line_edit.setValidator(positive_double_validator)
+        self.q_resolution_sample_w_line_edit.setValidator(positive_double_validator)
+        self.q_resolution_delta_r_line_edit.setValidator(positive_double_validator)
+        self.q_resolution_collimation_length_line_edit.setValidator(double_validator)
+
+    def reset_all_fields_to_default(self):
+        # ------------------------------
+        # General tab
+        # ------------------------------
+        self.reduction_dimensionality_1D.setChecked(True)
+        self.reduction_mode_combo_box.setCurrentIndex(0)
+
+        self.merged_q_range_start_line_edit.setText("")
+        self.merged_q_range_stop_line_edit.setText("")
+        self.merged_scale_line_edit.setText("")
+        self.merged_shift_line_edit.setText("")
+        self.merged_shift_use_fit_check_box.setChecked(False)
+        self.merged_scale_use_fit_check_box.setChecked(False)
+
+        self.slice_event_line_edit.setText("")
+        self.event_binning_line_edit.setText("")
+
+        self.wavelength_min_line_edit.setText("")
+        self.wavelength_max_line_edit.setText("")
+        self.wavelength_step_line_edit.setText("")
+        self.wavelength_step_type_combo_box.setCurrentIndex(0)
+
+        self.absolute_scale_line_edit.setText("")
+        self.geometry_combo_box.setCurrentIndex(0)
+        self.height_line_edit.setText("")
+        self.width_line_edit.setText("")
+        self.thickness_line_edit.setText("")
+        self.z_offset_line_edit.setText("")
+
+        # --------------------------------
+        # Adjustment tab
+        # --------------------------------
+        self.monitor_normalization_line_edit.setText("")
+        self.monitor_normalization_interpolating_rebin_check_box.setChecked(False)
+
+        self.transmission_line_edit.setText("")
+        self.transmission_interpolating_rebin_check_box.setChecked(False)
+        self.transmission_target_combo_box.setCurrentIndex(0)
+        self.transmission_m3_radio_button.setChecked(True)
+        self.transmission_m4_shift_line_edit.setText("")
+        self.transmission_radius_line_edit.setText("")
+        self.transmission_roi_files_line_edit.setText("")
+        self.transmission_mask_files_line_edit.setText("")
+
+        self.pixel_adjustment_det_1_line_edit.setText("")
+        self.pixel_adjustment_det_2_line_edit.setText("")
+
+        self.wavelength_adjustment_det_1_line_edit.setText("")
+        self.wavelength_adjustment_det_2_line_edit.setText("")
+
+        # --------------------------------
+        # Q tab
+        # --------------------------------
+        self.q_1d_min_line_edit.setText("")
+        self.q_1d_max_line_edit.setText("")
+        self.q_1d_step_line_edit.setText("")
+        self.q_1d_step_type_combo_box.setCurrentIndex(0)
+
+        self.q_xy_max_line_edit.setText("")
+        self.q_xy_step_line_edit.setText("")
+        self.q_xy_step_type_combo_box.setCurrentIndex(0)
+
+        self.gravity_group_box.setChecked(True)
+        self.gravity_extra_length_line_edit.setText("")
+
+        self.q_resolution_group_box.setChecked(False)
+        self.q_resolution_shape_combo_box.setCurrentIndex(0)
+        self.q_resolution_source_a_line_edit.setText("")
+        self.q_resolution_sample_a_line_edit.setText("")
+        self.q_resolution_source_h_line_edit.setText("")
+        self.q_resolution_sample_h_line_edit.setText("")
+        self.q_resolution_source_w_line_edit.setText("")
+        self.q_resolution_sample_w_line_edit.setText("")
+        self.q_resolution_delta_r_line_edit.setText("")
+        self.q_resolution_collimation_length_line_edit.setText("")
+        self.q_resolution_moderator_file_line_edit.setText("")
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Table interaction
+    # ------------------------------------------------------------------------------------------------------------------
+    def get_cell(self, row, column, convert_to=None):
+        value = self.data_processor_table.getCell(row, column)
+        return value if convert_to is None else convert_to(value)
+
+    def set_cell(self, value, row, column):
+        value_as_str = str(value)
+        self.data_processor_table.setCell(value_as_str, row, column)
+
+    def get_number_of_rows(self):
+        return self.data_processor_table.getNumberOfRows()
+
+    def clear_table(self):
+        self.data_processor_table.clearTable()
+
+    def add_row(self, value):
+        """
+        Inserts a row in to the table.
+
+        The value needs to have the form: "Input:test,Output:test,Options:OutputWorkspace=2", where the keys
+        are the names of the column
+        :param value: the value specifying a row
+        """
+        self.data_processor_table.transfer([value])
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # NON-ESSENTIAL (Should we get rid of it?)
+    # ------------------------------------------------------------------------------------------------------------------
+    def add_actions_to_menus(self, workspace_list):
+        """
+        Initialize table actions. Some table actions are not shown with the widget but they can be added to
+        external menus.
+        In this interface we have a 'File' menu and an 'Edit' menu
+        """
+        self.menuEdit.clear()
+        self.menuFile.clear()
+
+        # Actions that go in the 'Edit' menu
+        self._create_action(MantidQt.MantidWidgets.DataProcessorProcessCommand(self.data_processor_table),
+                            self.menuEdit)
+        self._create_action(MantidQt.MantidWidgets.DataProcessorPlotRowCommand(self.data_processor_table),
+                            self.menuEdit)
+        self._create_action(MantidQt.MantidWidgets.DataProcessorAppendRowCommand(self.data_processor_table),
+                            self.menuEdit)
+        self._create_action(MantidQt.MantidWidgets.DataProcessorCopySelectedCommand(self.data_processor_table
+                                                                                    ), self.menuEdit)
+        self._create_action(MantidQt.MantidWidgets.DataProcessorCutSelectedCommand(self.data_processor_table),
+                            self.menuEdit)
+        self._create_action(MantidQt.MantidWidgets.DataProcessorPasteSelectedCommand(self.data_processor_table),
+                            self.menuEdit)
+        self._create_action(MantidQt.MantidWidgets.DataProcessorClearSelectedCommand(self.data_processor_table),
+                            self.menuEdit)
+        self._create_action(MantidQt.MantidWidgets.DataProcessorDeleteRowCommand(self.data_processor_table),
+                            self.menuEdit)
+
+        # Actions that go in the 'File' menu
+        self._create_action(MantidQt.MantidWidgets.DataProcessorOpenTableCommand(self.data_processor_table),
+                            self.menuFile, workspace_list)
+        self._create_action(MantidQt.MantidWidgets.DataProcessorNewTableCommand(self.data_processor_table),
+                            self.menuFile)
+        self._create_action(MantidQt.MantidWidgets.DataProcessorSaveTableCommand(self.data_processor_table),
+                            self.menuFile)
+        self._create_action(MantidQt.MantidWidgets.DataProcessorSaveTableAsCommand(self.data_processor_table),
+                            self.menuFile)
+        self._create_action(MantidQt.MantidWidgets.DataProcessorImportTableCommand(self.data_processor_table),
+                            self.menuFile)
+        self._create_action(MantidQt.MantidWidgets.DataProcessorExportTableCommand(self.data_processor_table),
+                            self.menuFile)
+        self._create_action(MantidQt.MantidWidgets.DataProcessorOptionsCommand(self.data_processor_table),
+                            self.menuFile)
+
+    def _create_action(self, command, menu, workspace_list=None):
+        """
+        Create an action from a given DataProcessorCommand and add it to a given menu
+        A 'workspace_list' can be provided but it is only intended to be used with DataProcessorOpenTableCommand.
+        It refers to the list of table workspaces in the ADS that could be loaded into the widget. Note that only
+        table workspaces with an appropriate number of columns and column types can be loaded.
+        """
+        if (workspace_list is not None and command.name() == "Open Table"):
+            submenu = QtGui.QMenu(command.name(), self)
+            submenu.setIcon(QtGui.QIcon(command.icon()))
+
+            for ws in workspace_list:
+                ws_command = MantidQt.MantidWidgets.DataProcessorWorkspaceCommand(self.data_processor_table, ws)
+                action = QtGui.QAction(QtGui.QIcon(ws_command.icon()), ws_command.name(), self)
+                action.triggered.connect(lambda: self._connect_action(ws_command))
+                submenu.addAction(action)
+
+            menu.addMenu(submenu)
+        else:
+            action = QtGui.QAction(QtGui.QIcon(command.icon()), command.name(), self)
+            action.setShortcut(command.shortcut())
+            action.setStatusTip(command.tooltip())
+            action.triggered.connect(lambda: self._connect_action(command))
+            menu.addAction(action)
+
+    def _connect_action(self, command):
+        """
+        Executes an action
+        """
+        command.execute()
+
+    def _run_python_code(self, text):
+        """
+        Re-emits 'runPytonScript' signal
+        """
+        mantidplot.runPythonScript(text, True)
diff --git a/scripts/Interface/ui/sans_isis/sans_data_processor_window.ui b/scripts/Interface/ui/sans_isis/sans_data_processor_window.ui
new file mode 100755
index 0000000000000000000000000000000000000000..ee6e6a7c230d8f38de35b6389be8985805f472f0
--- /dev/null
+++ b/scripts/Interface/ui/sans_isis/sans_data_processor_window.ui
@@ -0,0 +1,1925 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SansDataProcessorWindow</class>
+ <widget class="QMainWindow" name="SansDataProcessorWindow">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>1072</width>
+    <height>897</height>
+   </rect>
+  </property>
+  <property name="acceptDrops">
+   <bool>true</bool>
+  </property>
+  <property name="windowTitle">
+   <string>ISIS SANS Reduction GUI</string>
+  </property>
+  <property name="styleSheet">
+   <string notr="true">
+
+QGroupBox {
+    border: 1px solid gray;
+    border-radius: 9px;
+    margin-top: 0.5em;
+}
+
+QGroupBox::title {
+    subcontrol-origin: margin;
+    left: 10px;
+    padding: 0 3px 0 3px;
+}</string>
+  </property>
+  <widget class="QWidget" name="widgetMainRow">
+   <layout class="QVBoxLayout" name="outer_layout">
+    <item>
+     <layout class="QHBoxLayout" name="main_layout">
+      <item>
+       <layout class="QVBoxLayout" name="tab_choice_layout">
+        <item>
+         <widget class="QListWidget" name="tab_choice_list">
+          <property name="sizePolicy">
+           <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="maximumSize">
+           <size>
+            <width>140</width>
+            <height>16777215</height>
+           </size>
+          </property>
+          <property name="frameShape">
+           <enum>QFrame::Box</enum>
+          </property>
+          <property name="frameShadow">
+           <enum>QFrame::Raised</enum>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </item>
+      <item>
+       <widget class="QStackedWidget" name="main_stacked_widget">
+        <property name="currentIndex">
+         <number>0</number>
+        </property>
+        <widget class="QWidget" name="run_page">
+         <layout class="QVBoxLayout" name="verticalLayout_3">
+          <item>
+           <layout class="QVBoxLayout" name="run_layout">
+            <item>
+             <layout class="QGridLayout" name="header">
+              <item row="1" column="1">
+               <widget class="QLabel" name="user_file_label">
+                <property name="toolTip">
+                 <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Specify the user file (aka mask file) which is used to provide the bulk of the reduction settings. For a list of user file commands see &lt;a href=&quot;https://www.mantidproject.org/SANS_User_File_Commands&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;here&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                </property>
+                <property name="frameShape">
+                 <enum>QFrame::NoFrame</enum>
+                </property>
+                <property name="text">
+                 <string>&amp;User File:</string>
+                </property>
+                <property name="buddy">
+                 <cstring>masking_table</cstring>
+                </property>
+               </widget>
+              </item>
+              <item row="2" column="3">
+               <widget class="QPushButton" name="batch_button">
+                <property name="toolTip">
+                 <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Specify a batch file to load. For the batch file format see &lt;a href=&quot;https://www.mantidproject.org/SANS_batch_file_format&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;here&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                </property>
+                <property name="text">
+                 <string>Load Batch File</string>
+                </property>
+               </widget>
+              </item>
+              <item row="1" column="3">
+               <widget class="QPushButton" name="user_file_button">
+                <property name="toolTip">
+                 <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Specify the user file (aka mask file) which is used to provide the bulk of the reduction settings. For a list of user file commands see &lt;a href=&quot;https://www.mantidproject.org/SANS_User_File_Commands&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;here&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                </property>
+                <property name="text">
+                 <string>Load User File</string>
+                </property>
+               </widget>
+              </item>
+              <item row="2" column="2">
+               <widget class="QLineEdit" name="batch_line_edit">
+                <property name="toolTip">
+                 <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Specify a batch file to load. For the batch file format see &lt;a href=&quot;https://www.mantidproject.org/SANS_batch_file_format&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;here&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                </property>
+               </widget>
+              </item>
+              <item row="2" column="1">
+               <widget class="QLabel" name="batch_label">
+                <property name="toolTip">
+                 <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Specify a batch file to load. For the batch file format see &lt;a href=&quot;https://www.mantidproject.org/SANS_batch_file_format&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;here&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                </property>
+                <property name="text">
+                 <string>Batch File:</string>
+                </property>
+               </widget>
+              </item>
+              <item row="1" column="2">
+               <widget class="QLineEdit" name="user_file_line_edit">
+                <property name="toolTip">
+                 <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Specify the user file (aka mask file) which is used to provide the bulk of the reduction settings. For a list of user file commands see &lt;a href=&quot;https://www.mantidproject.org/SANS_User_File_Commands&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;here&lt;/span&gt;&lt;/a&gt;.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                </property>
+               </widget>
+              </item>
+             </layout>
+            </item>
+            <item>
+             <layout class="QVBoxLayout" name="data_processor_widget_layout"/>
+            </item>
+            <item>
+             <layout class="QHBoxLayout" name="save_layout_2">
+              <item>
+               <spacer name="horizontalSpacer_2">
+                <property name="orientation">
+                 <enum>Qt::Horizontal</enum>
+                </property>
+                <property name="sizeHint" stdset="0">
+                 <size>
+                  <width>40</width>
+                  <height>20</height>
+                 </size>
+                </property>
+               </spacer>
+              </item>
+              <item>
+               <widget class="QGroupBox" name="save_group_box">
+                <property name="styleSheet">
+                 <string notr="true"/>
+                </property>
+                <property name="title">
+                 <string>Save Options</string>
+                </property>
+                <property name="flat">
+                 <bool>false</bool>
+                </property>
+                <layout class="QHBoxLayout" name="horizontalLayout_4">
+                 <item>
+                  <layout class="QHBoxLayout" name="save_layout">
+                   <item>
+                    <layout class="QVBoxLayout" name="save_location_layout">
+                     <item>
+                      <widget class="QRadioButton" name="output_mode_memory_radio_button">
+                       <property name="toolTip">
+                        <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The save locations for the output of batch reductions are: Memory (RAM), File (Hard disk), Both (RAM and Hard disk).&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                       </property>
+                       <property name="text">
+                        <string>Memor&amp;y</string>
+                       </property>
+                       <property name="checked">
+                        <bool>true</bool>
+                       </property>
+                      </widget>
+                     </item>
+                     <item>
+                      <widget class="QRadioButton" name="output_mode_file_radio_button">
+                       <property name="toolTip">
+                        <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The save locations for the output of batch reductions are: Memory (RAM), File (Hard disk), Both (RAM and Hard disk).&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                       </property>
+                       <property name="text">
+                        <string>&amp;File</string>
+                       </property>
+                      </widget>
+                     </item>
+                     <item>
+                      <widget class="QRadioButton" name="output_mode_both_radio_button">
+                       <property name="toolTip">
+                        <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The save locations for the output of batch reductions are: Memory (RAM), File (Hard disk), Both (RAM and Hard disk).&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                       </property>
+                       <property name="text">
+                        <string>Both</string>
+                       </property>
+                      </widget>
+                     </item>
+                    </layout>
+                   </item>
+                   <item>
+                    <widget class="Line" name="line">
+                     <property name="orientation">
+                      <enum>Qt::Vertical</enum>
+                     </property>
+                    </widget>
+                   </item>
+                   <item>
+                    <layout class="QVBoxLayout" name="save_file_format_layout">
+                     <item>
+                      <widget class="QCheckBox" name="can_sas_checkbox">
+                       <property name="toolTip">
+                        <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The save file formats. Note that different formats are suitable for different reduction dimensionalities.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                       </property>
+                       <property name="text">
+                        <string>CanSAS (1D)</string>
+                       </property>
+                      </widget>
+                     </item>
+                     <item>
+                      <widget class="QCheckBox" name="nx_can_sas_checkbox">
+                       <property name="toolTip">
+                        <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The save file formats. Note that different formats are suitable for different reduction dimensionalities.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                       </property>
+                       <property name="text">
+                        <string>NxCanSAS (1D/2D)</string>
+                       </property>
+                       <property name="checked">
+                        <bool>true</bool>
+                       </property>
+                      </widget>
+                     </item>
+                     <item>
+                      <widget class="QCheckBox" name="rkh_checkbox">
+                       <property name="toolTip">
+                        <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The save file formats. Note that different formats are suitable for different reduction dimensionalities.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                       </property>
+                       <property name="text">
+                        <string>RKH (1D/2D)</string>
+                       </property>
+                      </widget>
+                     </item>
+                     <item>
+                      <widget class="QCheckBox" name="nist_qxy_checkbox">
+                       <property name="toolTip">
+                        <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The save file formats. Note that different formats are suitable for different reduction dimensionalities.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                       </property>
+                       <property name="text">
+                        <string>Nist Qxy (2D)</string>
+                       </property>
+                      </widget>
+                     </item>
+                    </layout>
+                   </item>
+                   <item>
+                    <widget class="Line" name="line_2">
+                     <property name="orientation">
+                      <enum>Qt::Vertical</enum>
+                     </property>
+                    </widget>
+                   </item>
+                   <item>
+                    <layout class="QGridLayout" name="gridLayout">
+                     <item row="0" column="0">
+                      <widget class="QCheckBox" name="save_zero_error_free">
+                       <property name="toolTip">
+                        <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;When enabled it will replace all entries with zero-valued errors with errors of magnitude 1e6. &lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                       </property>
+                       <property name="text">
+                        <string>zero error free</string>
+                       </property>
+                       <property name="checked">
+                        <bool>true</bool>
+                       </property>
+                      </widget>
+                     </item>
+                     <item row="1" column="0">
+                      <widget class="QCheckBox" name="use_optimizations_checkbox">
+                       <property name="toolTip">
+                        <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;When optimizations are turned on then data is being stored in RAM and reused. The optimizations affect the raw data files and can reductions. Most of the time you will want these optimizations enabled. Disable the optimizations if you run a very long batch reduction where there might be the danger  that your RAM will max out.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                       </property>
+                       <property name="text">
+                        <string>Use Optimizations</string>
+                       </property>
+                       <property name="checked">
+                        <bool>true</bool>
+                       </property>
+                      </widget>
+                     </item>
+                    </layout>
+                   </item>
+                  </layout>
+                 </item>
+                </layout>
+               </widget>
+              </item>
+             </layout>
+            </item>
+           </layout>
+          </item>
+         </layout>
+        </widget>
+        <widget class="QWidget" name="settings_page">
+         <layout class="QHBoxLayout" name="horizontalLayout">
+          <item>
+           <widget class="QTabWidget" name="settings_tab_widget">
+            <property name="currentIndex">
+             <number>0</number>
+            </property>
+            <widget class="QWidget" name="general_tab">
+             <attribute name="title">
+              <string>General, Wavelength, Scale, Event Slice, Sample</string>
+             </attribute>
+             <layout class="QHBoxLayout" name="horizontalLayout_3">
+              <item>
+               <layout class="QHBoxLayout" name="general_tab_horizontal_layout">
+                <item>
+                 <layout class="QVBoxLayout" name="general_tab_left_layout">
+                  <item>
+                   <widget class="QGroupBox" name="general_group_box">
+                    <property name="title">
+                     <string>General</string>
+                    </property>
+                    <layout class="QVBoxLayout" name="verticalLayout_5">
+                     <item>
+                      <layout class="QVBoxLayout" name="general_vertical_layout">
+                       <item>
+                        <layout class="QGridLayout" name="general_grid">
+                         <item row="0" column="1">
+                          <layout class="QHBoxLayout" name="reduction_dimensioality_horizontal_layout">
+                           <item>
+                            <widget class="QRadioButton" name="reduction_dimensionality_1D">
+                             <property name="toolTip">
+                              <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The reduction dimensionality.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                             </property>
+                             <property name="text">
+                              <string>&amp;1D</string>
+                             </property>
+                             <property name="checked">
+                              <bool>true</bool>
+                             </property>
+                            </widget>
+                           </item>
+                           <item>
+                            <widget class="QRadioButton" name="reduction_dimensionality_2D">
+                             <property name="toolTip">
+                              <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The reduction dimensionality.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                             </property>
+                             <property name="text">
+                              <string>&amp;2D</string>
+                             </property>
+                            </widget>
+                           </item>
+                           <item>
+                            <spacer name="reduction_mode_spacer">
+                             <property name="orientation">
+                              <enum>Qt::Horizontal</enum>
+                             </property>
+                             <property name="sizeHint" stdset="0">
+                              <size>
+                               <width>40</width>
+                               <height>20</height>
+                              </size>
+                             </property>
+                            </spacer>
+                           </item>
+                          </layout>
+                         </item>
+                         <item row="1" column="0">
+                          <widget class="QLabel" name="reduction_mode_label">
+                           <property name="toolTip">
+                            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The reduction mode. This can be either of the banks of your instrument. In the case of two banks there is also the &lt;span style=&quot; font-style:italic;&quot;&gt;Merged&lt;/span&gt; and &lt;span style=&quot; font-style:italic;&quot;&gt;All&lt;/span&gt; mode. &lt;span style=&quot; font-style:italic;&quot;&gt;Merged&lt;/span&gt; mode stitches the reductions from two banks together. &lt;span style=&quot; font-style:italic;&quot;&gt;All&lt;/span&gt; mode reduces both banks.&lt;/p&gt;&lt;p&gt;Note that by default the entries are &lt;span style=&quot; font-style:italic;&quot;&gt;LAB&lt;/span&gt;, &lt;span style=&quot; font-style:italic;&quot;&gt;HAB&lt;/span&gt;, &lt;span style=&quot; font-style:italic;&quot;&gt;Merged&lt;/span&gt;, &lt;span style=&quot; font-style:italic;&quot;&gt;All&lt;/span&gt;. Once you have specifed data in the batch table, the entry names will be updated to reflect the naming of your instrument.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                           </property>
+                           <property name="text">
+                            <string>Reduction Mode</string>
+                           </property>
+                          </widget>
+                         </item>
+                         <item row="0" column="0">
+                          <widget class="QLabel" name="reduction_dimensionality_label">
+                           <property name="toolTip">
+                            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The reduction dimensionality.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                           </property>
+                           <property name="text">
+                            <string>Reduction Dimensionality</string>
+                           </property>
+                          </widget>
+                         </item>
+                         <item row="1" column="1">
+                          <widget class="QComboBox" name="reduction_mode_combo_box">
+                           <property name="toolTip">
+                            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The reduction mode. This can be either of the banks of your instrument. In the case of two banks there is also the &lt;span style=&quot; font-style:italic;&quot;&gt;Merged&lt;/span&gt; and &lt;span style=&quot; font-style:italic;&quot;&gt;All&lt;/span&gt; mode. &lt;span style=&quot; font-style:italic;&quot;&gt;Merged&lt;/span&gt; mode stitches the reductions from two banks together. &lt;span style=&quot; font-style:italic;&quot;&gt;All&lt;/span&gt; mode reduces both banks.&lt;/p&gt;&lt;p&gt;Note that by default the entries are &lt;span style=&quot; font-style:italic;&quot;&gt;LAB&lt;/span&gt;, &lt;span style=&quot; font-style:italic;&quot;&gt;HAB&lt;/span&gt;, &lt;span style=&quot; font-style:italic;&quot;&gt;Merged&lt;/span&gt;, &lt;span style=&quot; font-style:italic;&quot;&gt;All&lt;/span&gt;. Once you have specifed data in the batch table, the entry names will be updated to reflect the naming of your instrument.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                           </property>
+                          </widget>
+                         </item>
+                        </layout>
+                       </item>
+                      </layout>
+                     </item>
+                     <item>
+                      <widget class="QGroupBox" name="merged_settings">
+                       <property name="toolTip">
+                        <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Settings for a merged reduction.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                       </property>
+                       <property name="title">
+                        <string>Merged Settings</string>
+                       </property>
+                       <layout class="QGridLayout" name="gridLayout_12">
+                        <item row="1" column="0">
+                         <widget class="QLineEdit" name="merged_scale_line_edit">
+                          <property name="toolTip">
+                           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Scale which is used when merging two workspaces.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                          </property>
+                         </widget>
+                        </item>
+                        <item row="0" column="0">
+                         <widget class="QLabel" name="merged_scale_label">
+                          <property name="text">
+                           <string>Scale</string>
+                          </property>
+                         </widget>
+                        </item>
+                        <item row="0" column="1">
+                         <widget class="QLabel" name="merged_shift_label">
+                          <property name="text">
+                           <string>Shift</string>
+                          </property>
+                         </widget>
+                        </item>
+                        <item row="1" column="1">
+                         <widget class="QLineEdit" name="merged_shift_line_edit">
+                          <property name="toolTip">
+                           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Shift which is used when merging two workspaces.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                          </property>
+                         </widget>
+                        </item>
+                        <item row="1" column="4">
+                         <widget class="QLineEdit" name="merged_q_range_start_line_edit">
+                          <property name="toolTip">
+                           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Lower bound  of a custom q range. If none is specified, then the full range is used.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                          </property>
+                         </widget>
+                        </item>
+                        <item row="1" column="6">
+                         <widget class="QLineEdit" name="merged_q_range_stop_line_edit">
+                          <property name="toolTip">
+                           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Upper bound  of a custom q range. If none is specified, then the full range is used.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                          </property>
+                         </widget>
+                        </item>
+                        <item row="2" column="2">
+                         <widget class="Line" name="line_5">
+                          <property name="orientation">
+                           <enum>Qt::Vertical</enum>
+                          </property>
+                         </widget>
+                        </item>
+                        <item row="0" column="2">
+                         <widget class="Line" name="line_3">
+                          <property name="orientation">
+                           <enum>Qt::Vertical</enum>
+                          </property>
+                         </widget>
+                        </item>
+                        <item row="1" column="2">
+                         <widget class="Line" name="line_4">
+                          <property name="orientation">
+                           <enum>Qt::Vertical</enum>
+                          </property>
+                         </widget>
+                        </item>
+                        <item row="2" column="0">
+                         <widget class="QCheckBox" name="merged_scale_use_fit_check_box">
+                          <property name="toolTip">
+                           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;If checked hten the scale will be fit during the merge operation.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                          </property>
+                          <property name="text">
+                           <string>Use Fit</string>
+                          </property>
+                         </widget>
+                        </item>
+                        <item row="2" column="1">
+                         <widget class="QCheckBox" name="merged_shift_use_fit_check_box">
+                          <property name="toolTip">
+                           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;If checked hten the shift will be fit during the merge operation.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                          </property>
+                          <property name="text">
+                           <string>Use Fit</string>
+                          </property>
+                         </widget>
+                        </item>
+                        <item row="1" column="3">
+                         <widget class="QLabel" name="label_3">
+                          <property name="text">
+                           <string>from</string>
+                          </property>
+                         </widget>
+                        </item>
+                        <item row="1" column="5">
+                         <widget class="QLabel" name="label_4">
+                          <property name="text">
+                           <string>to</string>
+                          </property>
+                         </widget>
+                        </item>
+                        <item row="0" column="3" colspan="2">
+                         <widget class="QLabel" name="label">
+                          <property name="text">
+                           <string>Custom q range:</string>
+                          </property>
+                         </widget>
+                        </item>
+                       </layout>
+                      </widget>
+                     </item>
+                    </layout>
+                   </widget>
+                  </item>
+                  <item>
+                   <widget class="QGroupBox" name="slice_event_group_box">
+                    <property name="toolTip">
+                     <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;In the case of data which was measured in event-mode, it is possible to perform time-of-flight slices of the data and reduce these separately.&lt;/p&gt;&lt;p&gt;Input can be:&lt;/p&gt;&lt;p&gt;-&lt;span style=&quot; font-style:italic;&quot;&gt; start:step:stop&lt;/span&gt; specifies time slices from the &lt;span style=&quot; font-style:italic;&quot;&gt;start&lt;/span&gt; value to the &lt;span style=&quot; font-style:italic;&quot;&gt;stop &lt;/span&gt;value in steps of &lt;span style=&quot; font-style:italic;&quot;&gt;step&lt;/span&gt;&lt;/p&gt;&lt;p&gt;- &lt;span style=&quot; font-style:italic;&quot;&gt;start-stop &lt;/span&gt;which specifies a time slice from the &lt;span style=&quot; font-style:italic;&quot;&gt;start&lt;/span&gt; value to the &lt;span style=&quot; font-style:italic;&quot;&gt;stop&lt;/span&gt; value&lt;/p&gt;&lt;p&gt;- &lt;span style=&quot; font-style:italic;&quot;&gt;&amp;gt;start&lt;/span&gt; specifies a slice from the &lt;span style=&quot; font-style:italic;&quot;&gt;start &lt;/span&gt;value to the end of the data set&lt;/p&gt;&lt;p&gt;- &lt;span style=&quot; font-style:italic;&quot;&gt;&amp;lt;stop&lt;/span&gt; specifes a slcie from teh start of the data set to the &lt;span style=&quot; font-style:italic;&quot;&gt;stop &lt;/span&gt;value&lt;/p&gt;&lt;p&gt;In addition it is possible to concatenate these specifications useing comma-separation. An example is:&lt;/p&gt;&lt;p&gt;&lt;span style=&quot; font-style:italic;&quot;&gt;5-10,12:2:16,20-30&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                    </property>
+                    <property name="title">
+                     <string>Event Slice</string>
+                    </property>
+                    <layout class="QGridLayout" name="gridLayout_2">
+                     <item row="0" column="0">
+                      <layout class="QGridLayout" name="slice_event_grid_layout">
+                       <item row="0" column="0">
+                        <widget class="QLabel" name="slice_event_label">
+                         <property name="text">
+                          <string>Slices</string>
+                         </property>
+                        </widget>
+                       </item>
+                       <item row="0" column="1">
+                        <widget class="QLineEdit" name="slice_event_line_edit"/>
+                       </item>
+                      </layout>
+                     </item>
+                    </layout>
+                   </widget>
+                  </item>
+                  <item>
+                   <widget class="QGroupBox" name="event_binning_group_box">
+                    <property name="toolTip">
+                     <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;When checked, the data reduction will run in the compatibility mode. This means that the reduction workflow is equivalent to the previous legacy reduction workflow. Most of the time you don't want to have this checked as the unchecked state will provide more precise results.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                    </property>
+                    <property name="title">
+                     <string>&amp;Use compatibility mode</string>
+                    </property>
+                    <property name="checkable">
+                     <bool>true</bool>
+                    </property>
+                    <property name="checked">
+                     <bool>false</bool>
+                    </property>
+                    <layout class="QGridLayout" name="gridLayout_16">
+                     <item row="0" column="0">
+                      <widget class="QLabel" name="event_binning_label">
+                       <property name="toolTip">
+                        <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Rebin string for the initial time-of-flight workspace. This is only needed when using the compaptibility mode (ie when following the old reduction model). Note that this will only have an effect on event workspaces.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                       </property>
+                       <property name="text">
+                        <string>Event binning</string>
+                       </property>
+                      </widget>
+                     </item>
+                     <item row="0" column="1">
+                      <widget class="QLineEdit" name="event_binning_line_edit">
+                       <property name="toolTip">
+                        <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Rebin string for the initial time-of-flight workspace. This is only needed when using the compaptibility mode (ie when following the old reduction model). Note that this will only have an effect on event workspaces.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                       </property>
+                      </widget>
+                     </item>
+                    </layout>
+                   </widget>
+                  </item>
+                  <item>
+                   <widget class="QGroupBox" name="groupBox">
+                    <property name="toolTip">
+                     <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Settings concerning the wavelength binning when dat a is transformed from time-of-flight to wavlength units.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                    </property>
+                    <property name="title">
+                     <string>Wavelength</string>
+                    </property>
+                    <layout class="QGridLayout" name="gridLayout_6">
+                     <item row="1" column="0">
+                      <layout class="QGridLayout" name="gridLayout_3">
+                       <item row="0" column="2">
+                        <widget class="QLabel" name="wavelength_step_label">
+                         <property name="text">
+                          <string>Step  [Ã…]</string>
+                         </property>
+                        </widget>
+                       </item>
+                       <item row="0" column="1">
+                        <widget class="QLabel" name="wavelength_max_label">
+                         <property name="text">
+                          <string>Max  [Ã…]</string>
+                         </property>
+                        </widget>
+                       </item>
+                       <item row="1" column="3">
+                        <widget class="QComboBox" name="wavelength_step_type_combo_box"/>
+                       </item>
+                       <item row="0" column="0">
+                        <widget class="QLabel" name="wavelength_min_label">
+                         <property name="text">
+                          <string>Min [Ã…]</string>
+                         </property>
+                        </widget>
+                       </item>
+                       <item row="0" column="3">
+                        <widget class="QLabel" name="wavelength_step_type_label">
+                         <property name="text">
+                          <string>Step Type</string>
+                         </property>
+                        </widget>
+                       </item>
+                       <item row="1" column="2">
+                        <widget class="QLineEdit" name="wavelength_step_line_edit"/>
+                       </item>
+                       <item row="1" column="1">
+                        <widget class="QLineEdit" name="wavelength_max_line_edit"/>
+                       </item>
+                       <item row="1" column="0">
+                        <widget class="QLineEdit" name="wavelength_min_line_edit"/>
+                       </item>
+                      </layout>
+                     </item>
+                    </layout>
+                   </widget>
+                  </item>
+                  <item>
+                   <layout class="QGridLayout" name="scale_group_box">
+                    <item row="0" column="0">
+                     <widget class="QGroupBox" name="scale_layout">
+                      <property name="toolTip">
+                       <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Settings for the absolute scale and the sample geometry and position.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                      </property>
+                      <property name="title">
+                       <string>Scale and Sample</string>
+                      </property>
+                      <layout class="QGridLayout" name="gridLayout_5">
+                       <item row="0" column="0">
+                        <layout class="QGridLayout" name="gridLayout_4">
+                         <item row="3" column="0">
+                          <widget class="QLabel" name="width_label">
+                           <property name="toolTip">
+                            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The width of the sample. If this input is left empty, then the value stored in the metadata of the file is used.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                           </property>
+                           <property name="text">
+                            <string>Width [mm]</string>
+                           </property>
+                          </widget>
+                         </item>
+                         <item row="2" column="0">
+                          <widget class="QLabel" name="height_label">
+                           <property name="toolTip">
+                            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The height of the sample. If this input is left empty, then the value stored in the metadata of the file is used.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                           </property>
+                           <property name="text">
+                            <string>Height [mm]</string>
+                           </property>
+                          </widget>
+                         </item>
+                         <item row="4" column="0">
+                          <widget class="QLabel" name="thickness_label">
+                           <property name="toolTip">
+                            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The thickness of the sample. If this input is left empty, then the value stored in the metadata of the file is used.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                           </property>
+                           <property name="text">
+                            <string>Thickness [mm]</string>
+                           </property>
+                          </widget>
+                         </item>
+                         <item row="1" column="0">
+                          <widget class="QLabel" name="geometry_label">
+                           <property name="toolTip">
+                            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The geometry of the sample. If this is left at &lt;span style=&quot; font-style:italic;&quot;&gt;Read from file &lt;/span&gt;then the value stored in the metadata of the file is used.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                           </property>
+                           <property name="text">
+                            <string>Geometry</string>
+                           </property>
+                          </widget>
+                         </item>
+                         <item row="0" column="0">
+                          <widget class="QLabel" name="absolute_scale_label">
+                           <property name="toolTip">
+                            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The absolute (and unitless) scale factor for the data reduction.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                           </property>
+                           <property name="text">
+                            <string>Absolute Scale</string>
+                           </property>
+                          </widget>
+                         </item>
+                         <item row="5" column="0">
+                          <widget class="QLabel" name="z_offset_label">
+                           <property name="toolTip">
+                            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The z offset of the sample position.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                           </property>
+                           <property name="text">
+                            <string>Z Offset</string>
+                           </property>
+                          </widget>
+                         </item>
+                         <item row="0" column="1">
+                          <widget class="QLineEdit" name="absolute_scale_line_edit">
+                           <property name="toolTip">
+                            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The absolute (and unitless) scale factor for the data reduction.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                           </property>
+                          </widget>
+                         </item>
+                         <item row="2" column="1">
+                          <widget class="QLineEdit" name="height_line_edit">
+                           <property name="toolTip">
+                            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The height of the sample. If this input is left empty, then the value stored in the metadata of the file is used.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                           </property>
+                          </widget>
+                         </item>
+                         <item row="3" column="1">
+                          <widget class="QLineEdit" name="width_line_edit">
+                           <property name="toolTip">
+                            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The width of the sample. If this input is left empty, then the value stored in the metadata of the file is used.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                           </property>
+                          </widget>
+                         </item>
+                         <item row="4" column="1">
+                          <widget class="QLineEdit" name="thickness_line_edit">
+                           <property name="toolTip">
+                            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The thickness of the sample. If this input is left empty, then the value stored in the metadata of the file is used.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                           </property>
+                          </widget>
+                         </item>
+                         <item row="1" column="1">
+                          <widget class="QComboBox" name="geometry_combo_box">
+                           <property name="toolTip">
+                            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The geometry of the sample. If this is left at &lt;span style=&quot; font-style:italic;&quot;&gt;Read from file &lt;/span&gt;then the value stored in the metadata of the file is used.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                           </property>
+                          </widget>
+                         </item>
+                         <item row="5" column="1">
+                          <widget class="QLineEdit" name="z_offset_line_edit">
+                           <property name="toolTip">
+                            <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The z offset of the sample position.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                           </property>
+                          </widget>
+                         </item>
+                        </layout>
+                       </item>
+                      </layout>
+                     </widget>
+                    </item>
+                   </layout>
+                  </item>
+                  <item>
+                   <spacer name="verticalSpacer_3">
+                    <property name="orientation">
+                     <enum>Qt::Vertical</enum>
+                    </property>
+                    <property name="sizeHint" stdset="0">
+                     <size>
+                      <width>20</width>
+                      <height>40</height>
+                     </size>
+                    </property>
+                   </spacer>
+                  </item>
+                 </layout>
+                </item>
+                <item>
+                 <layout class="QVBoxLayout" name="general_tab_right_layout"/>
+                </item>
+               </layout>
+              </item>
+             </layout>
+            </widget>
+            <widget class="QWidget" name="mask_tab">
+             <attribute name="title">
+              <string>Mask</string>
+             </attribute>
+             <layout class="QHBoxLayout" name="horizontalLayout_7">
+              <item>
+               <widget class="MaskingTable" name="masking_table" native="true">
+                <property name="minimumSize">
+                 <size>
+                  <width>400</width>
+                  <height>0</height>
+                 </size>
+                </property>
+               </widget>
+              </item>
+              <item>
+               <layout class="QVBoxLayout" name="mask_tab_right_layout">
+                <item>
+                 <widget class="QGroupBox" name="phi_limit_group_box">
+                  <property name="toolTip">
+                   <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Allows for selecting pizza slice masks.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                  </property>
+                  <property name="title">
+                   <string>Phi limit</string>
+                  </property>
+                  <layout class="QGridLayout" name="gridLayout_18">
+                   <item row="0" column="3">
+                    <widget class="QLabel" name="phi_limit_to_label">
+                     <property name="text">
+                      <string>to</string>
+                     </property>
+                    </widget>
+                   </item>
+                   <item row="0" column="4">
+                    <widget class="QLineEdit" name="phi_limit_max_line_edit">
+                     <property name="toolTip">
+                      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Stop angle in degree&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                     </property>
+                    </widget>
+                   </item>
+                   <item row="0" column="0">
+                    <widget class="QLabel" name="phi_limit_from_label">
+                     <property name="text">
+                      <string>from</string>
+                     </property>
+                    </widget>
+                   </item>
+                   <item row="0" column="1">
+                    <widget class="QLineEdit" name="phi_limit_min_line_edit">
+                     <property name="toolTip">
+                      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Start angle in degree&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                     </property>
+                    </widget>
+                   </item>
+                   <item row="0" column="5">
+                    <widget class="QCheckBox" name="phi_limit_use_mirror_check_box">
+                     <property name="toolTip">
+                      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;If the mirror sector should be used.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                     </property>
+                     <property name="text">
+                      <string>use mirror sector</string>
+                     </property>
+                    </widget>
+                   </item>
+                  </layout>
+                 </widget>
+                </item>
+                <item>
+                 <widget class="QGroupBox" name="radius_limit_group_box">
+                  <property name="toolTip">
+                   <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Disk mask which is useful for the beam stop&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                  </property>
+                  <property name="title">
+                   <string>Radius limit</string>
+                  </property>
+                  <layout class="QGridLayout" name="gridLayout_19">
+                   <item row="1" column="1">
+                    <widget class="QLineEdit" name="radius_limit_min_line_edit">
+                     <property name="toolTip">
+                      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Lower radius setting in mm.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                     </property>
+                    </widget>
+                   </item>
+                   <item row="1" column="0">
+                    <widget class="QLabel" name="phi_limit">
+                     <property name="text">
+                      <string>Radius</string>
+                     </property>
+                    </widget>
+                   </item>
+                   <item row="1" column="2">
+                    <widget class="QLineEdit" name="radius_limit_max_line_edit">
+                     <property name="toolTip">
+                      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Upper radius setting in mm.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                     </property>
+                    </widget>
+                   </item>
+                   <item row="0" column="1">
+                    <widget class="QLabel" name="radius_limit_min_label">
+                     <property name="text">
+                      <string>Min [mm]</string>
+                     </property>
+                    </widget>
+                   </item>
+                   <item row="0" column="2">
+                    <widget class="QLabel" name="radius_limit_max_label">
+                     <property name="text">
+                      <string>Max [mm]</string>
+                     </property>
+                    </widget>
+                   </item>
+                  </layout>
+                 </widget>
+                </item>
+                <item>
+                 <spacer name="verticalSpacer_4">
+                  <property name="orientation">
+                   <enum>Qt::Vertical</enum>
+                  </property>
+                  <property name="sizeHint" stdset="0">
+                   <size>
+                    <width>20</width>
+                    <height>40</height>
+                   </size>
+                  </property>
+                 </spacer>
+                </item>
+               </layout>
+              </item>
+             </layout>
+            </widget>
+            <widget class="QWidget" name="adjustment_tab">
+             <attribute name="title">
+              <string>Adjustment</string>
+             </attribute>
+             <layout class="QHBoxLayout" name="horizontalLayout_5">
+              <item>
+               <layout class="QHBoxLayout" name="adjustment_tab_horizontal_layout">
+                <item>
+                 <layout class="QVBoxLayout" name="adjustment_tab_left_layout">
+                  <item>
+                   <widget class="QGroupBox" name="monitor_normalization_group_box">
+                    <property name="toolTip">
+                     <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Settings for the monitor normalization.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                    </property>
+                    <property name="title">
+                     <string>Monitor Normalization</string>
+                    </property>
+                    <layout class="QGridLayout" name="gridLayout_8">
+                     <item row="0" column="0">
+                      <widget class="QLabel" name="monitor_normalization_monitor_label">
+                       <property name="toolTip">
+                        <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Spectrum number of the incident monitor which is used for monitor normalization.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                       </property>
+                       <property name="text">
+                        <string>Incidient monitor</string>
+                       </property>
+                      </widget>
+                     </item>
+                     <item row="0" column="2">
+                      <widget class="QCheckBox" name="monitor_normalization_interpolating_rebin_check_box">
+                       <property name="toolTip">
+                        <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Selects the type of rebin which is to be used during monitor normalization. If this is checked then a interpolating rebin operation is performed, else a standard rebin operation is used.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                       </property>
+                       <property name="text">
+                        <string>Use interpolating rebin</string>
+                       </property>
+                      </widget>
+                     </item>
+                     <item row="0" column="1">
+                      <widget class="QLineEdit" name="monitor_normalization_line_edit">
+                       <property name="toolTip">
+                        <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Spectrum number of the incident monitor which is used for monitor normalization.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                       </property>
+                      </widget>
+                     </item>
+                    </layout>
+                   </widget>
+                  </item>
+                  <item>
+                   <widget class="QGroupBox" name="transmission_group_box">
+                    <property name="toolTip">
+                     <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Settings for the transmission calculation.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                    </property>
+                    <property name="title">
+                     <string>Transmission</string>
+                    </property>
+                    <layout class="QGridLayout" name="gridLayout_9">
+                     <item row="7" column="3">
+                      <widget class="QPushButton" name="transmission_mask_files_push_button">
+                       <property name="text">
+                        <string>Browse</string>
+                       </property>
+                      </widget>
+                     </item>
+                     <item row="7" column="2">
+                      <widget class="QLineEdit" name="transmission_mask_files_line_edit">
+                       <property name="toolTip">
+                        <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;A comma-separated list of MASK files which define areas on the bank which are excluded from the transmission calculation.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                       </property>
+                      </widget>
+                     </item>
+                     <item row="6" column="2">
+                      <widget class="QLineEdit" name="transmission_roi_files_line_edit">
+                       <property name="toolTip">
+                        <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;A comma-separated list of ROI files which define areas on the bank which contribute to the transmission calculation.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                       </property>
+                      </widget>
+                     </item>
+                     <item row="5" column="2">
+                      <widget class="QLineEdit" name="transmission_radius_line_edit">
+                       <property name="toolTip">
+                        <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;A radius that defines a circle which includes all pixels on the bank which contribute to the transmission calculation.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                       </property>
+                      </widget>
+                     </item>
+                     <item row="7" column="0">
+                      <widget class="QLabel" name="transmission_mask_files_label">
+                       <property name="toolTip">
+                        <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;A comma-separated list of MASK files which define areas on the bank which are excluded from the transmission calculation.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                       </property>
+                       <property name="text">
+                        <string>Mask Files</string>
+                       </property>
+                      </widget>
+                     </item>
+                     <item row="1" column="2">
+                      <widget class="QComboBox" name="transmission_target_combo_box">
+                       <item>
+                        <property name="text">
+                         <string>Transmission monitor</string>
+                        </property>
+                       </item>
+                       <item>
+                        <property name="text">
+                         <string>Region of interest on bank</string>
+                        </property>
+                       </item>
+                      </widget>
+                     </item>
+                     <item row="6" column="0">
+                      <widget class="QLabel" name="transmission_roi_files_label">
+                       <property name="toolTip">
+                        <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;A comma-separated list of ROI files which define areas on the bank which contribute to the transmission calculation.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                       </property>
+                       <property name="text">
+                        <string>ROI Files</string>
+                       </property>
+                      </widget>
+                     </item>
+                     <item row="6" column="3">
+                      <widget class="QPushButton" name="transmission_roi_files_push_button">
+                       <property name="text">
+                        <string>Browse</string>
+                       </property>
+                      </widget>
+                     </item>
+                     <item row="5" column="0">
+                      <widget class="QLabel" name="transmission_radius_label">
+                       <property name="toolTip">
+                        <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;A radius that defines a circle which includes all pixels on the bank which contribute to the transmission calculation.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                       </property>
+                       <property name="text">
+                        <string>Radius[mm]</string>
+                       </property>
+                      </widget>
+                     </item>
+                     <item row="1" column="0">
+                      <widget class="QLabel" name="transmission_target_label">
+                       <property name="text">
+                        <string>Transmission target</string>
+                       </property>
+                      </widget>
+                     </item>
+                     <item row="0" column="0">
+                      <widget class="QLabel" name="transmission_incident_monitor_target">
+                       <property name="toolTip">
+                        <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Spectrum number of the incident monitor which is used for transmission calculation.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                       </property>
+                       <property name="text">
+                        <string>Incident monitor</string>
+                       </property>
+                      </widget>
+                     </item>
+                     <item row="0" column="3">
+                      <widget class="QCheckBox" name="transmission_interpolating_rebin_check_box">
+                       <property name="toolTip">
+                        <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Selects the type of rebin which is to be used during transmission calculation. If this is checked then a interpolating rebin operation is performed, else a standard rebin operation is used.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                       </property>
+                       <property name="text">
+                        <string>Use interpolating rebin</string>
+                       </property>
+                      </widget>
+                     </item>
+                     <item row="4" column="2">
+                      <widget class="QLineEdit" name="transmission_m4_shift_line_edit">
+                       <property name="toolTip">
+                        <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;An option shift of the M4 monitor.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                       </property>
+                      </widget>
+                     </item>
+                     <item row="0" column="2">
+                      <widget class="QLineEdit" name="transmission_line_edit">
+                       <property name="toolTip">
+                        <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Spectrum number of the incident monitor which is used for transmission calculation.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                       </property>
+                      </widget>
+                     </item>
+                     <item row="4" column="0">
+                      <widget class="QLabel" name="transmission_m4_shift_label">
+                       <property name="toolTip">
+                        <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;An option shift of the M4 monitor.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                       </property>
+                       <property name="text">
+                        <string>M4 Shift [m]</string>
+                       </property>
+                      </widget>
+                     </item>
+                     <item row="3" column="0">
+                      <widget class="QLabel" name="transmission_monitor_label">
+                       <property name="toolTip">
+                        <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Spectrum number of the transmission monitor which is used for transmission calculation.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                       </property>
+                       <property name="text">
+                        <string>Transmission monitor</string>
+                       </property>
+                      </widget>
+                     </item>
+                     <item row="3" column="2">
+                      <layout class="QGridLayout" name="gridLayout_14">
+                       <item row="1" column="0">
+                        <widget class="QRadioButton" name="transmission_m3_radio_button">
+                         <property name="toolTip">
+                          <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;If this is selected then the standard transmission monitor is used for transmission calculation.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                         </property>
+                         <property name="text">
+                          <string>M3</string>
+                         </property>
+                        </widget>
+                       </item>
+                       <item row="1" column="1">
+                        <widget class="QRadioButton" name="transmission_m4_radio_button">
+                         <property name="toolTip">
+                          <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;If this is selected then the M4 transmission monitor is used for transmission calculation. This is the monitor which is located just before the detector. The name of this monitor might be different for some instruments (e.g. in ZOOM it is M5).&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                         </property>
+                         <property name="text">
+                          <string>M4</string>
+                         </property>
+                        </widget>
+                       </item>
+                      </layout>
+                     </item>
+                     <item row="8" column="0" colspan="4">
+                      <widget class="QGroupBox" name="fit_combo_box">
+                       <property name="toolTip">
+                        <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Fit options for the transmission calculation. These can be either set for both the Sample and the Can run or separately.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                       </property>
+                       <property name="title">
+                        <string>Fit</string>
+                       </property>
+                       <layout class="QGridLayout" name="gridLayout_22">
+                        <item row="2" column="3">
+                         <widget class="QComboBox" name="fit_can_fit_type_combo_box">
+                          <property name="toolTip">
+                           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;If fitting should be used, then this allows for the selection of the fit type.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                          </property>
+                         </widget>
+                        </item>
+                        <item row="0" column="3">
+                         <widget class="QLabel" name="fit_fit_type_label">
+                          <property name="text">
+                           <string>Fit type</string>
+                          </property>
+                         </widget>
+                        </item>
+                        <item row="2" column="2">
+                         <widget class="QCheckBox" name="fit_can_use_fit_check_box">
+                          <property name="toolTip">
+                           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;If fitting should be used&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                          </property>
+                          <property name="text">
+                           <string>Use fit</string>
+                          </property>
+                         </widget>
+                        </item>
+                        <item row="1" column="1">
+                         <widget class="QLabel" name="fit_sample_label">
+                          <property name="text">
+                           <string>Sample              </string>
+                          </property>
+                         </widget>
+                        </item>
+                        <item row="2" column="1">
+                         <widget class="QLabel" name="fit_can_label">
+                          <property name="text">
+                           <string>Can</string>
+                          </property>
+                         </widget>
+                        </item>
+                        <item row="1" column="0">
+                         <widget class="QComboBox" name="fit_selection_combo_box">
+                          <property name="toolTip">
+                           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Selects if fit options should be the same (Both) for Sample and Can, or if the user should be able to set them separately (Separate).&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                          </property>
+                          <item>
+                           <property name="text">
+                            <string>Both</string>
+                           </property>
+                          </item>
+                          <item>
+                           <property name="text">
+                            <string>Separate</string>
+                           </property>
+                          </item>
+                         </widget>
+                        </item>
+                        <item row="2" column="5">
+                         <widget class="QGroupBox" name="fit_can_wavelength_combo_box">
+                          <property name="toolTip">
+                           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Allows for setting a custom wavelength range during fitting.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                          </property>
+                          <property name="title">
+                           <string>Use custom wavelength range [Ã…]</string>
+                          </property>
+                          <property name="checkable">
+                           <bool>true</bool>
+                          </property>
+                          <property name="checked">
+                           <bool>false</bool>
+                          </property>
+                          <layout class="QGridLayout" name="gridLayout_24">
+                           <item row="0" column="1">
+                            <widget class="QLineEdit" name="fit_can_wavelength_min_line_edit">
+                             <property name="toolTip">
+                              <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The beginning of the custom wavelength range.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                             </property>
+                            </widget>
+                           </item>
+                           <item row="0" column="0">
+                            <widget class="QLabel" name="fit_can_from_label">
+                             <property name="text">
+                              <string>from</string>
+                             </property>
+                            </widget>
+                           </item>
+                           <item row="0" column="2">
+                            <widget class="QLabel" name="fit_can_to_label">
+                             <property name="text">
+                              <string>to</string>
+                             </property>
+                            </widget>
+                           </item>
+                           <item row="0" column="3">
+                            <widget class="QLineEdit" name="fit_can_wavelength_max_line_edit">
+                             <property name="toolTip">
+                              <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The end of the custom wavelength range.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                             </property>
+                            </widget>
+                           </item>
+                          </layout>
+                         </widget>
+                        </item>
+                        <item row="1" column="3">
+                         <widget class="QComboBox" name="fit_sample_fit_type_combo_box">
+                          <property name="toolTip">
+                           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;If fitting should be used, then this allows for the selection of the fit type.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                          </property>
+                         </widget>
+                        </item>
+                        <item row="1" column="2">
+                         <widget class="QCheckBox" name="fit_sample_use_fit_check_box">
+                          <property name="toolTip">
+                           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;If fitting should be used&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                          </property>
+                          <property name="text">
+                           <string>Use fit</string>
+                          </property>
+                         </widget>
+                        </item>
+                        <item row="1" column="5">
+                         <widget class="QGroupBox" name="fit_sample_wavelength_combo_box">
+                          <property name="toolTip">
+                           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Allows for setting a custom wavelength range during fitting.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                          </property>
+                          <property name="title">
+                           <string>Use custom wavelength range [Ã…]</string>
+                          </property>
+                          <property name="checkable">
+                           <bool>true</bool>
+                          </property>
+                          <property name="checked">
+                           <bool>false</bool>
+                          </property>
+                          <layout class="QGridLayout" name="gridLayout_23">
+                           <item row="0" column="1">
+                            <widget class="QLineEdit" name="fit_sample_wavelength_min_line_edit">
+                             <property name="toolTip">
+                              <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The beginning of the custom wavelength range.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                             </property>
+                            </widget>
+                           </item>
+                           <item row="0" column="2">
+                            <widget class="QLabel" name="fit_sample_to_label">
+                             <property name="text">
+                              <string>to</string>
+                             </property>
+                            </widget>
+                           </item>
+                           <item row="0" column="0">
+                            <widget class="QLabel" name="fit_sample_from_label">
+                             <property name="text">
+                              <string>from</string>
+                             </property>
+                            </widget>
+                           </item>
+                           <item row="0" column="3">
+                            <widget class="QLineEdit" name="fit_sample_wavelength_max_line_edit">
+                             <property name="toolTip">
+                              <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The end of the custom wavelength range.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                             </property>
+                            </widget>
+                           </item>
+                          </layout>
+                         </widget>
+                        </item>
+                        <item row="1" column="4">
+                         <widget class="QSpinBox" name="fit_sample_polynomial_order_spin_box">
+                          <property name="toolTip">
+                           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;If a polynomial fit type was selected, then the polynomial order of the fit can be specified here.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                          </property>
+                          <property name="minimum">
+                           <number>2</number>
+                          </property>
+                          <property name="maximum">
+                           <number>6</number>
+                          </property>
+                         </widget>
+                        </item>
+                        <item row="0" column="4">
+                         <widget class="QLabel" name="fit_polynomial_order_label">
+                          <property name="text">
+                           <string>Poly. order</string>
+                          </property>
+                         </widget>
+                        </item>
+                        <item row="2" column="4">
+                         <widget class="QSpinBox" name="fit_can_polynomial_order_spin_box">
+                          <property name="toolTip">
+                           <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;If a polynomial fit type was selected, then the polynomial order of the fit can be specified here.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                          </property>
+                          <property name="minimum">
+                           <number>2</number>
+                          </property>
+                          <property name="maximum">
+                           <number>6</number>
+                          </property>
+                         </widget>
+                        </item>
+                       </layout>
+                      </widget>
+                     </item>
+                    </layout>
+                   </widget>
+                  </item>
+                  <item>
+                   <widget class="QGroupBox" name="pixel_adjustment_group_box">
+                    <property name="toolTip">
+                     <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The pixel adjustment files.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                    </property>
+                    <property name="title">
+                     <string>Pixel adjustment files</string>
+                    </property>
+                    <layout class="QGridLayout" name="gridLayout_10">
+                     <item row="0" column="1">
+                      <widget class="QLineEdit" name="pixel_adjustment_det_1_line_edit">
+                       <property name="toolTip">
+                        <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The path to the pixel adjustment file for the first detector.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                       </property>
+                      </widget>
+                     </item>
+                     <item row="0" column="0">
+                      <widget class="QLabel" name="pixel_adjustment_det_2_label">
+                       <property name="toolTip">
+                        <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The path to the pixel adjustment file for the first detector.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                       </property>
+                       <property name="text">
+                        <string>Det1</string>
+                       </property>
+                      </widget>
+                     </item>
+                     <item row="0" column="2">
+                      <widget class="QPushButton" name="pixel_adjustment_det_1_push_button">
+                       <property name="text">
+                        <string>Browse</string>
+                       </property>
+                      </widget>
+                     </item>
+                     <item row="1" column="2">
+                      <widget class="QPushButton" name="pixel_adjustment_det_2_push_button">
+                       <property name="text">
+                        <string>Browse</string>
+                       </property>
+                      </widget>
+                     </item>
+                     <item row="1" column="1">
+                      <widget class="QLineEdit" name="pixel_adjustment_det_2_line_edit">
+                       <property name="toolTip">
+                        <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The path to the pixel adjustment file for the second detector.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                       </property>
+                      </widget>
+                     </item>
+                     <item row="1" column="0">
+                      <widget class="QLabel" name="pixel_adjustement_det_1_label">
+                       <property name="toolTip">
+                        <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The path to the pixel adjustment file for the second detector.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                       </property>
+                       <property name="text">
+                        <string>Det2</string>
+                       </property>
+                      </widget>
+                     </item>
+                    </layout>
+                   </widget>
+                  </item>
+                  <item>
+                   <widget class="QGroupBox" name="wavelength_adjustment_group_box">
+                    <property name="toolTip">
+                     <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The wavelength adjustment files.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                    </property>
+                    <property name="title">
+                     <string>Wavelength adjustment files</string>
+                    </property>
+                    <layout class="QGridLayout" name="gridLayout_11">
+                     <item row="0" column="1">
+                      <widget class="QLineEdit" name="wavelength_adjustment_det_1_line_edit">
+                       <property name="toolTip">
+                        <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The path to the wavelength adjustment file for the first detector.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                       </property>
+                      </widget>
+                     </item>
+                     <item row="0" column="0">
+                      <widget class="QLabel" name="wavelength_adjustment_det_1_label">
+                       <property name="toolTip">
+                        <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The path to the wavelength adjustment file for the first detector.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                       </property>
+                       <property name="text">
+                        <string>Det 1</string>
+                       </property>
+                      </widget>
+                     </item>
+                     <item row="2" column="0">
+                      <widget class="QLabel" name="wavelength_adjustment_det_2_label">
+                       <property name="toolTip">
+                        <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The path to the wavelength adjustment file for the second detector.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                       </property>
+                       <property name="text">
+                        <string>Det 2</string>
+                       </property>
+                      </widget>
+                     </item>
+                     <item row="2" column="1">
+                      <widget class="QLineEdit" name="wavelength_adjustment_det_2_line_edit">
+                       <property name="toolTip">
+                        <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The path to the wavelength adjustment file for the second detector.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                       </property>
+                      </widget>
+                     </item>
+                     <item row="0" column="2">
+                      <widget class="QPushButton" name="wavelength_adjustment_det_1_push_button">
+                       <property name="text">
+                        <string>Browse</string>
+                       </property>
+                      </widget>
+                     </item>
+                     <item row="2" column="2">
+                      <widget class="QPushButton" name="wavelength_adjustment_det_2_push_button">
+                       <property name="text">
+                        <string>Browse</string>
+                       </property>
+                      </widget>
+                     </item>
+                    </layout>
+                   </widget>
+                  </item>
+                  <item>
+                   <spacer name="verticalSpacer_2">
+                    <property name="orientation">
+                     <enum>Qt::Vertical</enum>
+                    </property>
+                    <property name="sizeHint" stdset="0">
+                     <size>
+                      <width>20</width>
+                      <height>40</height>
+                     </size>
+                    </property>
+                   </spacer>
+                  </item>
+                 </layout>
+                </item>
+                <item>
+                 <layout class="QVBoxLayout" name="adjustemnt_tab_right_layout"/>
+                </item>
+               </layout>
+              </item>
+             </layout>
+            </widget>
+            <widget class="QWidget" name="q_tab">
+             <attribute name="title">
+              <string>Q</string>
+             </attribute>
+             <layout class="QHBoxLayout" name="horizontalLayout_6">
+              <item>
+               <layout class="QVBoxLayout" name="q_tab_left_layout">
+                <item>
+                 <widget class="QGroupBox" name="q_limits_group_box">
+                  <property name="toolTip">
+                   <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Settings for the momentum transfer limits.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                  </property>
+                  <property name="title">
+                   <string>Q limits</string>
+                  </property>
+                  <layout class="QGridLayout" name="gridLayout_15">
+                   <item row="1" column="1">
+                    <widget class="QLineEdit" name="q_1d_min_line_edit">
+                     <property name="toolTip">
+                      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The lower bound of the momentum transfer for a 1D reduction.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                     </property>
+                    </widget>
+                   </item>
+                   <item row="2" column="0">
+                    <widget class="QLabel" name="q_xy_label">
+                     <property name="toolTip">
+                      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Momentum transfer settings for 2D reductions.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                     </property>
+                     <property name="text">
+                      <string>Qxy</string>
+                     </property>
+                    </widget>
+                   </item>
+                   <item row="1" column="0">
+                    <widget class="QLabel" name="q_1d_label">
+                     <property name="toolTip">
+                      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Momentum transfer settings for 1D reductions.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                     </property>
+                     <property name="text">
+                      <string>Q1D</string>
+                     </property>
+                    </widget>
+                   </item>
+                   <item row="1" column="2">
+                    <widget class="QLineEdit" name="q_1d_max_line_edit">
+                     <property name="toolTip">
+                      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The upper bound of the momentum transfer for a 1D reduction.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                     </property>
+                    </widget>
+                   </item>
+                   <item row="1" column="3">
+                    <widget class="QLineEdit" name="q_1d_step_line_edit">
+                     <property name="toolTip">
+                      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The step of the momentum transfer for a 1D reduction.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                     </property>
+                    </widget>
+                   </item>
+                   <item row="2" column="2">
+                    <widget class="QLineEdit" name="q_xy_max_line_edit">
+                     <property name="toolTip">
+                      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The upper bound of the momentum transfer for a 2D reduction.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                     </property>
+                    </widget>
+                   </item>
+                   <item row="2" column="3">
+                    <widget class="QLineEdit" name="q_xy_step_line_edit">
+                     <property name="toolTip">
+                      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The step of the momentum transfer for a 2D reduction.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                     </property>
+                    </widget>
+                   </item>
+                   <item row="1" column="4">
+                    <widget class="QComboBox" name="q_1d_step_type_combo_box">
+                     <property name="toolTip">
+                      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The step type of the momentum transfer for a 1D reduction.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                     </property>
+                    </widget>
+                   </item>
+                   <item row="2" column="4">
+                    <widget class="QComboBox" name="q_xy_step_type_combo_box">
+                     <property name="toolTip">
+                      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The step type of the momentum transfer for a 2D reduction.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                     </property>
+                    </widget>
+                   </item>
+                   <item row="0" column="2">
+                    <widget class="QLabel" name="q_max_label">
+                     <property name="text">
+                      <string>Max [Ã…^-1]</string>
+                     </property>
+                    </widget>
+                   </item>
+                   <item row="0" column="1">
+                    <widget class="QLabel" name="q_min_label">
+                     <property name="text">
+                      <string>Min [Ã…^-1]</string>
+                     </property>
+                    </widget>
+                   </item>
+                   <item row="0" column="3">
+                    <widget class="QLabel" name="q_step_label">
+                     <property name="text">
+                      <string>Step [Ã…^-1]</string>
+                     </property>
+                    </widget>
+                   </item>
+                   <item row="0" column="4">
+                    <widget class="QLabel" name="q_step_type_label">
+                     <property name="text">
+                      <string>Step type</string>
+                     </property>
+                    </widget>
+                   </item>
+                  </layout>
+                 </widget>
+                </item>
+                <item>
+                 <widget class="QGroupBox" name="gravity_group_box">
+                  <property name="toolTip">
+                   <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Gravity settings. If checked then gravity will be accounted for in the reduction.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                  </property>
+                  <property name="title">
+                   <string>Account for gravity</string>
+                  </property>
+                  <property name="checkable">
+                   <bool>true</bool>
+                  </property>
+                  <property name="checked">
+                   <bool>false</bool>
+                  </property>
+                  <layout class="QGridLayout" name="gridLayout_17">
+                   <item row="0" column="0">
+                    <widget class="QLabel" name="gravity_extra_length_label">
+                     <property name="toolTip">
+                      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Extra length for the gravity correction.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                     </property>
+                     <property name="text">
+                      <string>Extra length [m]</string>
+                     </property>
+                    </widget>
+                   </item>
+                   <item row="0" column="1">
+                    <widget class="QLineEdit" name="gravity_extra_length_line_edit">
+                     <property name="toolTip">
+                      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Extra length for the gravity correction.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                     </property>
+                    </widget>
+                   </item>
+                  </layout>
+                 </widget>
+                </item>
+                <item>
+                 <widget class="QGroupBox" name="q_resolution_group_box">
+                  <property name="toolTip">
+                   <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Settings for Q resolution. If checked, then the Q resolution is used, else not.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                  </property>
+                  <property name="title">
+                   <string>Q resolution</string>
+                  </property>
+                  <property name="checkable">
+                   <bool>true</bool>
+                  </property>
+                  <property name="checked">
+                   <bool>false</bool>
+                  </property>
+                  <layout class="QGridLayout" name="gridLayout_13">
+                   <item row="0" column="0" colspan="2">
+                    <widget class="QComboBox" name="q_resolution_shape_combo_box">
+                     <property name="toolTip">
+                      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Selection of the aperture. This can be either a rectangular or a circular aperture&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                     </property>
+                     <item>
+                      <property name="text">
+                       <string>Circular</string>
+                      </property>
+                     </item>
+                     <item>
+                      <property name="text">
+                       <string>Rectangular</string>
+                      </property>
+                     </item>
+                    </widget>
+                   </item>
+                   <item row="3" column="0">
+                    <widget class="QLabel" name="q_resolution_source_a_label">
+                     <property name="toolTip">
+                      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Diameter of a circular source aperature.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                     </property>
+                     <property name="text">
+                      <string>A1 [mm]</string>
+                     </property>
+                    </widget>
+                   </item>
+                   <item row="3" column="4">
+                    <widget class="QLabel" name="q_resolution_sample_a_label">
+                     <property name="toolTip">
+                      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Diameter of a circular sample aperature.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                     </property>
+                     <property name="text">
+                      <string>A2 [mm]</string>
+                     </property>
+                    </widget>
+                   </item>
+                   <item row="1" column="1">
+                    <widget class="QLineEdit" name="q_resolution_source_h_line_edit">
+                     <property name="toolTip">
+                      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Height of a rectangular source aperature.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                     </property>
+                    </widget>
+                   </item>
+                   <item row="2" column="4">
+                    <widget class="QLabel" name="q_resolution_sample_w_label">
+                     <property name="toolTip">
+                      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Width of a rectangular sample aperature.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                     </property>
+                     <property name="text">
+                      <string>W2 [mm]</string>
+                     </property>
+                    </widget>
+                   </item>
+                   <item row="2" column="5">
+                    <widget class="QLineEdit" name="q_resolution_sample_w_line_edit">
+                     <property name="toolTip">
+                      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Width of a rectangular sample aperature.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                     </property>
+                    </widget>
+                   </item>
+                   <item row="6" column="0">
+                    <widget class="QLabel" name="q_resolution_collimation_length_label">
+                     <property name="toolTip">
+                      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The collimation length.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                     </property>
+                     <property name="text">
+                      <string>Collimation length [m]</string>
+                     </property>
+                    </widget>
+                   </item>
+                   <item row="6" column="4">
+                    <widget class="QLabel" name="q_resolution_delta_r_label">
+                     <property name="toolTip">
+                      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Delta r.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                     </property>
+                     <property name="text">
+                      <string>Delta r [mm]</string>
+                     </property>
+                    </widget>
+                   </item>
+                   <item row="7" column="1" colspan="4">
+                    <widget class="QLineEdit" name="q_resolution_moderator_file_line_edit">
+                     <property name="toolTip">
+                      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Path to the moderator file.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                     </property>
+                    </widget>
+                   </item>
+                   <item row="7" column="5">
+                    <widget class="QPushButton" name="q_resolution_moderator_file_push_button">
+                     <property name="text">
+                      <string>Browse</string>
+                     </property>
+                    </widget>
+                   </item>
+                   <item row="7" column="0">
+                    <widget class="QLabel" name="q_resolution_moderator_file_label">
+                     <property name="toolTip">
+                      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Path to the moderator file.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                     </property>
+                     <property name="text">
+                      <string>Moderator file</string>
+                     </property>
+                    </widget>
+                   </item>
+                   <item row="6" column="1">
+                    <widget class="QLineEdit" name="q_resolution_collimation_length_line_edit">
+                     <property name="toolTip">
+                      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The collimation length.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                     </property>
+                    </widget>
+                   </item>
+                   <item row="6" column="5">
+                    <widget class="QLineEdit" name="q_resolution_delta_r_line_edit">
+                     <property name="toolTip">
+                      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Delta r.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                     </property>
+                    </widget>
+                   </item>
+                   <item row="5" column="0" colspan="6">
+                    <widget class="Line" name="line_6">
+                     <property name="orientation">
+                      <enum>Qt::Horizontal</enum>
+                     </property>
+                    </widget>
+                   </item>
+                   <item row="3" column="1">
+                    <widget class="QLineEdit" name="q_resolution_source_a_line_edit">
+                     <property name="toolTip">
+                      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Diameter of a circular source aperature.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                     </property>
+                    </widget>
+                   </item>
+                   <item row="3" column="5">
+                    <widget class="QLineEdit" name="q_resolution_sample_a_line_edit">
+                     <property name="toolTip">
+                      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Diameter of a circular sample aperature.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                     </property>
+                    </widget>
+                   </item>
+                   <item row="1" column="0">
+                    <widget class="QLabel" name="q_resolution_source_h_label">
+                     <property name="toolTip">
+                      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Height of a rectangular source aperature.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                     </property>
+                     <property name="text">
+                      <string>H1 [mm]</string>
+                     </property>
+                    </widget>
+                   </item>
+                   <item row="2" column="1">
+                    <widget class="QLineEdit" name="q_resolution_source_w_line_edit">
+                     <property name="toolTip">
+                      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Width of a rectangular source aperature.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                     </property>
+                    </widget>
+                   </item>
+                   <item row="2" column="0">
+                    <widget class="QLabel" name="q_resolution_source_w_label">
+                     <property name="toolTip">
+                      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Width of a rectangular source aperature.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                     </property>
+                     <property name="text">
+                      <string>W1 [mm]</string>
+                     </property>
+                    </widget>
+                   </item>
+                   <item row="1" column="5">
+                    <widget class="QLineEdit" name="q_resolution_sample_h_line_edit">
+                     <property name="toolTip">
+                      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Height of a rectangular sample aperature.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                     </property>
+                    </widget>
+                   </item>
+                   <item row="1" column="4">
+                    <widget class="QLabel" name="q_resolution_sample_h_label">
+                     <property name="toolTip">
+                      <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Height of a rectangular sample aperature.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+                     </property>
+                     <property name="text">
+                      <string>H2 [mm]</string>
+                     </property>
+                    </widget>
+                   </item>
+                   <item row="1" column="2" rowspan="3">
+                    <widget class="Line" name="line_7">
+                     <property name="orientation">
+                      <enum>Qt::Vertical</enum>
+                     </property>
+                    </widget>
+                   </item>
+                  </layout>
+                 </widget>
+                </item>
+                <item>
+                 <spacer name="verticalSpacer">
+                  <property name="orientation">
+                   <enum>Qt::Vertical</enum>
+                  </property>
+                  <property name="sizeHint" stdset="0">
+                   <size>
+                    <width>20</width>
+                    <height>40</height>
+                   </size>
+                  </property>
+                 </spacer>
+                </item>
+               </layout>
+              </item>
+              <item>
+               <layout class="QVBoxLayout" name="q_tab_right_layout"/>
+              </item>
+             </layout>
+            </widget>
+            <widget class="SettingsDiagnosticTab" name="settings_diagnostic_tab">
+             <attribute name="title">
+              <string>State Diagnostic</string>
+             </attribute>
+            </widget>
+           </widget>
+          </item>
+         </layout>
+        </widget>
+       </widget>
+      </item>
+     </layout>
+    </item>
+   </layout>
+  </widget>
+  <widget class="QMenuBar" name="menuBar">
+   <property name="geometry">
+    <rect>
+     <x>0</x>
+     <y>0</y>
+     <width>1072</width>
+     <height>22</height>
+    </rect>
+   </property>
+   <widget class="QMenu" name="menuEdit">
+    <property name="title">
+     <string>&amp;Edit</string>
+    </property>
+   </widget>
+   <widget class="QMenu" name="menuFile">
+    <property name="title">
+     <string>Fi&amp;le</string>
+    </property>
+   </widget>
+   <addaction name="menuFile"/>
+   <addaction name="menuEdit"/>
+  </widget>
+ </widget>
+ <customwidgets>
+  <customwidget>
+   <class>SettingsDiagnosticTab</class>
+   <extends>QWidget</extends>
+   <header>settings_diagnostic_tab.h</header>
+   <container>1</container>
+  </customwidget>
+  <customwidget>
+   <class>MaskingTable</class>
+   <extends>QWidget</extends>
+   <header>masking_table.h</header>
+   <container>1</container>
+  </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/scripts/Interface/ui/sans_isis/settings_diagnostic_tab.py b/scripts/Interface/ui/sans_isis/settings_diagnostic_tab.py
new file mode 100644
index 0000000000000000000000000000000000000000..2d4e0662dc82fcc0466e33ebad39e2d1b4886580
--- /dev/null
+++ b/scripts/Interface/ui/sans_isis/settings_diagnostic_tab.py
@@ -0,0 +1,144 @@
+""" The settings diagnostic tab view.
+
+The settings diagnostic tab allows to display the state information in a tree view. The user can select the data
+from the individual rows in the data table. This view is useful for checking the overall settings of a reduction
+and helps the developer to identify issues.
+"""
+
+from __future__ import (absolute_import, division, print_function)
+
+from abc import ABCMeta, abstractmethod
+
+from six import with_metaclass
+from PyQt4 import QtGui
+
+import ui_settings_diagnostic_tab
+
+
+class SettingsDiagnosticTab(QtGui.QWidget, ui_settings_diagnostic_tab.Ui_SettingsDiagnosticTab):
+    class SettingsDiagnosticTabListener(with_metaclass(ABCMeta, object)):
+        """
+        Defines the elements which a presenter can listen to for the diagnostic tab
+        """
+        @abstractmethod
+        def on_row_changed(self):
+            pass
+
+        @abstractmethod
+        def on_update_rows(self):
+            pass
+
+        @abstractmethod
+        def on_collapse(self):
+            pass
+
+        @abstractmethod
+        def on_expand(self):
+            pass
+
+    def __init__(self):
+        super(SettingsDiagnosticTab, self).__init__()
+        self.setupUi(self)
+
+        # Hook up signal and slots
+        self.connect_signals()
+        self._settings_diagnostic_listeners = []
+
+        # Excluded settings entries
+        self.excluded = ["state_module", "state_name"]
+        self.class_type_id = "ClassTypeParameter"
+
+    def add_listener(self, listener):
+        if not isinstance(listener, SettingsDiagnosticTab.SettingsDiagnosticTabListener):
+            raise ValueError("The listener ist not of type SettingsDiagnosticTabListener but rather {}".format(type(listener)))
+        self._settings_diagnostic_listeners.append(listener)
+
+    def clear_listeners(self):
+        self._settings_diagnostic_listeners = []
+
+    def _call_settings_diagnostic_listeners(self, target):
+        for listener in self._settings_diagnostic_listeners:
+            target(listener)
+
+    def on_expand(self):
+        self._call_settings_diagnostic_listeners(lambda listener: listener.on_expand())
+
+    def on_collapse(self):
+        self._call_settings_diagnostic_listeners(lambda listener: listener.on_collapse())
+
+    def on_row_changed(self):
+        self._call_settings_diagnostic_listeners(lambda listener: listener.on_row_changed())
+
+    def on_update_rows(self):
+        self._call_settings_diagnostic_listeners(lambda listener: listener.on_update_rows())
+
+    def connect_signals(self):
+        self.select_row_combo_box.currentIndexChanged.connect(self.on_row_changed)
+        self.select_row_push_button.clicked.connect(self.on_update_rows)
+        self.collapse_button.clicked.connect(self.on_collapse)
+        self.expand_button.clicked.connect(self.on_expand)
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Actions
+    # ------------------------------------------------------------------------------------------------------------------
+    def update_rows(self, indices):
+        self.select_row_combo_box.blockSignals(True)
+        self.select_row_combo_box.clear()
+        for index in indices:
+            self.select_row_combo_box.addItem(str(index))
+        self.select_row_combo_box.blockSignals(False)
+
+    def fill_tree_widget(self, item, value):
+        item.setExpanded(True)
+        if type(value) is dict:
+            for key, val in sorted(value.iteritems()):
+                if key in self.excluded:
+                    continue
+                child = QtGui.QTreeWidgetItem()
+                child.setText(0, unicode(key))
+                item.addChild(child)
+                self.fill_tree_widget(child, val)
+        elif type(value) is list:
+            for val in value:
+                child = QtGui.QTreeWidgetItem()
+                child.setText(1, unicode(val))
+                item.addChild(child)
+        else:
+            child = QtGui.QTreeWidgetItem()
+            value = self.clean_class_type(value)
+            child.setText(1, unicode(value))
+            item.addChild(child)
+
+    def clean_class_type(self, value):
+        if isinstance(value, str) and self.class_type_id in value:
+            # Only the last element is of interest
+            split_values = value.split("#")
+            return split_values[-1]
+        else:
+            return value
+
+    def set_row(self, index):
+        found_index = self.select_row_combo_box.findText(str(index))
+        if found_index and found_index != -1:
+            self.select_row_combo_box.setCurrentIndex(found_index)
+
+    def set_tree(self, state_dict):
+        self.tree_widget.clear()
+        if state_dict:
+            self.fill_tree_widget(self.tree_widget.invisibleRootItem(), state_dict)
+
+    def get_current_row(self):
+        value = self.select_row_combo_box.currentText()
+        if not value:
+            value = -1
+        return int(value)
+
+    def collapse(self):
+        for index in range(self.tree_widget.topLevelItemCount()):
+            top_level_item = self.tree_widget.topLevelItem(index)
+            self.tree_widget.collapseItem(top_level_item)
+
+    def expand(self):
+        for index in range(self.tree_widget.topLevelItemCount()):
+            top_level_item = self.tree_widget.topLevelItem(index)
+            self.tree_widget.expandItem(top_level_item)
diff --git a/scripts/Interface/ui/sans_isis/settings_diagnostic_tab.ui b/scripts/Interface/ui/sans_isis/settings_diagnostic_tab.ui
new file mode 100644
index 0000000000000000000000000000000000000000..a3bb4b2be4b1be1832a64c430d00a8a854bd000d
--- /dev/null
+++ b/scripts/Interface/ui/sans_isis/settings_diagnostic_tab.ui
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>SettingsDiagnosticTab</class>
+ <widget class="QWidget" name="SettingsDiagnosticTab">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>736</width>
+    <height>396</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Form</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout_2">
+   <item>
+    <layout class="QHBoxLayout" name="settings_diagnostic_tab_layout">
+     <item>
+      <widget class="QLabel" name="select_row_label">
+       <property name="text">
+        <string>Select row: </string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QComboBox" name="select_row_combo_box"/>
+     </item>
+     <item>
+      <widget class="QPushButton" name="select_row_push_button">
+       <property name="text">
+        <string>Update row selection</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <spacer name="horizontalSpacer">
+       <property name="orientation">
+        <enum>Qt::Horizontal</enum>
+       </property>
+       <property name="sizeHint" stdset="0">
+        <size>
+         <width>40</width>
+         <height>20</height>
+        </size>
+       </property>
+      </spacer>
+     </item>
+     <item>
+      <widget class="QPushButton" name="expand_button">
+       <property name="text">
+        <string>Expand</string>
+       </property>
+      </widget>
+     </item>
+     <item>
+      <widget class="QPushButton" name="collapse_button">
+       <property name="text">
+        <string>Collapse</string>
+       </property>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <widget class="QTreeWidget" name="tree_widget">
+     <property name="animated">
+      <bool>true</bool>
+     </property>
+     <attribute name="headerDefaultSectionSize">
+      <number>350</number>
+     </attribute>
+     <attribute name="headerMinimumSectionSize">
+      <number>350</number>
+     </attribute>
+     <attribute name="headerStretchLastSection">
+      <bool>true</bool>
+     </attribute>
+     <column>
+      <property name="text">
+       <string notr="true">Key</string>
+      </property>
+     </column>
+     <column>
+      <property name="text">
+       <string>Value</string>
+      </property>
+     </column>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/scripts/MantidIPython/__init__.py b/scripts/MantidIPython/__init__.py
index 831824e6114261387169bae1de844b987c996b0a..e0adbfe0ebe26fb8f6572d3c95595d84d63b66bb 100644
--- a/scripts/MantidIPython/__init__.py
+++ b/scripts/MantidIPython/__init__.py
@@ -23,6 +23,7 @@ Some tools for use in ipython notebooks generated by Mantid.
 
 # Suppress warnings about unused import as these
 # imports are important for iPython
+from __future__ import (absolute_import, division, print_function)
 from MantidIPython.plot_functions import *  # noqa: F401
 import warnings  # noqa: F401
 import mantid.kernel  # noqa: F401
diff --git a/scripts/MantidIPython/plot_functions.py b/scripts/MantidIPython/plot_functions.py
index 5cf53680e10ccc9dfbe1935f3e9a352835741500..b8519d237b1fb04857c3a496b62852fdf59bebe3 100644
--- a/scripts/MantidIPython/plot_functions.py
+++ b/scripts/MantidIPython/plot_functions.py
@@ -2,6 +2,7 @@
 Plotting functions for use in IPython notebooks that are generated by MantidPlot
 """
 
+from __future__ import (absolute_import, division, print_function)
 import matplotlib.pyplot as plt
 
 # Import Mantid
diff --git a/scripts/ORNL_SANS.py b/scripts/ORNL_SANS.py
index c0cb689df6f5b661e34a4d1c325276ad27b97286..7c75c4a1935e22ed0fb6bb020aaa2f2e132059c7 100644
--- a/scripts/ORNL_SANS.py
+++ b/scripts/ORNL_SANS.py
@@ -2,6 +2,7 @@
 """
     Script used to start the HFIR SANS reduction gui from Mantidplot
 """
+from __future__ import (absolute_import, division, print_function)
 from reduction_application import ReductionGUI
 
 reducer = ReductionGUI(instrument_list=["BIOSANS", "GPSANS", "EQSANS"])
diff --git a/scripts/REFL_Reduction.py b/scripts/REFL_Reduction.py
index 8038e3f0086729613e2a30f4f261f22ecc64efa6..2c45991060373a51dca2881faee4b6d39f95bee0 100644
--- a/scripts/REFL_Reduction.py
+++ b/scripts/REFL_Reduction.py
@@ -2,6 +2,7 @@
 """
     Script used to start the REFL reduction gui from Mantidplot
 """
+from __future__ import (absolute_import, division, print_function)
 from reduction_application import ReductionGUI
 
 reducer = ReductionGUI(instrument="REFL", instrument_list=["REFL"])
diff --git a/scripts/REFL_SF_Calculator.py b/scripts/REFL_SF_Calculator.py
index eabf63819a2dc1f897c46999db28da7674885d78..a6ce27641874470d7591de8c938d8f3ef418e0ae 100644
--- a/scripts/REFL_SF_Calculator.py
+++ b/scripts/REFL_SF_Calculator.py
@@ -2,6 +2,7 @@
 """
     Script used to start the REFL SF calculator gui from Mantidplot
 """
+from __future__ import (absolute_import, division, print_function)
 from reduction_application import ReductionGUI
 
 reducer = ReductionGUI(instrument="REFLSF", instrument_list=["REFLSF"])
diff --git a/scripts/REFM_Reduction.py b/scripts/REFM_Reduction.py
index d589aa0b2c13a007002f12a6f526096e24ffc3bb..f755196eb030347b141a0fed9bebf032f30e7182 100644
--- a/scripts/REFM_Reduction.py
+++ b/scripts/REFM_Reduction.py
@@ -2,6 +2,7 @@
 """
     Script used to start the REFL reduction gui from Mantidplot
 """
+from __future__ import (absolute_import, division, print_function)
 from reduction_application import ReductionGUI
 
 reducer = ReductionGUI(instrument="REFM", instrument_list=["REFM"])
diff --git a/scripts/SANS/ISISCommandInterface.py b/scripts/SANS/ISISCommandInterface.py
index 0a81425fa643b98485a6b37b13bf2b7d620f2b44..d2b27b10ea938ad1516783a1add52508af4f05b2 100644
--- a/scripts/SANS/ISISCommandInterface.py
+++ b/scripts/SANS/ISISCommandInterface.py
@@ -978,9 +978,6 @@ def DisplayMask(mask_worksp=None):
         @param mask_worksp: optional this named workspace will be modified and should be from the currently selected instrument
         @return the name of the workspace that was displayed
     """
-    # this will be copied from a sample work space if one exists
-    counts_data = None
-
     if not mask_worksp:
         mask_worksp = '__CurrentMask'
         samp = LAST_SAMPLE
@@ -993,18 +990,12 @@ def DisplayMask(mask_worksp=None):
                 CloneWorkspace(InputWorkspace=samp + "_monitors",
                                OutputWorkspace=mask_worksp + "_monitors")
                 su.fromEvent2Histogram(mask_worksp, mtd[mask_worksp + "_monitors"])
-
-            counts_data = '__DisplayMasked_tempory_wksp'
-            Integration(InputWorkspace=mask_worksp, OutputWorkspace=counts_data)
         else:
             msg = 'Cannot display the mask without a sample workspace'
             _printMessage(msg, log=True, no_console=False)
             return
 
-    ReductionSingleton().mask.display(mask_worksp, ReductionSingleton(), counts_data)
-    if counts_data:
-        DeleteWorkspace(counts_data)
-
+    ReductionSingleton().mask.display(mask_worksp, ReductionSingleton())
     return mask_worksp
 
 
diff --git a/scripts/SANS/isis_reduction_steps.py b/scripts/SANS/isis_reduction_steps.py
index e92225fdceba723385416e7edd815e1d94455d30..65d072ea271150f764986032f9d09d374a3325dd 100644
--- a/scripts/SANS/isis_reduction_steps.py
+++ b/scripts/SANS/isis_reduction_steps.py
@@ -1099,12 +1099,11 @@ class Mask_ISIS(ReductionStep):
         # opens an instrument showing the contents of the workspace (i.e. the instrument with masked detectors)
         instrum.view(wksp_name)
 
-    def display(self, wksp, reducer, counts=None):
+    def display(self, wksp, reducer):
         """
             Mask detectors in a workspace and display its show instrument
             @param wksp: this named workspace will be masked and displayed
             @param reducer: the reduction chain that contains all the settings
-            @param counts: optional workspace containing neutron counts data that the mask will be supperimposed on to
         """
         # apply masking to the current detector
         self.execute(reducer, wksp)
@@ -1118,49 +1117,6 @@ class Mask_ISIS(ReductionStep):
         # reset the instrument to mask the current detector
         instrum.setDetector(original)
 
-        if counts:
-            Power(InputWorkspace=counts, OutputWorkspace='ones', Exponent=0)
-            Plus(LHSWorkspace=wksp, RHSWorkspace='ones', OutputWorkspace=wksp)
-
-        # Mark up "dead" detectors with error value
-        FindDeadDetectors(InputWorkspace=wksp, OutputWorkspace=wksp, LiveValue=0, DeadValue=1)
-
-        # check if we have a workspace to superimpose the mask on to
-        if counts:
-            # the code below is a proto-type for the ISIS SANS group, to make it perminent it should be improved
-
-            # create a workspace where the masked spectra have a value
-            flags = mtd[wksp]
-            # normalise that value to the data in the workspace
-            vals = mtd[counts]
-            maxval = 0
-            Xs = []
-            Ys = []
-            Es = []
-            for i in range(0, flags.getNumberHistograms()):
-                Xs.append(flags.readX(i)[0])
-                Xs.append(flags.readX(i)[1])
-                Ys.append(flags.readY(i)[0])
-                Es.append(0)
-
-                if vals.readY(i)[0] > maxval:
-                    # don't include masked or monitors
-                    if (flags.readY(i)[0] == 0) and (vals.readY(i)[0] < 5000):
-                        maxval = vals.readY(i)[0]
-
-            # now normalise to the max/5
-            maxval /= 5.0
-            for i in range(0, len(Ys)):
-                if Ys[i] != 0:
-                    Ys[i] = maxval * Ys[i] + vals.readY(i)[0]
-
-            CreateWorkspace(OutputWorkspace=wksp, DataX=Xs, DataY=Ys, DataE=Es, NSpec=len(Ys), UnitX='TOF')
-            # change the units on the workspace so it is compatible with the workspace containing counts data
-            Multiply(LHSWorkspace='ones', RHSWorkspace=wksp, OutputWorkspace='units')
-            # do the super-position and clean up
-            Minus(LHSWorkspace=counts, RHSWorkspace='units', OutputWorkspace=wksp)
-            reducer.deleteWorkspaces(['ones', 'units'])
-
         # opens an instrument showing the contents of the workspace (i.e. the instrument with masked detectors)
         instrum.view(wksp)
 
diff --git a/scripts/SANS/sans/algorithm_detail/crop_helper.py b/scripts/SANS/sans/algorithm_detail/crop_helper.py
new file mode 100644
index 0000000000000000000000000000000000000000..fcb92794acbda0dc4ae8b60c6555a8ae9d9d432d
--- /dev/null
+++ b/scripts/SANS/sans/algorithm_detail/crop_helper.py
@@ -0,0 +1,14 @@
+# pylint: disable=invalid-name
+
+""" Helpers for SANSCrop."""
+from __future__ import (absolute_import, division, print_function)
+from sans.common.general_functions import convert_instrument_and_detector_type_to_bank_name
+from sans.common.enums import SANSInstrument
+
+
+def get_component_name(workspace, detector_type):
+    instrument = workspace.getInstrument()
+    instrument_name = instrument.getName().strip()
+    instrument_name = instrument_name.upper()
+    instrument = SANSInstrument.from_string(instrument_name)
+    return convert_instrument_and_detector_type_to_bank_name(instrument, detector_type)
diff --git a/scripts/SANS/sans/algorithm_detail/load_data.py b/scripts/SANS/sans/algorithm_detail/load_data.py
index 997ada3730da322362ef6167b1dbd7e1214f0bf5..ffbd05b9b7d3633dbe3e31947ac77c6ef86034c7 100644
--- a/scripts/SANS/sans/algorithm_detail/load_data.py
+++ b/scripts/SANS/sans/algorithm_detail/load_data.py
@@ -53,7 +53,7 @@ from sans.common.file_information import (SANSFileInformationFactory, FileType,
 from sans.common.constants import (EMPTY_NAME, SANS_SUFFIX, TRANS_SUFFIX, MONITOR_SUFFIX, CALIBRATION_WORKSPACE_TAG,
                                    SANS_FILE_TAG, OUTPUT_WORKSPACE_GROUP, OUTPUT_MONITOR_WORKSPACE,
                                    OUTPUT_MONITOR_WORKSPACE_GROUP)
-from sans.common.enums import (SANSInstrument, SANSDataType)
+from sans.common.enums import (SANSFacility, SANSInstrument, SANSDataType)
 from sans.common.general_functions import (create_child_algorithm)
 from sans.common.log_tagger import (set_tag, has_tag, get_tag)
 from sans.state.data import (StateData)
@@ -78,27 +78,27 @@ def get_file_and_period_information_from_data(data):
     file_information_factory = SANSFileInformationFactory()
     file_information = dict()
     period_information = dict()
-    if data.sample_scatter is not None:
+    if data.sample_scatter:
         update_file_information(file_information, file_information_factory,
                                 SANSDataType.SampleScatter, data.sample_scatter)
         period_information.update({SANSDataType.SampleScatter: data.sample_scatter_period})
-    if data.sample_transmission is not None:
+    if data.sample_transmission:
         update_file_information(file_information, file_information_factory,
                                 SANSDataType.SampleTransmission, data.sample_transmission)
         period_information.update({SANSDataType.SampleTransmission: data.sample_transmission_period})
-    if data.sample_direct is not None:
+    if data.sample_direct:
         update_file_information(file_information, file_information_factory,
                                 SANSDataType.SampleDirect, data.sample_direct)
         period_information.update({SANSDataType.SampleDirect: data.sample_direct_period})
-    if data.can_scatter is not None:
+    if data.can_scatter:
         update_file_information(file_information, file_information_factory,
                                 SANSDataType.CanScatter, data.can_scatter)
         period_information.update({SANSDataType.CanScatter: data.can_scatter_period})
-    if data.can_transmission is not None:
+    if data.can_transmission:
         update_file_information(file_information, file_information_factory,
                                 SANSDataType.CanTransmission, data.can_transmission)
         period_information.update({SANSDataType.CanTransmission: data.can_transmission_period})
-    if data.can_direct is not None:
+    if data.can_direct:
         update_file_information(file_information, file_information_factory,
                                 SANSDataType.CanDirect, data.can_direct)
         period_information.update({SANSDataType.CanDirect: data.can_direct_period})
@@ -753,13 +753,13 @@ class SANSLoadDataFactory(object):
         super(SANSLoadDataFactory, self).__init__()
 
     @staticmethod
-    def _get_instrument_type(state):
+    def _get_facility(state):
         data = state.data
         # Get the correct loader based on the sample scatter file from the data sub state
         data.validate()
         file_info, _ = get_file_and_period_information_from_data(data)
         sample_scatter_info = file_info[SANSDataType.SampleScatter]
-        return sample_scatter_info.get_instrument()
+        return sample_scatter_info.get_facility()
 
     @staticmethod
     def create_loader(state):
@@ -769,9 +769,8 @@ class SANSLoadDataFactory(object):
         :param state: a SANSState object
         :return: the corresponding loader
         """
-        instrument_type = SANSLoadDataFactory._get_instrument_type(state)
-        if instrument_type is SANSInstrument.LARMOR or instrument_type is SANSInstrument.LOQ or\
-           instrument_type is SANSInstrument.SANS2D:
+        facility = SANSLoadDataFactory._get_facility(state)
+        if facility is SANSFacility.ISIS:
             loader = SANSLoadDataISIS()
         else:
             raise RuntimeError("SANSLoaderFactory: Other instruments are not implemented yet.")
diff --git a/scripts/SANS/sans/algorithm_detail/merge_reductions.py b/scripts/SANS/sans/algorithm_detail/merge_reductions.py
index 7b550c2a3424b543d4b898caa28525f62c6f798d..2d0d0b6ea317f46bcb2fb10d82f1311813c2caab 100644
--- a/scripts/SANS/sans/algorithm_detail/merge_reductions.py
+++ b/scripts/SANS/sans/algorithm_detail/merge_reductions.py
@@ -4,7 +4,7 @@ from __future__ import (absolute_import, division, print_function)
 from abc import (ABCMeta, abstractmethod)
 from six import with_metaclass
 from sans.common.general_functions import create_child_algorithm
-from sans.common.enums import (SANSInstrument, DataType, FitModeForMerge)
+from sans.common.enums import (SANSFacility, DataType, FitModeForMerge)
 from sans.algorithm_detail.bundles import MergeBundle
 
 
@@ -101,10 +101,9 @@ class MergeFactory(object):
     def create_merger(state):
         # The selection depends on the facility/instrument
         data_info = state.data
-        instrument = data_info.instrument
+        facility = data_info.facility
 
-        if instrument is SANSInstrument.LARMOR or instrument is SANSInstrument.LOQ or \
-           instrument is SANSInstrument.SANS2D:
+        if facility is SANSFacility.ISIS:
             merger = ISIS1DMerger()
         else:
             merger = NullMerger()
diff --git a/scripts/SANS/sans/algorithm_detail/move_workspaces.py b/scripts/SANS/sans/algorithm_detail/move_workspaces.py
index 23cb98bc1fb8e2ff762876a7821644d3b0fb8334..81c08e37692423ac7167e3af436d545c173d668e 100644
--- a/scripts/SANS/sans/algorithm_detail/move_workspaces.py
+++ b/scripts/SANS/sans/algorithm_detail/move_workspaces.py
@@ -243,6 +243,34 @@ def get_detector_component(move_info, component):
     return component_selection
 
 
+def move_low_angle_bank_for_SANS2D_and_ZOOM(move_info, workspace, coordinates):
+    # REAR_DET_Z
+    lab_detector_z_tag = "Rear_Det_Z"
+
+    log_names = [lab_detector_z_tag]
+    log_types = [float]
+    log_values = get_single_valued_logs_from_workspace(workspace, log_names, log_types,
+                                                       convert_from_millimeter_to_meter=True)
+
+    lab_detector_z = move_info.lab_detector_z \
+        if log_values[lab_detector_z_tag] is None else log_values[lab_detector_z_tag]
+
+    # Perform x and y tilt
+    lab_detector = move_info.detectors[DetectorType.to_string(DetectorType.LAB)]
+    SANSMoveSANS2D.perform_x_and_y_tilts(workspace, lab_detector)
+
+    lab_detector_default_sd_m = move_info.lab_detector_default_sd_m
+    x_shift = -coordinates[0]
+    y_shift = -coordinates[1]
+
+    z_shift = (lab_detector_z + lab_detector.z_translation_correction) - lab_detector_default_sd_m
+    detector_name = lab_detector.detector_name
+    offset = {CanonicalCoordinates.X: x_shift,
+              CanonicalCoordinates.Y: y_shift,
+              CanonicalCoordinates.Z: z_shift}
+    move_component(workspace, offset, detector_name)
+
+
 # -------------------------------------------------
 # Move classes
 # -------------------------------------------------
@@ -420,31 +448,7 @@ class SANSMoveSANS2D(SANSMove):
 
     @staticmethod
     def _move_low_angle_bank(move_info, workspace, coordinates):
-        # REAR_DET_Z
-        lab_detector_z_tag = "Rear_Det_Z"
-
-        log_names = [lab_detector_z_tag]
-        log_types = [float]
-        log_values = get_single_valued_logs_from_workspace(workspace, log_names, log_types,
-                                                           convert_from_millimeter_to_meter=True)
-
-        lab_detector_z = move_info.lab_detector_z \
-            if log_values[lab_detector_z_tag] is None else log_values[lab_detector_z_tag]
-
-        # Perform x and y tilt
-        lab_detector = move_info.detectors[DetectorType.to_string(DetectorType.LAB)]
-        SANSMoveSANS2D.perform_x_and_y_tilts(workspace, lab_detector)
-
-        lab_detector_default_sd_m = move_info.lab_detector_default_sd_m
-        x_shift = -coordinates[0]
-        y_shift = -coordinates[1]
-
-        z_shift = (lab_detector_z + lab_detector.z_translation_correction) - lab_detector_default_sd_m
-        detector_name = lab_detector.detector_name
-        offset = {CanonicalCoordinates.X: x_shift,
-                  CanonicalCoordinates.Y: y_shift,
-                  CanonicalCoordinates.Z: z_shift}
-        move_component(workspace, offset, detector_name)
+        move_low_angle_bank_for_SANS2D_and_ZOOM(move_info, workspace, coordinates)
 
     @staticmethod
     def _move_monitor_4(workspace, move_info):
@@ -501,7 +505,7 @@ class SANSMoveSANS2D(SANSMove):
 
     @staticmethod
     def is_correct(instrument_type, run_number, **kwargs):
-        return True if instrument_type is SANSInstrument.SANS2D else False
+        return instrument_type is SANSInstrument.SANS2D
 
 
 class SANSMoveLOQ(SANSMove):
@@ -548,7 +552,7 @@ class SANSMoveLOQ(SANSMove):
 
     @staticmethod
     def is_correct(instrument_type, run_number, **kwargs):
-        return True if instrument_type is SANSInstrument.LOQ else False
+        return instrument_type is SANSInstrument.LOQ
 
 
 class SANSMoveLARMOROldStyle(SANSMove):
@@ -598,7 +602,7 @@ class SANSMoveLARMOROldStyle(SANSMove):
     def is_correct(instrument_type, run_number, **kwargs):
         is_correct_instrument = instrument_type is SANSInstrument.LARMOR
         is_correct_run_number = run_number < 2217
-        return True if is_correct_instrument and is_correct_run_number else False
+        return is_correct_instrument and is_correct_run_number
 
 
 class SANSMoveLARMORNewStyle(SANSMove):
@@ -665,7 +669,39 @@ class SANSMoveLARMORNewStyle(SANSMove):
     def is_correct(instrument_type, run_number, **kwargs):
         is_correct_instrument = instrument_type is SANSInstrument.LARMOR
         is_correct_run_number = run_number >= 2217
-        return True if is_correct_instrument and is_correct_run_number else False
+        return is_correct_instrument and is_correct_run_number
+
+
+class SANSMoveZOOM(SANSMove):
+    @staticmethod
+    def _move_low_angle_bank(move_info, workspace, coordinates):
+        move_low_angle_bank_for_SANS2D_and_ZOOM(move_info, workspace, coordinates)
+
+    def do_move_initial(self, move_info, workspace, coordinates, component, is_transmission_workspace):
+        # For ZOOM we only have to coordinates
+        assert len(coordinates) == 2
+
+        _component = component  # noqa
+        _is_transmission_workspace = is_transmission_workspace  # noqa
+
+        # Move the low angle bank
+        self._move_low_angle_bank(move_info, workspace, coordinates)
+
+        # Move the sample holder
+        move_sample_holder(workspace, move_info.sample_offset, move_info.sample_offset_direction)
+
+    def do_move_with_elementary_displacement(self, move_info, workspace, coordinates, component):
+        # For ZOOM we only have to coordinates
+        assert len(coordinates) == 2
+        coordinates_to_move = [-coordinates[0], -coordinates[1]]
+        apply_standard_displacement(move_info, workspace, coordinates_to_move, component)
+
+    def do_set_to_zero(self, move_info, workspace, component):
+        set_components_to_original_for_isis(move_info, workspace, component)
+
+    @staticmethod
+    def is_correct(instrument_type, run_number, **kwargs):
+        return instrument_type is SANSInstrument.ZOOM
 
 
 class SANSMoveFactory(object):
@@ -688,6 +724,8 @@ class SANSMoveFactory(object):
             mover = SANSMoveLARMOROldStyle()
         elif SANSMoveLARMORNewStyle.is_correct(instrument_type, run_number):
             mover = SANSMoveLARMORNewStyle()
+        elif SANSMoveZOOM.is_correct(instrument_type, run_number):
+            mover = SANSMoveZOOM()
         else:
             mover = None
             NotImplementedError("SANSLoaderFactory: Other instruments are not implemented yet.")
diff --git a/scripts/SANS/sans/algorithm_detail/q_resolution_calculator.py b/scripts/SANS/sans/algorithm_detail/q_resolution_calculator.py
index 4e5460342fbdf0246a30d021a5761f5aeac82050..885b36598f7321905f30d2c7779e7d758b9321ed 100644
--- a/scripts/SANS/sans/algorithm_detail/q_resolution_calculator.py
+++ b/scripts/SANS/sans/algorithm_detail/q_resolution_calculator.py
@@ -3,7 +3,7 @@ from abc import (ABCMeta, abstractmethod)
 from six import with_metaclass
 from math import sqrt
 from sans.common.constants import EMPTY_NAME
-from sans.common.enums import (SANSInstrument)
+from sans.common.enums import (SANSFacility)
 from sans.common.general_functions import create_unmanaged_algorithm
 
 
@@ -145,10 +145,8 @@ class QResolutionCalculatorFactory(object):
     @staticmethod
     def create_q_resolution_calculator(state):
         data = state.data
-        instrument = data.instrument
-        is_isis_instrument = instrument is SANSInstrument.LARMOR or instrument is SANSInstrument.SANS2D or\
-                             instrument is SANSInstrument.LOQ  # noqa
-        if is_isis_instrument:
+        facility = data.facility
+        if facility is SANSFacility.ISIS:
             convert_to_q = state.convert_to_q
             if convert_to_q.use_q_resolution:
                 q_resolution = QResolutionCalculatorISIS()
diff --git a/scripts/SANS/sans/algorithm_detail/scale_helpers.py b/scripts/SANS/sans/algorithm_detail/scale_helpers.py
index 9b9a03f6e871596d4858273c095ea0583b0640bd..2d136f994d154c739535740c97e3bedcc16a4ef1 100644
--- a/scripts/SANS/sans/algorithm_detail/scale_helpers.py
+++ b/scripts/SANS/sans/algorithm_detail/scale_helpers.py
@@ -2,7 +2,7 @@ from __future__ import (absolute_import, division, print_function)
 import math
 from abc import (ABCMeta, abstractmethod)
 from six import (with_metaclass)
-from sans.common.enums import (SANSInstrument, SampleShape)
+from sans.common.enums import (SANSInstrument, SANSFacility, SampleShape)
 from sans.common.general_functions import create_unmanaged_algorithm
 from sans.common.constants import EMPTY_NAME
 
@@ -82,10 +82,9 @@ class DivideByVolumeFactory(object):
     @staticmethod
     def create_divide_by_volume(state):
         data = state.data
-        instrument = data.instrument
+        facility = data.facility
 
-        is_isis_instrument = instrument is SANSInstrument.LARMOR or instrument is SANSInstrument.SANS2D or instrument is SANSInstrument.LOQ  # noqa
-        if is_isis_instrument:
+        if facility is SANSFacility.ISIS:
             divider = DivideByVolumeISIS()
         else:
             raise RuntimeError("DivideVolumeFactory: Other instruments are not implemented yet.")
@@ -149,12 +148,11 @@ class MultiplyByAbsoluteScaleFactory(object):
     def create_multiply_by_absolute(state):
         data = state.data
         instrument = data.instrument
+        facility = data.facility
 
-        is_isis_instrument = instrument is SANSInstrument.LARMOR or instrument is SANSInstrument.SANS2D or \
-                             SANSInstrument.LOQ  # noqa
         if instrument is SANSInstrument.LOQ:
             multiplier = MultiplyByAbsoluteScaleLOQ()
-        elif is_isis_instrument:
+        elif facility is SANSFacility.ISIS:
             multiplier = MultiplyByAbsoluteScaleISIS()
         else:
             raise NotImplementedError("MultiplyByAbsoluteScaleFactory: Other instruments are not implemented yet.")
diff --git a/scripts/SANS/sans/algorithm_detail/slicer.py b/scripts/SANS/sans/algorithm_detail/slicer.py
index 16bb504f5a23f3aebb117a6f841334344a20b794..9d3ab4c83690d26d1593912d82e626736622a7de 100644
--- a/scripts/SANS/sans/algorithm_detail/slicer.py
+++ b/scripts/SANS/sans/algorithm_detail/slicer.py
@@ -7,7 +7,7 @@ from mantid.dataobjects import Workspace2D
 
 from sans.common.general_functions import (get_charge_and_time, create_unmanaged_algorithm)
 from sans.common.constants import EMPTY_NAME
-from sans.common.enums import (SANSInstrument, DataType)
+from sans.common.enums import (SANSFacility, DataType)
 
 
 def slice_by_time(workspace, start_time=None, stop_time=None):
@@ -133,7 +133,7 @@ class SliceEventFactory(object):
         :return: the corresponding slicer
         """
         data_info = state.data
-        instrument = data_info.instrument
+        facility = data_info.facility
 
         # The factory is currently set up to
         # 1. Use NullSlicer when we have a histogram
@@ -141,8 +141,7 @@ class SliceEventFactory(object):
         # 3. else raise error
         if isinstance(workspace, Workspace2D):
             slicer = NullSlicer()
-        elif instrument is SANSInstrument.LARMOR or instrument is SANSInstrument.LOQ or \
-             instrument is SANSInstrument.SANS2D:  # noqa
+        elif facility is SANSFacility.ISIS:
             slicer = ISISSlicer(data_type)
         else:
             raise RuntimeError("SliceEventFactory: Other instruments are not implemented yet.")
diff --git a/scripts/SANS/sans/command_interface/ISISCommandInterface.py b/scripts/SANS/sans/command_interface/ISISCommandInterface.py
index 7487245ad7f125b953c827212a496199a6e67cae..3af8f99bbb89bdc1ec595a28852181de36e1d6bd 100644
--- a/scripts/SANS/sans/command_interface/ISISCommandInterface.py
+++ b/scripts/SANS/sans/command_interface/ISISCommandInterface.py
@@ -97,6 +97,10 @@ def LARMOR(idf_path = None):
     config['default.instrument'] = 'LARMOR'
 
 
+def ZOOM(idf_path = None):
+    config['default.instrument'] = 'ZOOM'
+
+
 # ----------------------------------------------------------------------------------------------------------------------
 # Unused commands
 # ----------------------------------------------------------------------------------------------------------------------
@@ -378,8 +382,10 @@ def SetMonitorSpectrum(specNum, interp=False):
                    default no interpolation
     """
     specNum = int(specNum)
-    monitor_spectrum_command = NParameterCommand(command_id=NParameterCommandId.monitor_spectrum, values=[specNum,
-                                                                                                          interp])
+    is_trans = False
+    monitor_spectrum_command = NParameterCommand(command_id=NParameterCommandId.incident_spectrum, values=[specNum,
+                                                                                                           interp,
+                                                                                                           is_trans])
     director.add_command(monitor_spectrum_command)
 
 
@@ -392,8 +398,9 @@ def SetTransSpectrum(specNum, interp=False):
                    default no interpolation
     """
     specNum = int(specNum)
-    transmission_spectrum_command = NParameterCommand(command_id=NParameterCommandId.transmission_spectrum,
-                                                      values=[specNum, interp])
+    is_trans = True
+    transmission_spectrum_command = NParameterCommand(command_id=NParameterCommandId.incident_spectrum,
+                                                      values=[specNum, interp, is_trans])
     director.add_command(transmission_spectrum_command)
 
 
@@ -525,7 +532,7 @@ def TransFit(mode, lambdamin=None, lambdamax=None, selector='BOTH'):
     if mode == "LINEAR" or mode == "STRAIGHT" or mode == "LIN":
         fit_type = FitType.Linear
     elif mode == "LOGARITHMIC" or mode == "LOG" or mode == "YLOG":
-        fit_type = FitType.Log
+        fit_type = FitType.Logarithmic
     elif does_pattern_match(polynomial_pattern, mode):
         fit_type = FitType.Polynomial
         polynomial_order = extract_polynomial_order(mode)
diff --git a/scripts/SANS/sans/common/configurations.py b/scripts/SANS/sans/common/configurations.py
index 785aef0dc312ee65e6eb24e2a04efdd5cdea5bc3..636969c281f253c716660037086479ccf08d9657 100644
--- a/scripts/SANS/sans/common/configurations.py
+++ b/scripts/SANS/sans/common/configurations.py
@@ -24,3 +24,8 @@ class Configurations(object):
         # The default prompt peak range for LOQ
         prompt_peak_correction_min = 19000.0
         prompt_peak_correction_max = 20500.0
+
+    class ZOOM(object):
+        # The full wavelength range of the instrument
+        wavelength_full_range_low = 1.75
+        wavelength_full_range_high = 16.5
diff --git a/scripts/SANS/sans/common/constants.py b/scripts/SANS/sans/common/constants.py
index b58a773eaabc9f10432cf006978c257abe2428e9..b40bf3680ce3944242de593a2996924b7cb5d906 100644
--- a/scripts/SANS/sans/common/constants.py
+++ b/scripts/SANS/sans/common/constants.py
@@ -34,6 +34,7 @@ LOW_ANGLE_BANK = "LAB"
 SANS2D = "SANS2D"
 LARMOR = "LARMOR"
 LOQ = "LOQ"
+ZOOM = "ZOOM"
 
 REDUCED_WORKSPACE_BASE_NAME_IN_LOGS = "reduced_workspace_base_name"
 REDUCED_WORKSPACE_NAME_BY_USER_IN_LOGS = "reduced_workspace_name_by_user"
diff --git a/scripts/SANS/sans/common/enums.py b/scripts/SANS/sans/common/enums.py
index 35821dbe081f9e4a2983f453e6e5626c71ce68a9..12f797158a83ba1e2d34fcd73873844dd2a4ff9e 100644
--- a/scripts/SANS/sans/common/enums.py
+++ b/scripts/SANS/sans/common/enums.py
@@ -81,7 +81,7 @@ def string_convertible(cls):
 #  Instrument and facility types
 # --------------------------------
 @string_convertible
-@serializable_enum("LOQ", "LARMOR", "SANS2D", "NoInstrument")
+@serializable_enum("LOQ", "LARMOR", "SANS2D", "ZOOM", "NoInstrument")
 class SANSInstrument(object):
     pass
 
@@ -120,6 +120,7 @@ class CanonicalCoordinates(Coordinates):
 # --------------------------
 #  ReductionMode
 # --------------------------
+@string_convertible
 @serializable_enum("Merged", "All")
 class ReductionMode(object):
     """
@@ -258,7 +259,7 @@ class SaveType(object):
 # Fit type for the transmission calculation
 # ------------------------------------------
 @string_convertible
-@serializable_enum("Linear", "Log", "Polynomial", "NoFit")
+@serializable_enum("Linear", "Logarithmic", "Polynomial", "NoFit")
 class FitType(object):
     """
     Defines possible fit types
@@ -269,6 +270,7 @@ class FitType(object):
 # --------------------------
 #  SampleShape
 # --------------------------
+@string_convertible
 @serializable_enum("CylinderAxisUp", "Cuboid", "CylinderAxisAlong")
 class SampleShape(object):
     """
diff --git a/scripts/SANS/sans/common/file_information.py b/scripts/SANS/sans/common/file_information.py
index 19725adef267b0c3a1bbe9016f34ccb5dc9c757b..5aa16665ab2b7607872fdfaa7fe71bb7f24d2c35 100644
--- a/scripts/SANS/sans/common/file_information.py
+++ b/scripts/SANS/sans/common/file_information.py
@@ -10,7 +10,7 @@ from mantid.api import FileFinder
 from mantid.kernel import (DateAndTime, ConfigService)
 from mantid.api import (AlgorithmManager, ExperimentInfo)
 from sans.common.enums import (SANSInstrument, FileType, SampleShape)
-from sans.common.constants import (SANS2D, LARMOR, LOQ)
+from sans.common.general_functions import (get_instrument, instrument_name_correction, get_facility)
 from six import with_metaclass
 
 
@@ -48,7 +48,6 @@ MANTID_WORKSPACE_PREFIX = 'mantid_workspace_'
 EVENT_WORKSPACE = "event_workspace"
 
 # Other
-ALTERNATIVE_SANS2D_NAME = "SAN"
 DEFINITION = "Definition"
 PARAMETERS = "Parameters"
 
@@ -95,6 +94,9 @@ def find_sans_file(file_name):
     """
     full_path = find_full_file_path(file_name)
     if not full_path:
+        # TODO: If we only provide a run number for example 98843 for LOQ measurments, but have LARMOR specified as the
+        #       Mantid instrument, then the FileFinder will search itself to death. This is a general Mantid issue.
+        #       One way to handle this graceful would be a timeout option.
         runs = FileFinder.findRuns(file_name)
         if runs:
             full_path = runs[0]
@@ -157,11 +159,13 @@ def is_multi_period(func, file_name):
     return is_file_type and number_of_periods >= 1
 
 
-def get_instrument_paths_for_sans_file(file_name):
+def get_instrument_paths_for_sans_file(file_name=None, file_information=None):
     """
     Gets the Instrument Definition File (IDF) path and the Instrument Parameter Path (IPF) path associated with a file.
 
-    :param file_name: the file name is a name fo a SANS data file, e.g. SANS2D0001234
+    :param file_name: the file name is a name fo a SANS data file, e.g. SANS2D0001234. This or the file_information
+                      has to be specified.
+    :param file_information: a file_information object. either this or the file_name has to be specified.
     :return: the IDF path and the IPF path
     """
     def get_file_location(path):
@@ -204,9 +208,11 @@ def get_instrument_paths_for_sans_file(file_name):
         return check_for_files(directory, path)
 
     # Get the measurement date
-    file_information_factory = SANSFileInformationFactory()
-    file_information = file_information_factory.create_sans_file_information(file_name)
+    if not isinstance(file_information, SANSFileInformation):
+        file_information_factory = SANSFileInformationFactory()
+        file_information = file_information_factory.create_sans_file_information(file_name)
     measurement_time = file_information.get_date()
+
     # For some odd reason the __str__ method of DateAndTime adds a space which we need to strip here. It seems
     # to be on purpose though since the export method is called IS08601StringPlusSpace --> hence we need to strip it
     # ourselves
@@ -217,6 +223,13 @@ def get_instrument_paths_for_sans_file(file_name):
     instrument_as_string = SANSInstrument.to_string(instrument)
 
     # Get the idf file path
+    # IMPORTANT NOTE: I profiled the call to ExperimentInfo.getInstrumentFilename and it dominates
+    #                 the state creation. Ironically this routine is exported from C++. The problem is
+    #                 that we are performing XML parsing on the C++ side, which is costly. There is a
+    #                 movement currently towards making the IDF redundant and storing instrument info
+    #                 as native nexus information.
+    # TODO for optimization: Add the IDF path to a global cache layer which takes the
+    #                        instrument name and the from-to dates
     idf_path = ExperimentInfo.getInstrumentFilename(instrument_as_string, measurement_time_as_string)
     idf_path = os.path.normpath(idf_path)
 
@@ -628,12 +641,9 @@ def get_from_raw_header(file_name, index):
     return element
 
 
-def instrument_name_correction(instrument_name):
-    return SANS2D if instrument_name == ALTERNATIVE_SANS2D_NAME else instrument_name
-
-
 def get_instrument_name_for_raw(file_name):
     instrument_name = get_from_raw_header(file_name, 0)
+    # We sometimes need an instrument name correction, eg SANS2D is sometimes stored as SAN
     return instrument_name_correction(instrument_name)
 
 
@@ -686,19 +696,6 @@ def get_date_for_raw(file_name):
     return get_raw_measurement_time(date, time)
 
 
-def get_instrument(instrument_name):
-    instrument_name = instrument_name.upper()
-    if instrument_name == SANS2D:
-        instrument = SANSInstrument.SANS2D
-    elif instrument_name == LARMOR:
-        instrument = SANSInstrument.LARMOR
-    elif instrument_name == LOQ:
-        instrument = SANSInstrument.LOQ
-    else:
-        instrument = SANSInstrument.NoInstrument
-    return instrument
-
-
 def get_geometry_information_raw(file_name):
     """
     Gets the geometry information form the table workspace with the spb information
@@ -734,9 +731,8 @@ def get_geometry_information_raw(file_name):
 # SANS file Information
 # ----------------------------------------------------------------------------------------------------------------------
 class SANSFileInformation(with_metaclass(ABCMeta, object)):
-    def __init__(self, file_name):
-        self._file_name = file_name
-        self._full_file_name = SANSFileInformation.get_full_file_name(self._file_name)
+    def __init__(self, full_file_name):
+        self._full_file_name = full_file_name
 
         # Idf and Ipf file path (will be loaded via lazy evaluation)
         self._idf_file_path = None
@@ -750,6 +746,10 @@ class SANSFileInformation(with_metaclass(ABCMeta, object)):
     def get_instrument(self):
         pass
 
+    @abstractmethod
+    def get_facility(self):
+        pass
+
     @abstractmethod
     def get_date(self):
         pass
@@ -792,14 +792,14 @@ class SANSFileInformation(with_metaclass(ABCMeta, object)):
 
     def get_idf_file_path(self):
         if self._idf_file_path is None:
-            idf_path, ipf_path = get_instrument_paths_for_sans_file(self._full_file_name)
+            idf_path, ipf_path = get_instrument_paths_for_sans_file(file_information=self)
             self._idf_file_path = idf_path
             self._ipf_file_path = ipf_path
         return self._idf_file_path
 
     def get_ipf_file_path(self):
         if self._ipf_file_path is None:
-            idf_path, ipf_path = get_instrument_paths_for_sans_file(self._full_file_name)
+            idf_path, ipf_path = get_instrument_paths_for_sans_file(file_information=self)
             self._idf_file_path = idf_path
             self._ipf_file_path = ipf_path
         return self._ipf_file_path
@@ -816,6 +816,9 @@ class SANSFileInformationISISNexus(SANSFileInformation):
         instrument_name = get_instrument_name_for_isis_nexus(self._full_file_name)
         self._instrument = SANSInstrument.from_string(instrument_name)
 
+        # Setup the facility
+        self._facility = get_facility(self._instrument)
+
         # Setup date
         self._date = get_date_for_isis_nexus(self._full_file_name)
 
@@ -841,6 +844,9 @@ class SANSFileInformationISISNexus(SANSFileInformation):
     def get_instrument(self):
         return self._instrument
 
+    def get_facility(self):
+        return self._facility
+
     def get_date(self):
         return self._date
 
@@ -877,7 +883,10 @@ class SANSFileInformationISISAdded(SANSFileInformation):
         super(SANSFileInformationISISAdded, self).__init__(file_name)
         # Setup instrument name
         instrument_name = get_instrument_name_for_isis_nexus(self._full_file_name)
-        self._instrument_name = get_instrument(instrument_name)
+        self._instrument = get_instrument(instrument_name)
+
+        # Setup the facility
+        self._facility = get_facility(self._instrument)
 
         date, run_number = get_date_and_run_number_added_nexus(self._full_file_name)
         self._date = date
@@ -898,7 +907,10 @@ class SANSFileInformationISISAdded(SANSFileInformation):
         return self._full_file_name
 
     def get_instrument(self):
-        return self._instrument_name
+        return self._instrument
+
+    def get_facility(self):
+        return self._facility
 
     def get_date(self):
         return self._date
@@ -938,6 +950,9 @@ class SANSFileInformationRaw(SANSFileInformation):
         instrument_name = get_instrument_name_for_raw(self._full_file_name)
         self._instrument = SANSInstrument.from_string(instrument_name)
 
+        # Setup the facility
+        self._facility = get_facility(self._instrument)
+
         # Setup date
         self._date = get_date_for_raw(self._full_file_name)
 
@@ -961,6 +976,9 @@ class SANSFileInformationRaw(SANSFileInformation):
     def get_instrument(self):
         return self._instrument
 
+    def get_facility(self):
+        return self._facility
+
     def get_date(self):
         return self._date
 
@@ -997,6 +1015,7 @@ class SANSFileInformationFactory(object):
         super(SANSFileInformationFactory, self).__init__()
 
     def create_sans_file_information(self, file_name):
+
         full_file_name = find_sans_file(file_name)
         if is_isis_nexus_single_period(full_file_name) or is_isis_nexus_multi_period(full_file_name):
             file_information = SANSFileInformationISISNexus(full_file_name)
diff --git a/scripts/SANS/sans/common/general_functions.py b/scripts/SANS/sans/common/general_functions.py
index 87b2b1242fe06cbca59286dfcf02b6572317422c..19d4fbeb6af5772de0dc0681ed2a59d44fa7ded2 100644
--- a/scripts/SANS/sans/common/general_functions.py
+++ b/scripts/SANS/sans/common/general_functions.py
@@ -8,11 +8,16 @@ import re
 from copy import deepcopy
 import json
 from mantid.api import (AlgorithmManager, AnalysisDataService, isSameWorkspaceObject)
-from sans.common.constants import (SANS_FILE_TAG, ALL_PERIODS, SANS2D, LOQ, LARMOR, EMPTY_NAME,
+from sans.common.constants import (SANS_FILE_TAG, ALL_PERIODS, SANS2D, LOQ, LARMOR, ZOOM, EMPTY_NAME,
                                    REDUCED_CAN_TAG)
 from sans.common.log_tagger import (get_tag, has_tag, set_tag, has_hash, get_hash_value, set_hash)
 from sans.common.enums import (DetectorType, RangeStepType, ReductionDimensionality, OutputParts, ISISReductionMode,
-                               SANSInstrument)
+                               SANSInstrument, SANSFacility)
+
+# -------------------------------------------
+# Constants
+# -------------------------------------------
+ALTERNATIVE_SANS2D_NAME = "SAN"
 
 
 # -------------------------------------------
@@ -274,6 +279,7 @@ def convert_bank_name_to_detector_type_isis(detector_name):
             HAB                -> HAB
             but also allowed main
     LARMOR: DetectorBench      -> LAB
+    ZOOM:   rear-detector -> LAB
 
     :param detector_name: a string with a valid detector name
     :return: a detector type depending on the input string, or a runtime exception.
@@ -291,6 +297,20 @@ def convert_bank_name_to_detector_type_isis(detector_name):
     return detector_type
 
 
+def convert_instrument_and_detector_type_to_bank_name(instrument, detector_type):
+    if instrument is SANSInstrument.SANS2D:
+        bank_name = "front-detector" if detector_type is DetectorType.HAB else "rear-detector"
+    elif instrument is SANSInstrument.LOQ:
+        bank_name = "HAB" if detector_type is DetectorType.HAB else "main-detector-bank"
+    elif instrument is SANSInstrument.LARMOR:
+        bank_name = "DetectorBench"
+    elif instrument is SANSInstrument.ZOOM:
+        bank_name = "rear-detector"
+    else:
+        raise RuntimeError("SANSCrop: The instrument {0} is currently not supported.".format(instrument))
+    return bank_name
+
+
 def is_part_of_reduced_output_workspace_group(state):
     """
     Check if this state will generate a WorkspaceGroup as the output.
@@ -661,9 +681,41 @@ def sanitise_instrument_name(instrument_name):
         instrument_name = SANS2D
     elif re.search(LARMOR, instrument_name_upper):
         instrument_name = LARMOR
+    elif re.search(ZOOM, instrument_name_upper):
+        instrument_name = ZOOM
     return instrument_name
 
 
+def get_facility(instrument):
+    if (instrument is SANSInstrument.SANS2D or instrument is SANSInstrument.LOQ or
+        instrument is SANSInstrument.LARMOR or instrument is SANSInstrument.ZOOM):  # noqa
+        return SANSFacility.ISIS
+    else:
+        return SANSFacility.NoFacility
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# Other
+# ----------------------------------------------------------------------------------------------------------------------
+def instrument_name_correction(instrument_name):
+    return SANS2D if instrument_name == ALTERNATIVE_SANS2D_NAME else instrument_name
+
+
+def get_instrument(instrument_name):
+    instrument_name = instrument_name.upper()
+    if instrument_name == SANS2D:
+        instrument = SANSInstrument.SANS2D
+    elif instrument_name == LARMOR:
+        instrument = SANSInstrument.LARMOR
+    elif instrument_name == LOQ:
+        instrument = SANSInstrument.LOQ
+    elif instrument_name == ZOOM:
+        instrument = SANSInstrument.ZOOM
+    else:
+        instrument = SANSInstrument.NoInstrument
+    return instrument
+
+
 # ----------------------------------------------------------------------------------------------------------------------
 # Hashing + ADS
 # ----------------------------------------------------------------------------------------------------------------------
diff --git a/scripts/SANS/sans/gui_logic/__init__.py b/scripts/SANS/sans/gui_logic/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/scripts/SANS/sans/gui_logic/gui_common.py b/scripts/SANS/sans/gui_logic/gui_common.py
new file mode 100644
index 0000000000000000000000000000000000000000..5ff232601326771a28bb8ab0ef2f399d138abafb
--- /dev/null
+++ b/scripts/SANS/sans/gui_logic/gui_common.py
@@ -0,0 +1,75 @@
+from sans.common.enums import SANSInstrument, ISISReductionMode
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# Option column globals
+# ----------------------------------------------------------------------------------------------------------------------
+OPTIONS_INDEX = 7
+OPTIONS_SEPARATOR = ","
+OPTIONS_EQUAL = "="
+HIDDEN_OPTIONS_INDEX = 8
+
+# ----------------------------------------------------------------------------------------------------------------------
+#  Other Globals
+# ----------------------------------------------------------------------------------------------------------------------
+SANS2D_LAB = "rear"
+SANS2D_HAB = "front"
+
+LOQ_LAB = "main-detector"
+LOQ_HAB = "Hab"
+
+LARMOR_LAB = "DetectorBench"
+
+DEFAULT_LAB = ISISReductionMode.to_string(ISISReductionMode.LAB)
+DEFAULT_HAB = ISISReductionMode.to_string(ISISReductionMode.HAB)
+MERGED = "Merged"
+ALL = "All"
+
+
+def get_reduction_mode_strings_for_gui(instrument=None):
+    if instrument is SANSInstrument.SANS2D:
+        return [SANS2D_LAB, SANS2D_HAB, MERGED, ALL]
+    elif instrument is SANSInstrument.LOQ:
+        return [LOQ_LAB, LOQ_HAB, MERGED, ALL]
+    elif instrument is SANSInstrument.LARMOR:
+        return [LARMOR_LAB]
+    else:
+        return [DEFAULT_LAB, DEFAULT_HAB, MERGED, ALL]
+
+
+def get_reduction_selection(instrument):
+    selection = {ISISReductionMode.Merged: MERGED,
+                 ISISReductionMode.All: ALL}
+    if instrument is SANSInstrument.SANS2D:
+        selection.update({ISISReductionMode.LAB: SANS2D_LAB,
+                          ISISReductionMode.HAB: SANS2D_HAB})
+    elif instrument is SANSInstrument.LOQ:
+        selection.update({ISISReductionMode.LAB: LOQ_LAB,
+                          ISISReductionMode.HAB: LOQ_HAB})
+    elif instrument is SANSInstrument.LARMOR:
+        selection = {ISISReductionMode.LAB: LARMOR_LAB}
+    else:
+        selection.update({ISISReductionMode.LAB: DEFAULT_LAB,
+                          ISISReductionMode.HAB: DEFAULT_HAB})
+    return selection
+
+
+def get_string_for_gui_from_reduction_mode(reduction_mode, instrument):
+    reduction_selection = get_reduction_selection(instrument)
+    if reduction_selection and reduction_mode in list(reduction_selection.keys()):
+        return reduction_selection[reduction_mode]
+    else:
+        return None
+
+
+def get_reduction_mode_from_gui_selection(gui_selection):
+    if gui_selection == MERGED:
+        return ISISReductionMode.Merged
+    elif gui_selection == ALL:
+        return ISISReductionMode.All
+    elif gui_selection == SANS2D_LAB or gui_selection == LOQ_LAB or gui_selection == LARMOR_LAB or gui_selection == DEFAULT_LAB:  # noqa
+        return ISISReductionMode.LAB
+    elif gui_selection == SANS2D_HAB or gui_selection == LOQ_HAB:
+        return ISISReductionMode.HAB
+    else:
+        raise RuntimeError("Reduction mode selection is not valid.")
diff --git a/scripts/SANS/sans/gui_logic/models/__init__.py b/scripts/SANS/sans/gui_logic/models/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/scripts/SANS/sans/gui_logic/models/state_gui_model.py b/scripts/SANS/sans/gui_logic/models/state_gui_model.py
new file mode 100644
index 0000000000000000000000000000000000000000..794ce25d9b139a7986c4752a99ba0e22e345ff5a
--- /dev/null
+++ b/scripts/SANS/sans/gui_logic/models/state_gui_model.py
@@ -0,0 +1,997 @@
+""" The state gui model contains all the reduction information which is not explictily available in the data table.
+
+This is one of the two models which is used for the data reduction. It contains generally all the settings which
+are not available in the model associated with the data table.
+"""
+
+from __future__ import (absolute_import, division, print_function)
+
+from sans.user_file.settings_tags import (OtherId, DetectorId, LimitsId, SetId, SampleId, MonId, TransId, GravityId,
+                                          QResolutionId, FitId, event_binning_string_values, set_scales_entry,
+                                          monitor_spectrum, simple_range, monitor_file, det_fit_range,
+                                          q_rebin_values, fit_general, mask_angle_entry, range_entry)
+from sans.common.enums import (ReductionDimensionality, ISISReductionMode, RangeStepType, SaveType,
+                               DetectorType, DataType, FitType)
+
+
+class StateGuiModel(object):
+    def __init__(self, user_file_items):
+        super(StateGuiModel, self).__init__()
+        self._user_file_items = user_file_items
+
+    @property
+    def settings(self):
+        return self._user_file_items
+
+    def get_simple_element(self, element_id, default_value):
+        return self.get_simple_element_with_attribute(element_id, default_value)
+
+    def set_simple_element(self, element_id, value):
+        if element_id in self._user_file_items:
+            del self._user_file_items[element_id]
+        new_state_entries = {element_id: [value]}
+        self._user_file_items.update(new_state_entries)
+
+    def get_simple_element_with_attribute(self, element_id, default_value, attribute=None):
+        if element_id in self._user_file_items:
+            element = self._user_file_items[element_id][-1]
+            return getattr(element, attribute) if attribute else element
+        else:
+            return default_value
+
+    # ==================================================================================================================
+    # ==================================================================================================================
+    # FRONT TAB
+    # ==================================================================================================================
+    # ==================================================================================================================
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Compatibility Mode Options
+    # ------------------------------------------------------------------------------------------------------------------
+    @property
+    def compatibility_mode(self):
+        return self.get_simple_element(element_id=OtherId.use_compatibility_mode, default_value=False)
+
+    @compatibility_mode.setter
+    def compatibility_mode(self, value):
+        self.set_simple_element(element_id=OtherId.use_compatibility_mode, value=value)
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Save Options
+    # ------------------------------------------------------------------------------------------------------------------
+    @property
+    def zero_error_free(self):
+        if OtherId.save_as_zero_error_free in self._user_file_items:
+            return self._user_file_items[OtherId.save_as_zero_error_free][-1]
+        else:
+            # Turn on zero error free saving by default
+            return True
+
+    @zero_error_free.setter
+    def zero_error_free(self, value):
+        if value is None:
+            return
+        if OtherId.save_as_zero_error_free in self._user_file_items:
+            del self._user_file_items[OtherId.save_as_zero_error_free]
+        new_state_entries = {OtherId.save_as_zero_error_free: [value]}
+        self._user_file_items.update(new_state_entries)
+
+    @property
+    def save_types(self):
+        return self.get_simple_element(element_id=OtherId.save_types, default_value=[SaveType.NXcanSAS])
+
+    @save_types.setter
+    def save_types(self, value):
+        self.set_simple_element(element_id=OtherId.save_types, value=value)
+
+    # ==================================================================================================================
+    # ==================================================================================================================
+    # General TAB
+    # ==================================================================================================================
+    # ==================================================================================================================
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Event slices
+    # ------------------------------------------------------------------------------------------------------------------
+    @property
+    def event_slices(self):
+        return self.get_simple_element_with_attribute(element_id=OtherId.event_slices,
+                                                      default_value="",
+                                                      attribute="value")
+
+    @event_slices.setter
+    def event_slices(self, value):
+        if not value:
+            return
+        if OtherId.event_slices in self._user_file_items:
+            del self._user_file_items[OtherId.event_slices]
+        new_state_entries = {OtherId.event_slices: [event_binning_string_values(value=value)]}
+        self._user_file_items.update(new_state_entries)
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Reduction dimensionality
+    # ------------------------------------------------------------------------------------------------------------------
+    @property
+    def reduction_dimensionality(self):
+        return self.get_simple_element_with_attribute(element_id=OtherId.reduction_dimensionality,
+                                                      default_value=ReductionDimensionality.OneDim)
+
+    @reduction_dimensionality.setter
+    def reduction_dimensionality(self, value):
+        if value is ReductionDimensionality.OneDim or value is ReductionDimensionality.TwoDim:
+            if OtherId.reduction_dimensionality in self._user_file_items:
+                del self._user_file_items[OtherId.reduction_dimensionality]
+            new_state_entries = {OtherId.reduction_dimensionality: [value]}
+            self._user_file_items.update(new_state_entries)
+        else:
+            raise ValueError("A reduction dimensionality was expected, got instead {}".format(value))
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Reduction Mode
+    # ------------------------------------------------------------------------------------------------------------------
+    def _update_merged_fit(self, element_id, use_fit=None, use_q_range=None, q_start=None, q_stop=None):
+        # If the setting is not in there, then add, else all is good
+        if element_id in self._user_file_items:
+            settings = self._user_file_items[element_id]
+        else:
+            settings = [det_fit_range(start=None, stop=None, use_fit=False)]
+
+        new_settings = []
+        for setting in settings:
+            new_use_fit = use_fit if use_fit is not None else setting.use_fit
+            new_q_start = q_start if q_start is not None else setting.start
+            new_q_stop = q_stop if q_stop is not None else setting.stop
+
+            # If we don't want to use a custom q range, then we need to set the start and stop values to None
+            if use_q_range is not None and use_q_range is False:
+                new_q_start = None
+                new_q_stop = None
+
+            new_settings.append(det_fit_range(start=new_q_start, stop=new_q_stop, use_fit=new_use_fit))
+        self._user_file_items.update({element_id: new_settings})
+
+    def get_merge_range(self, default_value):
+        q_start = []
+        q_stop = []
+
+        settings = []
+        if DetectorId.rescale_fit in self._user_file_items:
+            settings.extend(self._user_file_items[DetectorId.rescale_fit])
+        if DetectorId.shift_fit in self._user_file_items:
+            settings.extend(self._user_file_items[DetectorId.shift_fit])
+
+        for setting in settings:
+            if setting.start is not None:
+                q_start.append(setting.start)
+
+            if setting.stop is not None:
+                q_stop.append(setting.stop)
+
+        q_range_start = min(q_start) if q_start else default_value
+        q_range_stop = max(q_stop) if q_stop else default_value
+        return q_range_start, q_range_stop
+
+    @property
+    def reduction_mode(self):
+        return self.get_simple_element_with_attribute(element_id=DetectorId.reduction_mode,
+                                                      default_value=ISISReductionMode.LAB)
+
+    @reduction_mode.setter
+    def reduction_mode(self, value):
+        if (value is ISISReductionMode.LAB or value is ISISReductionMode.HAB or
+            value is ISISReductionMode.Merged or value is ISISReductionMode.All):  # noqa
+            if DetectorId.reduction_mode in self._user_file_items:
+                del self._user_file_items[DetectorId.reduction_mode]
+            new_state_entries = {DetectorId.reduction_mode: [value]}
+            self._user_file_items.update(new_state_entries)
+        else:
+            raise ValueError("A reduction mode was expected, got instead {}".format(value))
+
+    @property
+    def merge_scale(self):
+        return self.get_simple_element(element_id=DetectorId.rescale, default_value="")
+
+    @merge_scale.setter
+    def merge_scale(self, value):
+        self.set_simple_element(element_id=DetectorId.rescale, value=value)
+
+    @property
+    def merge_shift(self):
+        return self.get_simple_element(element_id=DetectorId.shift, default_value="")
+
+    @merge_shift.setter
+    def merge_shift(self, value):
+        self.set_simple_element(element_id=DetectorId.shift, value=value)
+
+    @property
+    def merge_scale_fit(self):
+        return self.get_simple_element_with_attribute(element_id=DetectorId.rescale_fit,
+                                                      default_value=False,
+                                                      attribute="use_fit")
+
+    @merge_scale_fit.setter
+    def merge_scale_fit(self, value):
+        self._update_merged_fit(element_id=DetectorId.rescale_fit, use_fit=value)
+
+    @property
+    def merge_shift_fit(self):
+        return self.get_simple_element_with_attribute(element_id=DetectorId.shift_fit,
+                                                      default_value=False,
+                                                      attribute="use_fit")
+
+    @merge_shift_fit.setter
+    def merge_shift_fit(self, value):
+        self._update_merged_fit(element_id=DetectorId.shift_fit, use_fit=value)
+
+    @property
+    def merge_q_range_start(self):
+        q_range_start, _ = self.get_merge_range(default_value="")
+        return q_range_start
+
+    @merge_q_range_start.setter
+    def merge_q_range_start(self, value):
+        # Update for the shift
+        self._update_merged_fit(element_id=DetectorId.shift_fit, q_start=value)
+        # Update for the scale
+        self._update_merged_fit(element_id=DetectorId.rescale_fit, q_start=value)
+
+    @property
+    def merge_q_range_stop(self):
+        _, q_range_stop = self.get_merge_range(default_value="")
+        return q_range_stop
+
+    @merge_q_range_stop.setter
+    def merge_q_range_stop(self, value):
+        # Update for the shift
+        self._update_merged_fit(element_id=DetectorId.shift_fit, q_stop=value)
+        # Update for the scale
+        self._update_merged_fit(element_id=DetectorId.rescale_fit, q_stop=value)
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Event binning for compatibility mode
+    # ------------------------------------------------------------------------------------------------------------------
+    @property
+    def event_binning(self):
+        return self.get_simple_element(element_id=LimitsId.events_binning, default_value="")
+
+    @event_binning.setter
+    def event_binning(self, value):
+        self.set_simple_element(element_id=LimitsId.events_binning, value=value)
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Wavelength properties
+    # Note that the wavelength settings are being used in four sub-states:
+    # - wavelength
+    # - calculate_transmission
+    # - normalize_to_monitor
+    # - wavelength_and_pixel_adjustment
+    # This is not something that needs to be known at this point, but it is good to know.
+    # ------------------------------------------------------------------------------------------------------------------
+    def _update_wavelength(self, min_value=None, max_value=None, step=None, step_type=None):
+        if LimitsId.wavelength in self._user_file_items:
+            settings = self._user_file_items[LimitsId.wavelength]
+        else:
+            # If the entry does not already exist, then add it. The -1. is an illegal input which should get overriden
+            # and if not we want it to fail.
+            settings = [simple_range(start=-1., stop=-1., step=-1., step_type=RangeStepType.Lin)]
+
+        new_settings = []
+        for setting in settings:
+            new_min = min_value if min_value else setting.start
+            new_max = max_value if max_value else setting.stop
+            new_step = step if step else setting.step
+            new_step_type = step_type if step_type else setting.step_type
+            new_setting = simple_range(start=new_min, stop=new_max, step=new_step, step_type=new_step_type)
+            new_settings.append(new_setting)
+        self._user_file_items.update({LimitsId.wavelength: new_settings})
+
+    @property
+    def wavelength_step_type(self):
+        return self.get_simple_element_with_attribute(element_id=LimitsId.wavelength, default_value=RangeStepType.Lin,
+                                                      attribute="step_type")
+
+    @wavelength_step_type.setter
+    def wavelength_step_type(self, value):
+        self._update_wavelength(step_type=value)
+
+    @property
+    def wavelength_min(self):
+        return self.get_simple_element_with_attribute(element_id=LimitsId.wavelength,
+                                                      default_value="",
+                                                      attribute="start")
+
+    @wavelength_min.setter
+    def wavelength_min(self, value):
+        self._update_wavelength(min_value=value)
+
+    @property
+    def wavelength_max(self):
+        return self.get_simple_element_with_attribute(element_id=LimitsId.wavelength,
+                                                      default_value="",
+                                                      attribute="stop")
+
+    @wavelength_max.setter
+    def wavelength_max(self, value):
+        self._update_wavelength(max_value=value)
+
+    @property
+    def wavelength_step(self):
+        return self.get_simple_element_with_attribute(element_id=LimitsId.wavelength,
+                                                      default_value="",
+                                                      attribute="step")
+
+    @wavelength_step.setter
+    def wavelength_step(self, value):
+        self._update_wavelength(step=value)
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Scale properties
+    # While the absolute scale can be set in the
+    # ------------------------------------------------------------------------------------------------------------------
+    @property
+    def absolute_scale(self):
+        return self.get_simple_element_with_attribute(element_id=SetId.scales,
+                                                      default_value="",
+                                                      attribute="s")
+
+    @absolute_scale.setter
+    def absolute_scale(self, value):
+        if SetId.scales in self._user_file_items:
+            settings = self._user_file_items[SetId.scales]
+        else:
+            settings = [set_scales_entry(s=100., a=0., b=0., c=0., d=0.)]
+
+        new_settings = []
+        for setting in settings:
+            s_parameter = value if value else setting.s
+            new_settings.append(set_scales_entry(s=s_parameter, a=0., b=0., c=0., d=0.))
+        self._user_file_items.update({SetId.scales: new_settings})
+
+    @property
+    def sample_height(self):
+        return self.get_simple_element(element_id=OtherId.sample_height, default_value="")
+
+    @sample_height.setter
+    def sample_height(self, value):
+        self.set_simple_element(element_id=OtherId.sample_height, value=value)
+
+    @property
+    def sample_width(self):
+        return self.get_simple_element(element_id=OtherId.sample_width, default_value="")
+
+    @sample_width.setter
+    def sample_width(self, value):
+        self.set_simple_element(element_id=OtherId.sample_width, value=value)
+
+    @property
+    def sample_thickness(self):
+        return self.get_simple_element(element_id=OtherId.sample_thickness, default_value="")
+
+    @sample_thickness.setter
+    def sample_thickness(self, value):
+        self.set_simple_element(element_id=OtherId.sample_thickness, value=value)
+
+    @property
+    def sample_shape(self):
+        return self.get_simple_element(element_id=OtherId.sample_shape, default_value=None)
+
+    @sample_shape.setter
+    def sample_shape(self, value):
+        # We only set the value if it is not None. Note that it can be None if the sample shape selection
+        #  is "Read from file"
+        if value is not None:
+            self.set_simple_element(element_id=OtherId.sample_shape, value=value)
+
+    @property
+    def z_offset(self):
+        return self.get_simple_element(element_id=SampleId.offset, default_value="")
+
+    @z_offset.setter
+    def z_offset(self, value):
+        self.set_simple_element(element_id=SampleId.offset, value=value)
+
+    # ==================================================================================================================
+    # ==================================================================================================================
+    # ADJUSTMENT TAB
+    # ==================================================================================================================
+    # ==================================================================================================================
+    def _update_incident_spectrum_info(self, spectrum=None, interpolate=None, is_trans=False):
+        if MonId.spectrum in self._user_file_items:
+            settings = self._user_file_items[MonId.spectrum]
+        else:
+            # If the entry does not already exist, then add it. The -1. is an illegal input which should get overridden
+            # and if not we want it to fail.
+            settings = [monitor_spectrum(spectrum=-1, is_trans=is_trans, interpolate=is_trans)]
+
+        new_settings = []
+        for setting in settings:
+            # Only modify the settings which match the is_trans, selection. Else we muddle up the normalize to monitor
+            # settings with the transmission settings.
+            if setting.is_trans == is_trans:
+                new_spectrum = spectrum if spectrum else setting.spectrum
+                new_interpolate = interpolate if interpolate else setting.interpolate
+                new_setting = monitor_spectrum(spectrum=new_spectrum, is_trans=is_trans,
+                                               interpolate=new_interpolate)
+                new_settings.append(new_setting)
+            else:
+                new_settings.append(setting)
+        self._user_file_items.update({MonId.spectrum: new_settings})
+
+    def _get_incident_spectrum_info(self, default_value, attribute, is_trans):
+        if MonId.spectrum in self._user_file_items:
+            settings = self._user_file_items[MonId.spectrum]
+            if is_trans:
+                settings = [setting for setting in settings if setting.is_trans]
+            else:
+                settings = [setting for setting in settings if not setting.is_trans]
+            element = settings[-1]
+            return getattr(element, attribute)
+        else:
+            return default_value
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Monitor normalization
+    # ------------------------------------------------------------------------------------------------------------------
+    @property
+    def normalization_incident_monitor(self):
+        return self._get_incident_spectrum_info(default_value="", attribute="spectrum", is_trans=False)
+
+    @normalization_incident_monitor.setter
+    def normalization_incident_monitor(self, value):
+        self._update_incident_spectrum_info(spectrum=value, is_trans=False)
+
+    @property
+    def normalization_interpolate(self):
+        return self._get_incident_spectrum_info(default_value=False, attribute="interpolate", is_trans=False)
+
+    @normalization_interpolate.setter
+    def normalization_interpolate(self, value):
+        self._update_incident_spectrum_info(interpolate=value, is_trans=False)
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Transmission
+    # ------------------------------------------------------------------------------------------------------------------
+    @property
+    def transmission_incident_monitor(self):
+        return self._get_incident_spectrum_info(default_value="", attribute="spectrum", is_trans=True)
+
+    @transmission_incident_monitor.setter
+    def transmission_incident_monitor(self, value):
+        self._update_incident_spectrum_info(spectrum=value, is_trans=True)
+
+    @property
+    def transmission_interpolate(self):
+        return self._get_incident_spectrum_info(default_value=False, attribute="interpolate", is_trans=True)
+
+    @transmission_interpolate.setter
+    def transmission_interpolate(self, value):
+        self._update_incident_spectrum_info(interpolate=value, is_trans=True)
+
+    @property
+    def transmission_roi_files(self):
+        return self.get_simple_element(element_id=TransId.roi, default_value="")
+
+    @transmission_roi_files.setter
+    def transmission_roi_files(self, value):
+        self.set_simple_element(element_id=TransId.roi, value=value)
+
+    @property
+    def transmission_mask_files(self):
+        return self.get_simple_element(element_id=TransId.mask, default_value="")
+
+    @transmission_mask_files.setter
+    def transmission_mask_files(self, value):
+        self.set_simple_element(element_id=TransId.mask, value=value)
+
+    @property
+    def transmission_radius(self):
+        return self.get_simple_element(element_id=TransId.radius, default_value="")
+
+    @transmission_radius.setter
+    def transmission_radius(self, value):
+        self.set_simple_element(element_id=TransId.radius, value=value)
+
+    @property
+    def transmission_monitor(self):
+        return self.get_simple_element(element_id=TransId.spec, default_value=3)
+
+    @transmission_monitor.setter
+    def transmission_monitor(self, value):
+        self.set_simple_element(element_id=TransId.spec, value=value)
+
+    @property
+    def transmission_m4_shift(self):
+        # Note that this is actually part of the move operation, but is conceptually part of transmission
+        return self.get_simple_element(element_id=TransId.spec_shift, default_value="")
+
+    @transmission_m4_shift.setter
+    def transmission_m4_shift(self, value):
+        # Note that this is actually part of the move operation, but is conceptually part of transmission
+        self.set_simple_element(element_id=TransId.spec_shift, value=value)
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Fit
+    # ------------------------------------------------------------------------------------------------------------------
+    def _get_transmission_fit(self, data_type, attribute, default_value):
+        if FitId.general in self._user_file_items:
+            settings = self._user_file_items[FitId.general]
+            # Check first if there are data type specific settings, else check if there are general settings
+            extracted_settings = [setting for setting in settings if setting.data_type is data_type]
+            if not extracted_settings:
+                extracted_settings = [setting for setting in settings if setting.data_type is None]
+            if extracted_settings:
+                setting = extracted_settings[-1]
+                return getattr(setting, attribute)
+        return default_value
+
+    def _set_transmission_fit(self, data_type, start=None, stop=None, fit_type=None, polynomial_order=None):
+        if FitId.general in self._user_file_items:
+            # Gather all settings which correspond to the data type and where the data type is none
+            settings = self._user_file_items[FitId.general]
+            settings_general = [setting for setting in settings if setting.data_type is None]
+            settings_for_data_type = [setting for setting in settings if setting.data_type is data_type]
+            # We check if there are data-type specific settings.
+            # 1. There are data type specific settings. Then we are good.
+            # 2. There are no data type specific settings. We create one data type specific setting and populate it
+            #    with a general setting if it exists else we create a new entry
+            if not settings_for_data_type:
+                if settings_general:
+                    setting_general = settings_general[-1]
+                    settings.append(fit_general(start=setting_general.start, stop=setting_general.stop,
+                                                data_type=data_type, fit_type=setting_general.fit_type,
+                                                polynomial_order=setting_general.polynomial_order))
+                else:
+                    settings.append(fit_general(start=None, stop=None, data_type=data_type,
+                                                fit_type=FitType.NoFit, polynomial_order=2))
+        else:
+            settings = [fit_general(start=None, stop=None, data_type=data_type,
+                                    fit_type=FitType.NoFit, polynomial_order=2)]
+
+        new_settings = []
+        for setting in settings:
+            # We only want to modify the settings which are either the data type specific ones or the ones which
+            # don't have a specific data type
+            if setting.data_type is data_type and setting.data_type is not None:
+                new_start = start if start is not None else setting.start
+                new_stop = stop if stop is not None else setting.stop
+                new_fit_type = fit_type if fit_type is not None else setting.fit_type
+                new_polynomial_order = polynomial_order if polynomial_order is not None else setting.polynomial_order
+                new_settings.append(fit_general(start=new_start, stop=new_stop, fit_type=new_fit_type,
+                                                data_type=setting.data_type, polynomial_order=new_polynomial_order))
+            else:
+                new_settings.append(setting)
+        self._user_file_items.update({FitId.general: new_settings})
+
+    def has_transmission_fit_got_separate_settings_for_sample_and_can(self):
+        if FitId.general in self._user_file_items:
+            settings = self._user_file_items[FitId.general]
+            if settings:
+                settings_sample = [setting for setting in settings if setting.data_type is DataType.Sample]
+                settings_can = [setting for setting in settings if setting.data_type is DataType.Can]
+                # If we have either one or the other
+                if settings_sample or settings_can:
+                    return True
+        return False
+
+    @property
+    def transmission_sample_fit_type(self):
+        return self._get_transmission_fit(data_type=DataType.Sample, attribute="fit_type", default_value=FitType.NoFit)
+
+    @transmission_sample_fit_type.setter
+    def transmission_sample_fit_type(self, value):
+        self._set_transmission_fit(data_type=DataType.Sample, fit_type=value)
+
+    @property
+    def transmission_can_fit_type(self):
+        return self._get_transmission_fit(data_type=DataType.Can, attribute="fit_type", default_value=FitType.NoFit)
+
+    @transmission_can_fit_type.setter
+    def transmission_can_fit_type(self, value):
+        self._set_transmission_fit(data_type=DataType.Can, fit_type=value)
+
+    @property
+    def transmission_sample_polynomial_order(self):
+        return self._get_transmission_fit(data_type=DataType.Sample, attribute="polynomial_order",
+                                          default_value=2)
+
+    @transmission_sample_polynomial_order.setter
+    def transmission_sample_polynomial_order(self, value):
+        self._set_transmission_fit(data_type=DataType.Sample, polynomial_order=value)
+
+    @property
+    def transmission_can_polynomial_order(self):
+        return self._get_transmission_fit(data_type=DataType.Can, attribute="polynomial_order",
+                                          default_value=2)
+
+    @transmission_can_polynomial_order.setter
+    def transmission_can_polynomial_order(self, value):
+        self._set_transmission_fit(data_type=DataType.Can, polynomial_order=value)
+
+    @property
+    def transmission_sample_wavelength_min(self):
+        return self._get_transmission_fit(data_type=DataType.Sample, attribute="start", default_value="")
+
+    @transmission_sample_wavelength_min.setter
+    def transmission_sample_wavelength_min(self, value):
+        self._set_transmission_fit(data_type=DataType.Sample, start=value)
+
+    @property
+    def transmission_sample_wavelength_max(self):
+        return self._get_transmission_fit(data_type=DataType.Sample, attribute="stop", default_value="")
+
+    @transmission_sample_wavelength_max.setter
+    def transmission_sample_wavelength_max(self, value):
+        self._set_transmission_fit(data_type=DataType.Sample, stop=value)
+
+    @property
+    def transmission_can_wavelength_min(self):
+        return self._get_transmission_fit(data_type=DataType.Can, attribute="start", default_value="")
+
+    @transmission_can_wavelength_min.setter
+    def transmission_can_wavelength_min(self, value):
+        self._set_transmission_fit(data_type=DataType.Can, start=value)
+
+    @property
+    def transmission_can_wavelength_max(self):
+        return self._get_transmission_fit(data_type=DataType.Can, attribute="stop", default_value="")
+
+    @transmission_can_wavelength_max.setter
+    def transmission_can_wavelength_max(self, value):
+        self._set_transmission_fit(data_type=DataType.Can, stop=value)
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Wavelength- and pixel-adjustment files
+    # ------------------------------------------------------------------------------------------------------------------
+    def _get_adjustment_file_setting(self, element_id, detector_type, default_value):
+        if element_id in self._user_file_items:
+            settings = self._user_file_items[element_id]
+
+            # Separate out the correct detector type
+            settings = [setting for setting in settings if setting.detector_type is detector_type]
+            if settings:
+                setting = settings[-1]
+                return setting.file_path
+        return default_value
+
+    def _set_adjustment_file_setting(self, element_id, detector_type, file_path):
+        # Check if we already have items for the particular detector type
+        settings_with_correct_detector = []
+        settings = []
+        if element_id in self._user_file_items:
+            settings = self._user_file_items[element_id]
+            settings_with_correct_detector = [setting for setting in settings if setting.detector_type is detector_type]
+
+        if not (settings and settings_with_correct_detector):
+            settings.append(monitor_file(file_path="", detector_type=detector_type))
+
+        # At this point we have settings with the desired detector type
+        new_settings = []
+        for setting in settings:
+            if setting.detector_type is detector_type:
+                new_settings.append(monitor_file(file_path=file_path, detector_type=setting.detector_type))
+            else:
+                new_settings.append(setting)
+        self._user_file_items.update({element_id: new_settings})
+
+    @property
+    def pixel_adjustment_det_1(self):
+        return self._get_adjustment_file_setting(element_id=MonId.flat, detector_type=DetectorType.LAB,
+                                                 default_value="")
+
+    @pixel_adjustment_det_1.setter
+    def pixel_adjustment_det_1(self, value):
+        self._set_adjustment_file_setting(element_id=MonId.flat, detector_type=DetectorType.LAB, file_path=value)
+
+    @property
+    def pixel_adjustment_det_2(self):
+        return self._get_adjustment_file_setting(element_id=MonId.flat, detector_type=DetectorType.HAB,
+                                                 default_value="")
+
+    @pixel_adjustment_det_2.setter
+    def pixel_adjustment_det_2(self, value):
+        self._set_adjustment_file_setting(element_id=MonId.flat, detector_type=DetectorType.HAB, file_path=value)
+
+    @property
+    def wavelength_adjustment_det_1(self):
+        return self._get_adjustment_file_setting(element_id=MonId.direct, detector_type=DetectorType.LAB,
+                                                 default_value="")
+
+    @wavelength_adjustment_det_1.setter
+    def wavelength_adjustment_det_1(self, value):
+        self._set_adjustment_file_setting(element_id=MonId.direct, detector_type=DetectorType.LAB, file_path=value)
+
+    @property
+    def wavelength_adjustment_det_2(self):
+        return self._get_adjustment_file_setting(element_id=MonId.direct, detector_type=DetectorType.HAB,
+                                                 default_value="")
+
+    @wavelength_adjustment_det_2.setter
+    def wavelength_adjustment_det_2(self, value):
+        self._set_adjustment_file_setting(element_id=MonId.direct, detector_type=DetectorType.HAB, file_path=value)
+
+    # ==================================================================================================================
+    # ==================================================================================================================
+    # Q TAB
+    # ==================================================================================================================
+    # ==================================================================================================================
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Q Limits
+    # ------------------------------------------------------------------------------------------------------------------
+    def _set_q_1d_limits(self, min_value=None, max_value=None, rebin_string=None):
+        element_id = LimitsId.q
+        if element_id in self._user_file_items:
+            settings = self._user_file_items[element_id]
+        else:
+            settings = [q_rebin_values(min=None, max=None, rebin_string=None)]
+
+        # At this point we have settings with the desired detector type
+        new_settings = []
+        for setting in settings:
+            new_min = min_value if min_value is not None else setting.min
+            new_max = max_value if max_value is not None else setting.max
+            new_rebin_string = rebin_string if rebin_string is not None else setting.rebin_string
+            new_settings.append(q_rebin_values(min=new_min, max=new_max, rebin_string=new_rebin_string))
+        self._user_file_items.update({element_id: new_settings})
+
+    def _set_q_xy_limits(self, stop_value=None, step_value=None, step_type_value=None):
+        element_id = LimitsId.qxy
+        if element_id in self._user_file_items:
+            settings = self._user_file_items[element_id]
+        else:
+            settings = [simple_range(start=None, stop=None, step=None, step_type=None)]
+
+        # At this point we have settings with the desired detector type
+        new_settings = []
+        for setting in settings:
+            new_stop = stop_value if stop_value is not None else setting.stop
+            new_step = step_value if step_value is not None else setting.step
+            new_step_type_value = step_type_value if step_type_value is not None else setting.step_type
+            new_settings.append(simple_range(start=None, stop=new_stop, step=new_step, step_type=new_step_type_value))
+        self._user_file_items.update({element_id: new_settings})
+
+    @property
+    def q_1d_min(self):
+        return self.get_simple_element_with_attribute(element_id=LimitsId.q, default_value="",
+                                                      attribute="min")
+
+    @q_1d_min.setter
+    def q_1d_min(self, value):
+        self._set_q_1d_limits(min_value=value)
+
+    @property
+    def q_1d_max(self):
+        return self.get_simple_element_with_attribute(element_id=LimitsId.q, default_value="",
+                                                      attribute="max")
+
+    @q_1d_max.setter
+    def q_1d_max(self, value):
+        self._set_q_1d_limits(max_value=value)
+
+    @property
+    def q_1d_rebin_string(self):
+        return self.get_simple_element_with_attribute(element_id=LimitsId.q, default_value="",
+                                                      attribute="rebin_string")
+
+    @q_1d_rebin_string.setter
+    def q_1d_rebin_string(self, value):
+        self._set_q_1d_limits(rebin_string=value)
+
+    @property
+    def q_xy_max(self):
+        return self.get_simple_element_with_attribute(element_id=LimitsId.qxy, default_value="",
+                                                      attribute="stop")
+
+    @q_xy_max.setter
+    def q_xy_max(self, value):
+        self._set_q_xy_limits(stop_value=value)
+
+    @property
+    def q_xy_step(self):
+        return self.get_simple_element_with_attribute(element_id=LimitsId.qxy, default_value="",
+                                                      attribute="step")
+
+    @q_xy_step.setter
+    def q_xy_step(self, value):
+        self._set_q_xy_limits(step_value=value)
+
+    @property
+    def q_xy_step_type(self):
+        return self.get_simple_element_with_attribute(element_id=LimitsId.qxy, default_value=None,
+                                                      attribute="step_type")
+
+    @q_xy_step_type.setter
+    def q_xy_step_type(self, value):
+        self._set_q_xy_limits(step_type_value=value)
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Gravity
+    # ------------------------------------------------------------------------------------------------------------------
+    @property
+    def gravity_on_off(self):
+        return self.get_simple_element(element_id=GravityId.on_off, default_value=True)
+
+    @gravity_on_off.setter
+    def gravity_on_off(self, value):
+        self.set_simple_element(element_id=GravityId.on_off, value=value)
+
+    @property
+    def gravity_extra_length(self):
+        return self.get_simple_element(element_id=GravityId.extra_length, default_value="")
+
+    @gravity_extra_length.setter
+    def gravity_extra_length(self, value):
+        self.set_simple_element(element_id=GravityId.extra_length, value=value)
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # QResolution
+    # ------------------------------------------------------------------------------------------------------------------
+    @property
+    def use_q_resolution(self):
+        return self.get_simple_element(element_id=QResolutionId.on, default_value=False)
+
+    @use_q_resolution.setter
+    def use_q_resolution(self, value):
+        self.set_simple_element(element_id=QResolutionId.on, value=value)
+
+    @property
+    def q_resolution_source_a(self):
+        return self.get_simple_element(element_id=QResolutionId.a1, default_value="")
+
+    @q_resolution_source_a.setter
+    def q_resolution_source_a(self, value):
+        self.set_simple_element(element_id=QResolutionId.a1, value=value)
+
+    @property
+    def q_resolution_sample_a(self):
+        return self.get_simple_element(element_id=QResolutionId.a2, default_value="")
+
+    @q_resolution_sample_a.setter
+    def q_resolution_sample_a(self, value):
+        self.set_simple_element(element_id=QResolutionId.a2, value=value)
+
+    @property
+    def q_resolution_source_h(self):
+        return self.get_simple_element(element_id=QResolutionId.h1, default_value="")
+
+    @q_resolution_source_h.setter
+    def q_resolution_source_h(self, value):
+        self.set_simple_element(element_id=QResolutionId.h1, value=value)
+
+    @property
+    def q_resolution_sample_h(self):
+        return self.get_simple_element(element_id=QResolutionId.h2, default_value="")
+
+    @q_resolution_sample_h.setter
+    def q_resolution_sample_h(self, value):
+        self.set_simple_element(element_id=QResolutionId.h2, value=value)
+
+    @property
+    def q_resolution_source_w(self):
+        return self.get_simple_element(element_id=QResolutionId.w1, default_value="")
+
+    @q_resolution_source_w.setter
+    def q_resolution_source_w(self, value):
+        self.set_simple_element(element_id=QResolutionId.w1, value=value)
+
+    @property
+    def q_resolution_sample_w(self):
+        return self.get_simple_element(element_id=QResolutionId.w2, default_value="")
+
+    @q_resolution_sample_w.setter
+    def q_resolution_sample_w(self, value):
+        self.set_simple_element(element_id=QResolutionId.w2, value=value)
+
+    @property
+    def q_resolution_delta_r(self):
+        return self.get_simple_element(element_id=QResolutionId.delta_r, default_value="")
+
+    @q_resolution_delta_r.setter
+    def q_resolution_delta_r(self, value):
+        self.set_simple_element(element_id=QResolutionId.delta_r, value=value)
+
+    @property
+    def q_resolution_moderator_file(self):
+        return self.get_simple_element(element_id=QResolutionId.moderator, default_value="")
+
+    @q_resolution_moderator_file.setter
+    def q_resolution_moderator_file(self, value):
+        self.set_simple_element(element_id=QResolutionId.moderator, value=value)
+
+    @property
+    def q_resolution_collimation_length(self):
+        return self.get_simple_element(element_id=QResolutionId.collimation_length, default_value="")
+
+    @q_resolution_collimation_length.setter
+    def q_resolution_collimation_length(self, value):
+        self.set_simple_element(element_id=QResolutionId.collimation_length, value=value)
+
+    # ==================================================================================================================
+    # ==================================================================================================================
+    # MASK TAB
+    # ==================================================================================================================
+    # ==================================================================================================================
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Phi limit
+    # ------------------------------------------------------------------------------------------------------------------
+    def _set_phi_limit(self, min_value=None, max_value=None, use_mirror=None):
+        if LimitsId.angle in self._user_file_items:
+            settings = self._user_file_items[LimitsId.angle]
+        else:
+            settings = [mask_angle_entry(min=None, max=None, use_mirror=False)]
+
+        new_settings = []
+        for setting in settings:
+            new_min = min_value if min_value is not None else setting.min
+            new_max = max_value if max_value is not None else setting.max
+            new_use_mirror = use_mirror if use_mirror is not None else setting.use_mirror
+            new_settings.append(mask_angle_entry(min=new_min, max=new_max, use_mirror=new_use_mirror))
+        self._user_file_items.update({LimitsId.angle: new_settings})
+
+    @property
+    def phi_limit_min(self):
+        return self.get_simple_element_with_attribute(element_id=LimitsId.angle, attribute="min", default_value="")
+
+    @phi_limit_min.setter
+    def phi_limit_min(self, value):
+        self._set_phi_limit(min_value=value)
+
+    @property
+    def phi_limit_max(self):
+        return self.get_simple_element_with_attribute(element_id=LimitsId.angle, attribute="max", default_value="")
+
+    @phi_limit_max.setter
+    def phi_limit_max(self, value):
+        self._set_phi_limit(max_value=value)
+
+    @property
+    def phi_limit_use_mirror(self):
+        return self.get_simple_element_with_attribute(element_id=LimitsId.angle, attribute="use_mirror", default_value=False)  # noqa
+
+    @phi_limit_use_mirror.setter
+    def phi_limit_use_mirror(self, value):
+        self._set_phi_limit(use_mirror=value)
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Radius limit
+    # ------------------------------------------------------------------------------------------------------------------
+    def _set_radius_limit(self, min_value=None, max_value=None):
+        if LimitsId.radius in self._user_file_items:
+            settings = self._user_file_items[LimitsId.radius]
+        else:
+            settings = [range_entry(start=None, stop=None)]
+
+        new_settings = []
+        for setting in settings:
+            new_min = min_value if min_value is not None else setting.start
+            new_max = max_value if max_value is not None else setting.stop
+            new_settings.append(range_entry(start=new_min, stop=new_max))
+        self._user_file_items.update({LimitsId.radius: new_settings})
+
+    @property
+    def radius_limit_min(self):
+        return self.get_simple_element_with_attribute(element_id=LimitsId.radius, attribute="start", default_value="")
+
+    @radius_limit_min.setter
+    def radius_limit_min(self, value):
+        self._set_radius_limit(min_value=value)
+
+    @property
+    def radius_limit_max(self):
+        return self.get_simple_element_with_attribute(element_id=LimitsId.radius, attribute="stop", default_value="")
+
+    @radius_limit_max.setter
+    def radius_limit_max(self, value):
+        self._set_radius_limit(max_value=value)
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Output name
+    # ------------------------------------------------------------------------------------------------------------------
+    @property
+    def output_name(self):
+        return self.get_simple_element(element_id=OtherId.user_specified_output_name, default_value="")
+
+    @output_name.setter
+    def output_name(self, value):
+        self.set_simple_element(element_id=OtherId.user_specified_output_name, value=value)
diff --git a/scripts/SANS/sans/gui_logic/models/table_model.py b/scripts/SANS/sans/gui_logic/models/table_model.py
new file mode 100644
index 0000000000000000000000000000000000000000..0167984dbe74ac368d1e621e72edf3e945cbd7b2
--- /dev/null
+++ b/scripts/SANS/sans/gui_logic/models/table_model.py
@@ -0,0 +1,133 @@
+""" The table  model contains all the reduction information which is provided via the data table
+
+The main information in the table model are the run numbers and the selected periods. However it also contains
+information regarding the custom output name and the information in the options tab.
+"""
+
+from __future__ import (absolute_import, division, print_function)
+
+import os
+
+from sans.gui_logic.sans_data_processor_gui_algorithm import create_option_column_properties
+from sans.gui_logic.gui_common import OPTIONS_SEPARATOR, OPTIONS_EQUAL
+
+
+class TableModel(object):
+    def __init__(self):
+        super(TableModel, self).__init__()
+        self._user_file = ""
+        self._batch_file = ""
+        self._table_entries = {}
+
+    @staticmethod
+    def _validate_file_name(file_name):
+        if not file_name:
+            return
+        if not os.path.exists(file_name):
+            raise ValueError("The file {} does not seem to exist.".format(file_name))
+
+    @property
+    def user_file(self):
+        return self._user_file
+
+    @user_file.setter
+    def user_file(self, value):
+        self._validate_file_name(value)
+        self._user_file = value
+
+    @property
+    def batch_file(self):
+        return self._batch_file
+
+    @batch_file.setter
+    def batch_file(self, value):
+        self._validate_file_name(value)
+        self._batch_file = value
+
+    def get_table_entry(self, index):
+        if index not in self._table_entries:
+            raise ValueError("The {}th row entry does not exist".format(index))
+        return self._table_entries[index]
+
+    def add_table_entry(self, row, table_index_model):
+        self._table_entries.update({row: table_index_model})
+
+    def clear_table_entries(self):
+        self._table_entries = {}
+
+
+class TableIndexModel(object):
+    def __init__(self, index, sample_scatter, sample_transmission, sample_direct,
+                 can_scatter, can_transmission, can_direct, output_name="",
+                 options_column_string=""):
+        super(TableIndexModel, self).__init__()
+        self.index = index
+        self.sample_scatter = sample_scatter
+        self.sample_transmission = sample_transmission
+        self.sample_direct = sample_direct
+
+        self.can_scatter = can_scatter
+        self.can_transmission = can_transmission
+        self.can_direct = can_direct
+
+        self.user_file = ""
+        self.output_name = output_name
+
+        # Options column entries
+        self.options_column_model = OptionsColumnModel(options_column_string)
+
+
+class OptionsColumnModel(object):
+    def __init__(self, options_column_string):
+        super(OptionsColumnModel, self).__init__()
+        self._options_column_string = options_column_string
+        self._options = self._get_options(self._options_column_string)
+
+    def get_options(self):
+        return self._options
+
+    @staticmethod
+    def _get_permissible_properties():
+        props = {}
+        option_column_properties = create_option_column_properties()
+        for element in option_column_properties:
+            props.update({element.algorithm_property: element.property_type})
+        return props
+
+    @staticmethod
+    def _parse_string(options_column_string):
+        """
+        Parses a string of the form "PropName1=value1,PropName2=value2"
+        :param options_column_string: the string in the options column
+        :return: a dict with parsed values
+        """
+        parsed = {}
+        # Remove all white space
+        options_column_string_no_whitespace = "".join(options_column_string.split())
+        if not options_column_string_no_whitespace:
+            return parsed
+
+        # Split by the comma
+        elements = options_column_string_no_whitespace.split(OPTIONS_SEPARATOR)
+        for element in elements:
+            key, value = element.split(OPTIONS_EQUAL)
+            parsed.update({key: value})
+        return parsed
+
+    @staticmethod
+    def _get_options(options_column_string):
+        """
+        Gets all allowed values from the options column.
+
+        :param options_column_string: the string in the options column
+        :return: a dict with all options
+        """
+        parsed_options = OptionsColumnModel._parse_string(options_column_string)
+        permissible_properties = OptionsColumnModel._get_permissible_properties()
+
+        options = {}
+        for key, value in parsed_options.items():
+            if key in permissible_properties.keys():
+                conversion_functions = permissible_properties[key]
+                options.update({key: conversion_functions(value)})
+        return options
diff --git a/scripts/SANS/sans/gui_logic/presenter/__init__.py b/scripts/SANS/sans/gui_logic/presenter/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/scripts/SANS/sans/gui_logic/presenter/gui_state_director.py b/scripts/SANS/sans/gui_logic/presenter/gui_state_director.py
new file mode 100644
index 0000000000000000000000000000000000000000..486d3a333f7e29db2d0cf8a6a973cc01ff48f5b8
--- /dev/null
+++ b/scripts/SANS/sans/gui_logic/presenter/gui_state_director.py
@@ -0,0 +1,75 @@
+"""  The GuiStateDirector generates the state object from the models.
+
+The GuiStateDirector gets the information from the table and state model and generates state objects. It delegates
+the main part of the work to an StateDirectorISIS object.
+"""
+
+from __future__ import (absolute_import, division, print_function)
+
+import copy
+
+from sans.state.data import get_data_builder
+from sans.user_file.state_director import StateDirectorISIS
+
+
+class GuiStateDirector(object):
+    def __init__(self, table_model, state_gui_model, facility):
+        super(GuiStateDirector, self).__init__()
+        self._table_model = table_model
+        self._state_gui_model = state_gui_model
+        self._facility = facility
+
+    def create_state(self, row):
+        # 1. Get the data settings, such as sample_scatter, etc... and create the data state.
+        table_index_model = self._table_model.get_table_entry(row)
+        data_builder = get_data_builder(self._facility)
+
+        self._set_data_entry(data_builder.set_sample_scatter, table_index_model.sample_scatter)
+        self._set_data_entry(data_builder.set_sample_transmission, table_index_model.sample_transmission)
+        self._set_data_entry(data_builder.set_sample_direct, table_index_model.sample_direct)
+        self._set_data_entry(data_builder.set_can_scatter, table_index_model.can_scatter)
+        self._set_data_entry(data_builder.set_can_transmission, table_index_model.can_transmission)
+        self._set_data_entry(data_builder.set_can_direct, table_index_model.can_direct)
+
+        data = data_builder.build()
+
+        # 2. Add elements from the options column
+        state_gui_model = copy.deepcopy(self._state_gui_model)
+        options_column_model = table_index_model.options_column_model
+        self._apply_column_options_to_state(options_column_model, state_gui_model)
+
+        # 3. Add other columns
+        output_name = table_index_model.output_name
+        if output_name:
+            state_gui_model.output_name = output_name
+
+        # 4. Create the rest of the state based on the builder.
+        user_file_state_director = StateDirectorISIS(data)
+        settings = copy.deepcopy(state_gui_model.settings)
+        user_file_state_director.add_state_settings(settings)
+
+        return user_file_state_director.construct()
+
+    @staticmethod
+    def _set_data_entry(func, entry):
+        if entry:
+            func(entry)
+
+    @staticmethod
+    def _apply_column_options_to_state(options_column_model, state_gui_model):
+        """
+        Apply the column setting of the user to the state for that particular row.
+
+        Note if you are extending the options functionality, then you will have to add the property here.
+        :param options_column_model: the option column model with the row specific settings
+        :param state_gui_model: the state gui model
+        """
+        options = options_column_model.get_options()
+
+        # Here we apply the correction to the state depending on the settings in the options. This is not very nice,
+        # but currently it is not clear how to solve this differently.
+        if "WavelengthMin" in options.keys():
+            state_gui_model.wavelength_min = options["WavelengthMin"]
+
+        if "WavelengthMax" in options.keys():
+            state_gui_model.wavelength_max = options["WavelengthMax"]
diff --git a/scripts/SANS/sans/gui_logic/presenter/main_presenter.py b/scripts/SANS/sans/gui_logic/presenter/main_presenter.py
new file mode 100644
index 0000000000000000000000000000000000000000..89f0e96d68f27559a38bcd449fc8458b03f16892
--- /dev/null
+++ b/scripts/SANS/sans/gui_logic/presenter/main_presenter.py
@@ -0,0 +1,95 @@
+"""  The main presenter.
+
+The MainPresenter provides the QDataProcessorWidget with additional processing options which have not been
+set on the data table. The MainPresenter is required by the DataProcessorWidget framework.
+"""
+
+from __future__ import (absolute_import, division, print_function)
+
+from mantidqtpython import MantidQt
+
+from sans.gui_logic.sans_data_processor_gui_algorithm import (get_gui_algorithm_name, get_white_list,
+                                                              get_black_list)
+from sans.gui_logic.presenter.run_tab_presenter import RunTabPresenter
+
+
+class PresenterEnum(object):
+    class RunTabPresenter(object):
+        pass
+
+
+class MainPresenter(MantidQt.MantidWidgets.DataProcessorMainPresenter):
+    """
+    Comments below are from Raquel:
+
+    A DataProcessorMainPresenter. The base class provides default implementations
+    but we should re-implement the following methods:
+    - getPreprocessingOptionsAsString() -- to supply global pre-processing options to the table widget
+    - getProcessingOptions() -- to supply global processing options
+    - getPostprocessingOptions() -- to supply global post-processing options
+    - notifyADSChanged() -- to act when the ADS changed, typically we want to update
+      table actions with the list of table workspaces that can be loaded into the interface
+
+    This is an intermediate layer needed in python. Ideally our gui class should
+    inherit from 'DataProcessorMainPresenter' directly and provide the required implementations,
+    but multiple inheritance does not seem to be fully supported, hence we need this extra class.
+    """
+
+    def __init__(self, facility):
+        super(MantidQt.MantidWidgets.DataProcessorMainPresenter, self).__init__()
+
+        self._view = None
+
+        # Algorithm details
+        self._gui_algorithm_name = None
+        self._white_list = None
+        self._black_list = None
+        self._facility = facility
+
+        # Set of sub presenters
+        self._presenters = {}
+        self._presenters.update({PresenterEnum.RunTabPresenter: RunTabPresenter(facility=self._facility)})
+
+    def set_view(self, view):
+        self._view = view
+        for _, presenter in self._presenters.items():
+            presenter.set_view(self._view)
+
+    def get_gui_algorithm_name(self):
+        if self._gui_algorithm_name is None:
+            self._gui_algorithm_name = get_gui_algorithm_name(self._facility)
+        return self._gui_algorithm_name
+
+    def get_white_list(self):
+        if self._white_list is None:
+            self._white_list = get_white_list()
+        return self._white_list
+
+    def get_number_of_white_list_items(self):
+        return 0 if not self._white_list else len(self._white_list)
+
+    def get_black_list(self):
+        if self._black_list is None:
+            self._black_list = get_black_list()
+        return self._black_list
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Inherited methods
+    # ------------------------------------------------------------------------------------------------------------------
+    def getProcessingOptions(self):
+        """
+        Gets the processing options from the run tab presenter
+        """
+        return self._presenters[PresenterEnum.RunTabPresenter].get_processing_options()
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Unused
+    # ------------------------------------------------------------------------------------------------------------------
+    def getPreprocessingOptionsAsString(self):
+        return ""
+
+    def getPostprocessingOptions(self):
+        return ""
+
+    def notifyADSChanged(self, workspace_list):
+        self._view.add_actions_to_menus(workspace_list)
diff --git a/scripts/SANS/sans/gui_logic/presenter/masking_table_presenter.py b/scripts/SANS/sans/gui_logic/presenter/masking_table_presenter.py
new file mode 100644
index 0000000000000000000000000000000000000000..b873431581384f4f9b24196b506cc534ed55fceb
--- /dev/null
+++ b/scripts/SANS/sans/gui_logic/presenter/masking_table_presenter.py
@@ -0,0 +1,392 @@
+"""  The presenter associated with the masking table view. """
+
+from __future__ import (absolute_import, division, print_function)
+
+from collections import namedtuple
+import copy
+
+from mantid.api import (AnalysisDataService)
+try:
+    import mantidplot
+except ImportError:
+    pass
+
+from ui.sans_isis.masking_table import MaskingTable
+from sans.common.enums import DetectorType
+from sans.common.constants import EMPTY_NAME
+from sans.common.general_functions import create_unmanaged_algorithm
+
+
+masking_information = namedtuple("masking_information", "first, second, third")
+
+
+class MaskingTablePresenter(object):
+    DISPLAY_WORKSPACE_NAME = "__sans_mask_display_dummy_workspace"
+
+    class ConcreteMaskingTableListener(MaskingTable.MaskingTableListener):
+        def __init__(self, presenter):
+            super(MaskingTablePresenter.ConcreteMaskingTableListener, self).__init__()
+            self._presenter = presenter
+
+        def on_row_changed(self):
+            self._presenter.on_row_changed()
+
+        def on_update_rows(self):
+            self._presenter.on_update_rows()
+
+        def on_display(self):
+            self._presenter.on_display()
+
+    def __init__(self, parent_presenter):
+        super(MaskingTablePresenter, self).__init__()
+        self._view = None
+        self._parent_presenter = parent_presenter
+
+    def on_row_changed(self):
+        row_index = self._view.get_current_row()
+        state = self.get_state(row_index)
+        if state:
+            self.display_masking_information(state)
+
+    def on_display(self):
+        # TODO: This will run synchronously and block the GUI, therefore it is not enabled at the moment. Once,
+        # we agree on a async framework which we can use in combination with Mantid in Python, we will have to
+        # disable this feature. Once it is solved, it is easy to hook up.
+
+        # Load the sample workspace
+        row_index = self._view.get_current_row()
+        state = self.get_state(row_index)
+        workspace_to_mask = self._load_the_workspace_to_mask(state)
+
+        # Apply the mask
+        self._mask_workspace(state, workspace_to_mask)
+
+        # Display
+        self._display(workspace_to_mask)
+
+    def on_update_rows(self):
+        """
+        Update the row selection in the combobox
+        """
+        current_row_index = self._view.get_current_row()
+        valid_row_indices = self._parent_presenter.get_row_indices()
+
+        new_row_index = -1
+        if current_row_index in valid_row_indices:
+            new_row_index = current_row_index
+        elif len(valid_row_indices) > 0:
+            new_row_index = valid_row_indices[0]
+
+        self._view.update_rows(valid_row_indices)
+
+        if new_row_index != -1:
+            self.set_row(new_row_index)
+            self.on_row_changed()
+
+    def set_row(self, index):
+        self._view.set_row(index)
+
+    def set_view(self, view):
+        if view:
+            self._view = view
+
+            # Set up row selection listener
+            listener = MaskingTablePresenter.ConcreteMaskingTableListener(self)
+            self._view.add_listener(listener)
+
+            # Set the default gui
+            self._set_default_gui()
+
+    def _set_default_gui(self):
+        self._view.update_rows([])
+        self.display_masking_information(state=None)
+
+    def get_state(self, index):
+        return self._parent_presenter.get_state_for_row(index)
+
+    @staticmethod
+    def _append_single_spectrum_mask(spectrum_mask, container, detector_name, prefix):
+        if spectrum_mask:
+            for item in spectrum_mask:
+                detail = prefix + str(item)
+                container.append(masking_information(first="Spectrum", second=detector_name, third=detail))
+
+    @staticmethod
+    def _append_strip_spectrum_mask(strip_mask_start, strip_mask_stop, container, detector_name, prefix):
+        if strip_mask_start and strip_mask_stop:
+            for start, stop in zip(strip_mask_start, strip_mask_stop):
+                detail = prefix + str(start) + ">" + prefix + str(stop)
+                container.append(masking_information(first="Strip", second=detector_name, third=detail))
+
+    @staticmethod
+    def _append_block_spectrum_mask(horizontal_mask_start, horizontal_mask_stop, vertical_mask_start,
+                                    vertical_mask_stop, container, detector_name):
+        if horizontal_mask_start and horizontal_mask_stop and vertical_mask_start and vertical_mask_stop:
+            for h_start, h_stop, v_start, v_stop in zip(horizontal_mask_start, horizontal_mask_stop,
+                                                        vertical_mask_start, vertical_mask_stop):
+                detail = "H{}>H{}+V{}>V{}".format(h_start, h_stop, v_start, v_stop)
+                container.append(masking_information(first="Strip", second=detector_name, third=detail))
+
+    @staticmethod
+    def _append_spectrum_block_cross_mask(horizontal_mask, vertical_mask, container, detector_name):
+        if horizontal_mask and vertical_mask:
+            for h, v in zip(horizontal_mask, vertical_mask):
+                detail = "H{}+V{}".format(h, v)
+                container.append(masking_information(first="Strip", second=detector_name, third=detail))
+
+    @staticmethod
+    def _get_spectrum_masks(mask_detector_info):
+        detector_name = mask_detector_info.detector_name
+        spectrum_masks = []
+
+        # -------------------------------
+        # Get the vertical spectrum masks
+        # -------------------------------
+        single_vertical_strip_mask = mask_detector_info.single_vertical_strip_mask
+        MaskingTablePresenter._append_single_spectrum_mask(single_vertical_strip_mask, spectrum_masks,
+                                                           detector_name, "V")
+
+        range_vertical_strip_start = mask_detector_info.range_vertical_strip_start
+        range_vertical_strip_stop = mask_detector_info.range_vertical_strip_stop
+        MaskingTablePresenter._append_strip_spectrum_mask(range_vertical_strip_start,
+                                                          range_vertical_strip_stop,
+                                                          spectrum_masks, detector_name, "V")
+
+        # ---------------------------------
+        # Get the horizontal spectrum masks
+        # ---------------------------------
+        single_horizontal_strip_mask = mask_detector_info.single_horizontal_strip_mask
+        MaskingTablePresenter._append_single_spectrum_mask(single_horizontal_strip_mask, spectrum_masks,
+                                                           detector_name, "H")
+
+        range_horizontal_strip_start = mask_detector_info.range_horizontal_strip_start
+        range_horizontal_strip_stop = mask_detector_info.range_horizontal_strip_stop
+        MaskingTablePresenter._append_strip_spectrum_mask(range_horizontal_strip_start,
+                                                          range_horizontal_strip_stop,
+                                                          spectrum_masks, detector_name, "H")
+
+        # ---------------------------------
+        # Get the block masks
+        # ---------------------------------
+        block_horizontal_start = mask_detector_info.block_horizontal_start
+        block_horizontal_stop = mask_detector_info.block_horizontal_stop
+        block_vertical_start = mask_detector_info.block_vertical_start
+        block_vertical_stop = mask_detector_info.block_vertical_stop
+        MaskingTablePresenter._append_block_spectrum_mask(block_horizontal_start, block_horizontal_stop,
+                                                          block_vertical_start, block_vertical_stop,
+                                                          spectrum_masks, detector_name)
+
+        block_cross_horizontal = mask_detector_info.block_cross_horizontal
+        block_cross_vertical = mask_detector_info.block_cross_vertical
+        MaskingTablePresenter._append_spectrum_block_cross_mask(block_cross_horizontal, block_cross_vertical,
+                                                                spectrum_masks, detector_name)
+
+        # ---------------------------------
+        # Get spectrum masks
+        # ---------------------------------
+        single_spectra = mask_detector_info.single_spectra
+        MaskingTablePresenter._append_single_spectrum_mask(single_spectra, spectrum_masks,
+                                                           detector_name, "S")
+
+        spectrum_range_start = mask_detector_info.spectrum_range_start
+        spectrum_range_stop = mask_detector_info.spectrum_range_stop
+        MaskingTablePresenter._append_strip_spectrum_mask(spectrum_range_start,
+                                                          spectrum_range_stop,
+                                                          spectrum_masks, detector_name, "S")
+
+        return spectrum_masks
+
+    @staticmethod
+    def _get_time_masks_general(mask_info):
+        container = []
+        bin_mask_general_start = mask_info.bin_mask_general_start
+        bin_mask_general_stop = mask_info.bin_mask_general_stop
+        if bin_mask_general_start and bin_mask_general_stop:
+            for start, stop in zip(bin_mask_general_start, bin_mask_general_stop):
+                detail = "{}-{}".format(start, stop)
+                container.append(masking_information(first="Time", second="", third=detail))
+        return container
+
+    @staticmethod
+    def _get_time_masks(mask_info):
+        container = []
+        bin_mask_start = mask_info.bin_mask_start
+        bin_mask_stop = mask_info.bin_mask_stop
+        detector_name = mask_info.detector_name
+        if bin_mask_start and bin_mask_stop:
+            for start, stop in zip(bin_mask_start, bin_mask_stop):
+                detail = "{}-{}".format(start, stop)
+                container.append(masking_information(first="Time", second=detector_name, third=detail))
+        return container
+
+    @staticmethod
+    def _get_arm_mask(mask_info):
+        container = []
+        beam_stop_arm_width = mask_info.beam_stop_arm_width
+        beam_stop_arm_angle = mask_info.beam_stop_arm_angle
+        beam_stop_arm_pos1 = mask_info.beam_stop_arm_pos1
+        beam_stop_arm_pos2 = mask_info.beam_stop_arm_pos2
+        if beam_stop_arm_width and beam_stop_arm_angle and beam_stop_arm_pos1 and beam_stop_arm_pos2:
+            detail = "LINE {}, {}, {}, {}".format(beam_stop_arm_width, beam_stop_arm_angle,
+                                                  beam_stop_arm_pos1, beam_stop_arm_pos2)
+            container.append(masking_information(first="Arm", second="", third=detail))
+        return container
+
+    @staticmethod
+    def _get_phi_mask(mask_info):
+        container = []
+        phi_min = mask_info.phi_min
+        phi_max = mask_info.phi_max
+        use_mask_phi_mirror = mask_info.use_mask_phi_mirror
+        if phi_min and phi_max:
+            if use_mask_phi_mirror:
+                detail = "L/PHI {} {}".format(phi_min, phi_max)
+            else:
+                detail = "L/PHI/NOMIRROR{} {}".format(phi_min, phi_max)
+            container.append(masking_information(first="Phi", second="", third=detail))
+        return container
+
+    @staticmethod
+    def _get_mask_files(mask_info):
+        container = []
+        mask_files = mask_info.mask_files
+        if mask_files:
+            for mask_file in mask_files:
+                container.append(masking_information(first="Mask file", second="", third=mask_file))
+        return container
+
+    @staticmethod
+    def _get_radius(mask_info):
+        container = []
+        radius_min = mask_info.radius_min
+        radius_max = mask_info.radius_max
+
+        if radius_min:
+            detail = "infinite-cylinder, r = {}".format(radius_min)
+            container.append(masking_information(first="Beam stop", second="", third=detail))
+
+        if radius_max:
+            detail = "infinite-cylinder, r = {}".format(radius_max)
+            container.append(masking_information(first="Corners", second="", third=detail))
+        return container
+
+    def _generate_masking_information(self, state):
+        if state is None:
+            return []
+        mask_info = state.mask
+        masks = []
+
+        mask_info_lab = mask_info.detectors[DetectorType.to_string(DetectorType.LAB)]
+        mask_info_hab = mask_info.detectors[DetectorType.to_string(DetectorType.HAB)]
+
+        # Add the radius mask
+        radius_mask = self._get_radius(mask_info)
+        masks.extend(radius_mask)
+
+        # Add the spectrum masks for LAB
+        spectrum_masks_lab = self._get_spectrum_masks(mask_info_lab)
+        masks.extend(spectrum_masks_lab)
+
+        # Add the spectrum masks for HAB
+        spectrum_masks_hab = self._get_spectrum_masks(mask_info_hab)
+        masks.extend(spectrum_masks_hab)
+
+        # Add the general time mask
+        time_masks_general = self._get_time_masks_general(mask_info)
+        masks.extend(time_masks_general)
+
+        # Add the time masks for LAB
+        time_masks_lab = self._get_time_masks(mask_info_lab)
+        masks.extend(time_masks_lab)
+
+        # Add the time masks for HAB
+        time_masks_hab = self._get_time_masks(mask_info_hab)
+        masks.extend(time_masks_hab)
+
+        # Add arm mask
+        arm_mask = self._get_arm_mask(mask_info)
+        masks.extend(arm_mask)
+
+        # Add phi mask
+        phi_mask = self._get_phi_mask(mask_info)
+        masks.extend(phi_mask)
+
+        # Add mask files
+        mask_files = self._get_mask_files(mask_info)
+        masks.extend(mask_files)
+        return masks
+
+    def get_masking_information(self, state):
+        table_entries = []
+        if state is not None:
+            table_entries = self._generate_masking_information(state)
+        return table_entries
+
+    def display_masking_information(self, state):
+        table_entries = self.get_masking_information(state)
+        self._view.set_table(table_entries)
+
+    def _load_the_workspace_to_mask(self, state):
+        # Make a deepcopy of the state
+        state_copy = copy.deepcopy(state)
+
+        # We only want to load the data for the scatter sample. Hence we set everything else to an empty string.
+        # This is ok since we are changing a copy of the state which is not being used for the actual data reduction.
+        state_copy.data.sample_transmission = ""
+        state_copy.data.sample_direct = ""
+        state_copy.data.can_scatter = ""
+        state_copy.data.can_transmission = ""
+        state_copy.data.can_direct = ""
+
+        # If the data is multi-period data, then we select only the first period.
+        if state_copy.data.sample_scatter_is_multi_period and state_copy.data.sample_scatter_period == 0:
+            state_copy.data.sample_scatter_period = 1
+
+        # Load the workspace
+        serialized_state = state_copy.property_manager
+        load_name = "SANSLoad"
+        load_options = {"SANSState": serialized_state,
+                        "PublishToCache": False,
+                        "UseCached": True,
+                        "SampleScatterWorkspace": EMPTY_NAME,
+                        "SampleScatterMonitorWorkspace": EMPTY_NAME,
+                        "SampleTransmissionWorkspace": EMPTY_NAME,
+                        "SampleDirectWorkspace": EMPTY_NAME,
+                        "CanScatterWorkspace": EMPTY_NAME,
+                        "CanScatterMonitorWorkspace": EMPTY_NAME,
+                        "CanTransmissionWorkspace": EMPTY_NAME,
+                        "CanDirectWorkspace": EMPTY_NAME}
+        load_alg = create_unmanaged_algorithm(load_name, **load_options)
+        load_alg.execute()
+        workspace_to_mask = load_alg.getProperty("SampleScatterWorkspace").value
+
+        # Perform an initial move on the workspace
+        move_name = "SANSMove"
+        move_options = {"SANSState": serialized_state,
+                        "Workspace": workspace_to_mask,
+                        "MoveType": "InitialMove"}
+        move_alg = create_unmanaged_algorithm(move_name, **move_options)
+        move_alg.execute()
+
+        # Put the workspace onto the ADS as a hidden workspace
+        AnalysisDataService.addOrReplace(self.DISPLAY_WORKSPACE_NAME, workspace_to_mask)
+        return workspace_to_mask
+
+    @staticmethod
+    def _mask_workspace(state, workspace):
+        serialized_state = state.property_manager
+        mask_name = "SANSMaskWorkspace"
+        mask_options = {"SANSState": serialized_state,
+                        "Workspace": workspace}
+        mask_alg = create_unmanaged_algorithm(mask_name, **mask_options)
+
+        detectors = [DetectorType.to_string(DetectorType.LAB), DetectorType.to_string(DetectorType.HAB)]
+        for detector in detectors:
+            mask_alg.setProperty("Component", detector)
+            mask_alg.execute()
+
+    @staticmethod
+    def _display(masked_workspace):
+        if masked_workspace and AnalysisDataService.doesExist(masked_workspace.name()):
+            instrument_win = mantidplot.getInstrumentView(masked_workspace.name())
+            instrument_win.show()
diff --git a/scripts/SANS/sans/gui_logic/presenter/property_manager_service.py b/scripts/SANS/sans/gui_logic/presenter/property_manager_service.py
new file mode 100644
index 0000000000000000000000000000000000000000..ec3bded68f3714f7a856cdcec8b140c0dc4c7386
--- /dev/null
+++ b/scripts/SANS/sans/gui_logic/presenter/property_manager_service.py
@@ -0,0 +1,92 @@
+""" The property manager service.
+
+The property manager service serializes a SANS state object into a PropertyManager object and places it on the
+ PropertyManagerDataService. It is also used to retrieve the state from this service.
+"""
+
+from __future__ import (absolute_import, division, print_function)
+
+from mantid.kernel import (PropertyManagerDataService)
+
+from sans.state.state_base import create_deserialized_sans_state_from_property_manager
+
+
+class PropertyManagerService(object):
+    sans_property_manager_prefix = "SANS_PROPERTY_MANAGER_THIS_NEEDS_TO_BE_UNIQUE_"
+
+    def __init__(self):
+        super(PropertyManagerService, self).__init__()
+
+    def add_states_to_pmds(self, states):
+        # 1. Remove all property managers which belong to the sans property manager type
+        self.remove_sans_property_managers()
+
+        # 2. Add all property managers
+        self._add_property_managers_to_pmds(states)
+
+    def get_single_state_from_pmds(self, index_to_retrieve):
+        # 1. Find all sans state names
+        sans_property_managers = {}
+        for name in PropertyManagerDataService.getObjectNames():
+            if name.startswith(self.sans_property_manager_prefix):
+                property_manager = PropertyManagerDataService.retrieve(name)
+                index = self._get_index_from_name(name)
+                sans_property_managers.update({index: property_manager})
+
+        # 2. Convert property managers to states
+        if index_to_retrieve not in list(sans_property_managers.keys()):
+            return []
+        sans_property_manager = sans_property_managers[index_to_retrieve]
+        states_map = self._convert_property_manager_to_state({index_to_retrieve: sans_property_manager})
+
+        # 3. Create a sequence container
+        return self._get_states_list(states_map)
+
+    def get_states_from_pmds(self):
+        # 1. Find all sans state names
+        sans_property_managers = {}
+        for name in PropertyManagerDataService.getObjectNames():
+            if name.startswith(self.sans_property_manager_prefix):
+                property_manager = PropertyManagerDataService.retrieve(name)
+                index = self._get_index_from_name(name)
+                sans_property_managers.update({index: property_manager})
+
+        # 2. Convert property managers to states
+        states_map = self._convert_property_manager_to_state(sans_property_managers)
+
+        # 3. Create a sequence container
+        return self._get_states_list(states_map)
+
+    def remove_sans_property_managers(self):
+        property_manager_names_to_delete = []
+        for name in PropertyManagerDataService.getObjectNames():
+            if name.startswith(self.sans_property_manager_prefix):
+                property_manager_names_to_delete.append(name)
+
+        for element in property_manager_names_to_delete:
+            PropertyManagerDataService.remove(element)
+
+    def _add_property_managers_to_pmds(self, states):
+        for index, state in states.items():
+            name = self.sans_property_manager_prefix + str(index)
+            PropertyManagerDataService.addOrReplace(name, state.property_manager)
+
+    def _get_index_from_name(self, name):
+        return int(name.replace(self.sans_property_manager_prefix, ""))
+
+    @staticmethod
+    def _convert_property_manager_to_state(property_managers):
+        states = {}
+        for key, property_manager in property_managers.items():
+            state = create_deserialized_sans_state_from_property_manager(property_manager)
+            states.update({key: state})
+        return states
+
+    @staticmethod
+    def _get_states_list(states_map):
+        states = []
+        indices = list(states_map.keys())
+        indices.sort()
+        for index in indices:
+            states.append(states_map[index])
+        return states
diff --git a/scripts/SANS/sans/gui_logic/presenter/run_tab_presenter.py b/scripts/SANS/sans/gui_logic/presenter/run_tab_presenter.py
new file mode 100644
index 0000000000000000000000000000000000000000..7d6171620aba53a03e91b2a6a4d815c699af2861
--- /dev/null
+++ b/scripts/SANS/sans/gui_logic/presenter/run_tab_presenter.py
@@ -0,0 +1,878 @@
+""" The run tab presenter.
+
+This presenter is essentially the brain of the reduction gui. It controlls other presenters and is mainly responsible
+for presenting and generating the reduction settings.
+"""
+
+from __future__ import (absolute_import, division, print_function)
+
+import os
+import copy
+import time
+
+from mantid.kernel import Logger
+from mantid.api import (AnalysisDataService, FileFinder, WorkspaceFactory)
+from mantid.kernel import (Property)
+
+from ui.sans_isis.sans_data_processor_gui import SANSDataProcessorGui
+from sans.gui_logic.models.state_gui_model import StateGuiModel
+from sans.gui_logic.models.table_model import TableModel, TableIndexModel
+from sans.gui_logic.presenter.gui_state_director import (GuiStateDirector)
+from sans.gui_logic.presenter.settings_diagnostic_presenter import (SettingsDiagnosticPresenter)
+from sans.gui_logic.presenter.masking_table_presenter import (MaskingTablePresenter)
+from sans.gui_logic.sans_data_processor_gui_algorithm import SANS_DUMMY_INPUT_ALGORITHM_PROPERTY_NAME
+from sans.gui_logic.presenter.property_manager_service import PropertyManagerService
+from sans.gui_logic.gui_common import (get_reduction_mode_strings_for_gui, OPTIONS_SEPARATOR, OPTIONS_INDEX,
+                                       OPTIONS_EQUAL, HIDDEN_OPTIONS_INDEX)
+from sans.common.enums import (BatchReductionEntry, OutputMode, SANSInstrument, RangeStepType, SampleShape, FitType)
+from sans.common.file_information import (SANSFileInformationFactory)
+from sans.user_file.user_file_reader import UserFileReader
+from sans.command_interface.batch_csv_file_parser import BatchCsvParser
+
+
+class RunTabPresenter(object):
+    class ConcreteRunTabListener(SANSDataProcessorGui.RunTabListener):
+        def __init__(self, presenter):
+            super(RunTabPresenter.ConcreteRunTabListener, self).__init__()
+            self._presenter = presenter
+
+        def on_user_file_load(self):
+            self._presenter.on_user_file_load()
+
+        def on_batch_file_load(self):
+            self._presenter.on_batch_file_load()
+
+        def on_processed_clicked(self):
+            self._presenter.on_processed_clicked()
+
+        def on_processing_finished(self):
+            self._presenter.on_processing_finished()
+
+    def __init__(self, facility, view=None):
+        super(RunTabPresenter, self).__init__()
+        self._facility = facility
+
+        # Logger
+        self.sans_logger = Logger("SANS")
+
+        # Presenter needs to have a handle on the view since it delegates it
+        self._view = None
+        self.set_view(view)
+
+        # Models that are being used by the presenter
+        self._state_model = None
+        self._table_model = None
+
+        # Due to the nature of the DataProcessorWidget we need to provide an algorithm with at least one input
+        # workspace and at least one output workspace. Our SANS state approach is not compatible with this. Hence
+        # we provide a dummy workspace which is not used. We keep it invisible on the ADS and delete it when the
+        # main_presenter is deleted.
+        # This is not a nice solution but in line with the SANS dummy algorithm approach that we have provided
+        # for the
+        self._create_dummy_input_workspace()
+
+        # File information for the first input
+        self._file_information = None
+
+        # Settings diagnostic tab presenter
+        self._settings_diagnostic_tab_presenter = SettingsDiagnosticPresenter(self)
+
+        # Masking table presenter
+        self._masking_table_presenter = MaskingTablePresenter(self)
+
+    def __del__(self):
+        self._delete_dummy_input_workspace()
+
+    def _default_gui_setup(self):
+        """
+        Provides a default setup of the GUI. This is important for the initial start up, when the view is being set.
+        """
+        # Set the possible reduction modes
+        reduction_mode_list = get_reduction_mode_strings_for_gui()
+        self._view.set_reduction_modes(reduction_mode_list)
+
+        # Set the step type options for wavelength
+        range_step_types = [RangeStepType.to_string(RangeStepType.Lin),
+                            RangeStepType.to_string(RangeStepType.Log)]
+        self._view.wavelength_step_type = range_step_types
+
+        # Set the geometry options. This needs to include the option to read the sample shape from file.
+        sample_shape = ["Read from file",
+                        SampleShape.to_string(SampleShape.CylinderAxisUp),
+                        SampleShape.to_string(SampleShape.Cuboid),
+                        SampleShape.to_string(SampleShape.CylinderAxisAlong)]
+        self._view.sample_shape = sample_shape
+
+        # Set the q range
+        self._view.q_1d_step_type = range_step_types
+        self._view.q_xy_step_type = range_step_types
+
+        # Set the fit options
+        fit_types = [FitType.to_string(FitType.Linear),
+                     FitType.to_string(FitType.Logarithmic),
+                     FitType.to_string(FitType.Polynomial)]
+        self._view.transmission_sample_fit_type = fit_types
+        self._view.transmission_can_fit_type = fit_types
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Table + Actions
+    # ------------------------------------------------------------------------------------------------------------------
+    def set_view(self, view):
+        """
+        Sets the view
+        :param view: the view is the SANSDataProcessorGui. The presenter needs to access some of the API
+        """
+        if view is not None:
+            self._view = view
+
+            # Add a listener to the view
+            listener = RunTabPresenter.ConcreteRunTabListener(self)
+            self._view.add_listener(listener)
+
+            # Default gui setup
+            self._default_gui_setup()
+
+            # Set appropriate view for the state diagnostic tab presenter
+            self._settings_diagnostic_tab_presenter.set_view(self._view.settings_diagnostic_tab)
+
+            # Set appropriate view for the masking table presenter
+            self._masking_table_presenter.set_view(self._view.masking_table)
+
+    def on_user_file_load(self):
+        """
+        Loads the user file. Populates the models and the view.
+        """
+        try:
+            # 1. Get the user file path from the view
+            user_file_path = self._view.get_user_file_path()
+
+            if not user_file_path:
+                return
+
+            # 2. Get the full file path
+            user_file_path = FileFinder.getFullPath(user_file_path)
+            if not os.path.exists(user_file_path):
+                raise RuntimeError("The user path {} does not exist. Make sure a valid user file path"
+                                   " has been specified.".format(user_file_path))
+
+            # Clear out the current view
+            self._view.reset_all_fields_to_default()
+
+            # 3. Read and parse the user file
+            user_file_reader = UserFileReader(user_file_path)
+            user_file_items = user_file_reader.read_user_file()
+
+            # 4. Populate the model
+            self._state_model = StateGuiModel(user_file_items)
+
+            # 5. Update the views.
+            self._update_view_from_state_model()
+
+            # 6. Perform calls on child presenters
+            self._masking_table_presenter.on_update_rows()
+            self._settings_diagnostic_tab_presenter.on_update_rows()
+
+        except Exception as e:
+            self.sans_logger.error("Loading of the user file failed. See here for more details: {}".format(str(e)))
+
+    def on_batch_file_load(self):
+        """
+        Loads a batch file and populates the batch table based on that.
+        """
+        try:
+            # 1. Get the batch file from the view
+            batch_file_path = self._view.get_batch_file_path()
+
+            if not batch_file_path:
+                return
+
+            if not os.path.exists(batch_file_path):
+                raise RuntimeError("The batch file path {} does not exist. Make sure a valid batch file path"
+                                   " has been specified.".format(batch_file_path))
+
+            # 2. Read the batch file
+            batch_file_parser = BatchCsvParser(batch_file_path)
+            parsed_rows = batch_file_parser.parse_batch_file()
+
+            # 3. Clear the table
+            self._view.clear_table()
+
+            # 4. Populate the table
+            for row in parsed_rows:
+                self._populate_row_in_table(row)
+
+            # 5. Populate the selected instrument and the correct detector selection
+            self._setup_instrument_specific_settings()
+
+            # 6. Perform calls on child presenters
+            self._masking_table_presenter.on_update_rows()
+            self._settings_diagnostic_tab_presenter.on_update_rows()
+
+        except RuntimeError as e:
+            self.sans_logger.error("Loading of the batch file failed. See here for more details: {}".format(str(e)))
+
+    def on_processed_clicked(self):
+        """
+        Prepares the batch reduction.
+
+        0. Validate rows and create dummy workspace if it does not exist
+        1. Sets up the states
+        2. Adds a dummy input workspace
+        3. Adds row index information
+        """
+        self.sans_logger.information("Starting processing of batch table.")
+        # 0. Validate rows
+        self._create_dummy_input_workspace()
+        self._validate_rows()
+
+        # 1. Set up the states and convert them into property managers
+        states = self.get_states()
+        if not states:
+            raise RuntimeError("There seems to have been an issue with setting the states. Make sure that a user file"
+                               "has been loaded")
+        property_manager_service = PropertyManagerService()
+        property_manager_service.add_states_to_pmds(states)
+
+        # 2. Add dummy input workspace to Options column
+        self._remove_dummy_workspaces_and_row_index()
+        self._set_dummy_workspace()
+
+        # 3. Add dummy row index to Options column
+        self._set_indices()
+
+    def on_processing_finished(self):
+        self._remove_dummy_workspaces_and_row_index()
+
+    def _add_to_hidden_options(self, row, property_name, property_value):
+        """
+        Adds a new property to the Hidden Options column
+
+        @param row: The row where the Options column is being altered
+        @param property_name: The property name on the GUI algorithm.
+        @param property_value: The value which is being set for the property.
+        """
+        entry = property_name + OPTIONS_EQUAL + str(property_value)
+        options = self._get_hidden_options(row)
+        if options:
+            options += OPTIONS_SEPARATOR + entry
+        else:
+            options = entry
+        self._set_hidden_options(options, row)
+
+    def _set_hidden_options(self, value, row):
+        self._view.set_cell(value, row, HIDDEN_OPTIONS_INDEX)
+
+    def _get_options(self, row):
+        return self._view.get_cell(row, OPTIONS_INDEX, convert_to=str)
+
+    def _get_hidden_options(self, row):
+        return self._view.get_cell(row, HIDDEN_OPTIONS_INDEX, convert_to=str)
+
+    def is_empty_row(self, row):
+        """
+        Checks if a row has no entries. These rows will be ignored.
+        :param row: the row index
+        :return: True if the row is empty.
+        """
+        indices = range(OPTIONS_INDEX + 1)
+        for index in indices:
+            cell_value = self._view.get_cell(row, index, convert_to=str)
+            if cell_value:
+                return False
+        return True
+
+    def _remove_from_hidden_options(self, row, property_name):
+        """
+        Remove the entries in the hidden options column
+        :param row: the row index
+        :param property_name: the property name which is to be removed
+        """
+        options = self._get_hidden_options(row)
+        # Remove the property entry and the value
+        individual_options = options.split(",")
+        clean_options = []
+        for individual_option in individual_options:
+            if property_name not in individual_option:
+                clean_options.append(individual_option)
+        clean_options = ",".join(clean_options)
+        self._set_hidden_options(clean_options, row)
+
+    def _validate_rows(self):
+        """
+        Validation of the rows. A minimal setup requires that ScatterSample is set.
+        """
+        # If SampleScatter is empty, then don't run the reduction.
+        # We allow empty rows for now, since we cannot remove them from Python.
+        number_of_rows = self._view.get_number_of_rows()
+        for row in range(number_of_rows):
+            if not self.is_empty_row(row):
+                sample_scatter = self._view.get_cell(row, 0)
+                if not sample_scatter:
+                    raise RuntimeError("Row {} has not SampleScatter specified. Please correct this.".format(row))
+
+    def get_processing_options(self):
+        """
+        Creates a processing string for the data processor widget
+
+        :return: A processing string for the data processor widget
+        """
+        global_options = ""
+
+        # Check if optimizations should be used
+        optimization_selection = "UseOptimizations=1" if self._view.use_optimizations else "UseOptimizations=0"
+        global_options += optimization_selection
+
+        # Get the output mode
+        output_mode = self._view.output_mode
+        output_mode_selection = "OutputMode=" + OutputMode.to_string(output_mode)
+        global_options += ","
+        global_options += output_mode_selection
+
+        return global_options
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Controls
+    # ------------------------------------------------------------------------------------------------------------------
+    def disable_controls(self):
+        """
+        Disable all input fields and buttons during the execution of the reduction.
+        """
+        # TODO: think about enabling and disable some controls during reduction
+        pass
+
+    def enable_controls(self):
+        """
+        Enable all input fields and buttons after the execution has completed.
+        """
+        # TODO: think about enabling and disable some controls during reduction
+        pass
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Table Model and state population
+    # ------------------------------------------------------------------------------------------------------------------
+    def get_states(self, row_index=None):
+        """
+        Gathers the state information for all rows.
+        :param row_index: if a single row is selected, then only this row is returned, else all the state for all
+                             rows is returned
+        :return: a list of states
+        """
+        start_time_state_generation = time.time()
+
+        # 1. Update the state model
+        state_model_with_view_update = self._get_state_model_with_view_update()
+
+        # 2. Update the table model
+        table_model = self._get_table_model()
+
+        # 3. Go through each row and construct a state object
+        if table_model and state_model_with_view_update:
+            states = self._create_states(state_model_with_view_update, table_model, row_index)
+        else:
+            states = None
+        stop_time_state_generation = time.time()
+        time_taken = stop_time_state_generation - start_time_state_generation
+        self.sans_logger.information("The generation of all states took {}s".format(time_taken))
+        return states
+
+    def get_row_indices(self):
+        """
+        Gets the indices of row which are not empty.
+        :return: a list of row indices.
+        """
+        row_indices_which_are_not_empty = []
+        number_of_rows = self._view.get_number_of_rows()
+        for row in range(number_of_rows):
+            if not self.is_empty_row(row):
+                row_indices_which_are_not_empty.append(row)
+        return row_indices_which_are_not_empty
+
+    def get_state_for_row(self, row_index):
+        """
+        Creates the state for a particular row.
+        :param row_index: the row index
+        :return: a state if the index is valid and there is a state else None
+        """
+        states = self.get_states(row_index=row_index)
+        if states is None:
+            self.sans_logger.warning("There does not seem to be data for a row {}.".format(row_index))
+            return None
+
+        if row_index in list(states.keys()):
+            if states:
+                return states[row_index]
+        return None
+
+    def _update_view_from_state_model(self):
+        # Front tab view
+        self._set_on_view("zero_error_free")
+        self._set_on_view("save_types")
+        self._set_on_view("compatibility_mode")
+
+        self._set_on_view("merge_scale")
+        self._set_on_view("merge_shift")
+        self._set_on_view("merge_scale_fit")
+        self._set_on_view("merge_shift_fit")
+        self._set_on_view("merge_q_range_start")
+        self._set_on_view("merge_q_range_stop")
+
+        # Settings tab view
+        self._set_on_view("reduction_dimensionality")
+        self._set_on_view("reduction_mode")
+        self._set_on_view("event_slices")
+        self._set_on_view("event_binning")
+
+        self._set_on_view("wavelength_step_type")
+        self._set_on_view("wavelength_min")
+        self._set_on_view("wavelength_max")
+        self._set_on_view("wavelength_step")
+
+        self._set_on_view("absolute_scale")
+        self._set_on_view("sample_shape")
+        self._set_on_view("sample_height")
+        self._set_on_view("sample_width")
+        self._set_on_view("sample_thickness")
+        self._set_on_view("z_offset")
+
+        # Adjustment tab
+        self._set_on_view("normalization_incident_monitor")
+        self._set_on_view("normalization_interpolate")
+
+        self._set_on_view("transmission_incident_monitor")
+        self._set_on_view("transmission_interpolate")
+        self._set_on_view("transmission_roi_files")
+        self._set_on_view("transmission_mask_files")
+        self._set_on_view("transmission_radius")
+        self._set_on_view("transmission_monitor")
+        self._set_on_view("transmission_m4_shift")
+
+        self._set_on_view_transmission_fit()
+
+        self._set_on_view("pixel_adjustment_det_1")
+        self._set_on_view("pixel_adjustment_det_2")
+        self._set_on_view("wavelength_adjustment_det_1")
+        self._set_on_view("wavelength_adjustment_det_2")
+
+        # Q tab
+        self._set_on_view("q_1d_min")
+        self._set_on_view("q_1d_max")
+        self._set_on_view_q_rebin_string()
+        self._set_on_view("q_xy_max")
+        self._set_on_view("q_xy_step")
+        self._set_on_view("q_xy_step_type")
+
+        self._set_on_view("gravity_on_off")
+        self._set_on_view("gravity_extra_length")
+
+        self._set_on_view("use_q_resolution")
+        self._set_on_view_q_resolution_aperture()
+        self._set_on_view("q_resolution_delta_r")
+        self._set_on_view("q_resolution_collimation_length")
+        self._set_on_view("q_resolution_moderator_file")
+
+        # Mask
+        self._set_on_view("phi_limit_min")
+        self._set_on_view("phi_limit_max")
+        self._set_on_view("phi_limit_use_mirror")
+        self._set_on_view("radius_limit_min")
+        self._set_on_view("radius_limit_max")
+
+    def _set_on_view_transmission_fit_sample_settings(self):
+        # Set transmission_sample_use_fit
+        fit_type = self._state_model.transmission_sample_fit_type
+        use_fit = fit_type is not FitType.NoFit
+        self._view.transmission_sample_use_fit = use_fit
+
+        # Set the polynomial order for sample
+        polynomial_order = self._state_model.transmission_sample_polynomial_order if fit_type is FitType.Polynomial else 2  # noqa
+        self._view.transmission_sample_polynomial_order = polynomial_order
+
+        # Set the fit type for the sample
+        fit_type = fit_type if fit_type is not FitType.NoFit else FitType.Linear
+        self._view.transmission_sample_fit_type = fit_type
+
+        # Set the wavelength
+        wavelength_min = self._state_model.transmission_sample_wavelength_min
+        wavelength_max = self._state_model.transmission_sample_wavelength_max
+        if wavelength_min and wavelength_max:
+            self._view.transmission_sample_use_wavelength = True
+            self._view.transmission_sample_wavelength_min = wavelength_min
+            self._view.transmission_sample_wavelength_max = wavelength_max
+
+    def _set_on_view_transmission_fit(self):
+        # Steps for adding the transmission fit to the view
+        # 1. Check if individual settings exist. If so then set the view to separate, else set them to both
+        # 2. Apply the settings
+        separate_settings = self._state_model.has_transmission_fit_got_separate_settings_for_sample_and_can()
+        self._view.set_fit_selection(use_separate=separate_settings)
+
+        if separate_settings:
+            self._set_on_view_transmission_fit_sample_settings()
+
+            # Set transmission_sample_can_fit
+            fit_type_can = self._state_model.transmission_can_fit_type()
+            use_can_fit = fit_type_can is FitType.NoFit
+            self._view.transmission_can_use_fit = use_can_fit
+
+            # Set the polynomial order for can
+            polynomial_order_can = self._state_model.transmission_can_polynomial_order if fit_type_can is FitType.Polynomial else 2  # noqa
+            self._view.transmission_can_polynomial_order = polynomial_order_can
+
+            # Set the fit type for the can
+            fit_type_can = fit_type_can if fit_type_can is not FitType.NoFit else FitType.Linear
+            self.transmission_can_fit_type = fit_type_can
+
+            # Set the wavelength
+            wavelength_min = self._state_model.transmission_can_wavelength_min
+            wavelength_max = self._state_model.transmission_can_wavelength_max
+            if wavelength_min and wavelength_max:
+                self._view.transmission_can_use_wavelength = True
+                self._view.transmission_can_wavelength_min = wavelength_min
+                self._view.transmission_can_wavelength_max = wavelength_max
+        else:
+            self._set_on_view_transmission_fit_sample_settings()
+
+    def _set_on_view_q_resolution_aperture(self):
+        self._set_on_view("q_resolution_source_a")
+        self._set_on_view("q_resolution_sample_a")
+        self._set_on_view("q_resolution_source_h")
+        self._set_on_view("q_resolution_sample_h")
+        self._set_on_view("q_resolution_source_w")
+        self._set_on_view("q_resolution_sample_w")
+
+        # If we have h1, h2, w1, and w2 selected then we want to select the rectangular aperture.
+        is_rectangular = self._state_model.q_resolution_source_h and self._state_model.q_resolution_sample_h and \
+                         self._state_model.q_resolution_source_w and self._state_model.q_resolution_sample_w  # noqa
+        self._view.set_q_resolution_shape_to_rectangular(is_rectangular)
+
+    def _set_on_view_q_rebin_string(self):
+        """
+        Maps the q_1d_rebin_string of the model to the q_1d_step and q_1d_step_type property of the view.
+        """
+        rebin_string = self._state_model.q_1d_rebin_string
+        # Extract the min, max and step and step type from the rebin string
+        elements = rebin_string.split(",")
+        if len(elements) == 3:
+            step_element = float(elements[1])
+            step = abs(step_element)
+            step_type = RangeStepType.Lin if step_element >= 0 else RangeStepType.Log
+
+            # Set on the view
+            self._view.q_1d_step = step
+            self._view.q_1d_step_type = step_type
+
+    def _set_on_view(self, attribute_name):
+        attribute = getattr(self._state_model, attribute_name)
+        if attribute or isinstance(attribute, bool):  # We need to be careful here. We don't want to set empty strings, or None, but we want to set boolean values. # noqa
+            setattr(self._view, attribute_name, attribute)
+
+    def _get_state_model_with_view_update(self):
+        """
+        Goes through all sub presenters and update the state model based on the views.
+
+        Note that at the moment we have set up the view and the model such that the name of a property must be the same
+        in the view and the model. This can be easily changed, but it also provides a good cohesion.
+        """
+        state_model = copy.deepcopy(self._state_model)
+
+        # If we don't have a state model then return None
+        if state_model is None:
+            return state_model
+
+        # Run tab view
+        self._set_on_state_model("zero_error_free", state_model)
+        self._set_on_state_model("save_types", state_model)
+        self._set_on_state_model("compatibility_mode", state_model)
+        self._set_on_state_model("merge_scale", state_model)
+        self._set_on_state_model("merge_shift", state_model)
+        self._set_on_state_model("merge_scale_fit", state_model)
+        self._set_on_state_model("merge_shift_fit", state_model)
+        self._set_on_state_model("merge_q_range_start", state_model)
+        self._set_on_state_model("merge_q_range_stop", state_model)
+
+        # Settings tab
+        self._set_on_state_model("reduction_dimensionality", state_model)
+        self._set_on_state_model("reduction_mode", state_model)
+        self._set_on_state_model("event_slices", state_model)
+        self._set_on_state_model("event_binning", state_model)
+
+        self._set_on_state_model("wavelength_step_type", state_model)
+        self._set_on_state_model("wavelength_min", state_model)
+        self._set_on_state_model("wavelength_max", state_model)
+        self._set_on_state_model("wavelength_step", state_model)
+
+        self._set_on_state_model("absolute_scale", state_model)
+        self._set_on_state_model("sample_shape", state_model)
+        self._set_on_state_model("sample_height", state_model)
+        self._set_on_state_model("sample_width", state_model)
+        self._set_on_state_model("sample_thickness", state_model)
+        self._set_on_state_model("z_offset", state_model)
+
+        # Adjustment tab
+        self._set_on_state_model("normalization_incident_monitor", state_model)
+        self._set_on_state_model("normalization_interpolate", state_model)
+
+        self._set_on_state_model("transmission_incident_monitor", state_model)
+        self._set_on_state_model("transmission_interpolate", state_model)
+        self._set_on_state_model("transmission_roi_files", state_model)
+        self._set_on_state_model("transmission_mask_files", state_model)
+        self._set_on_state_model("transmission_radius", state_model)
+        self._set_on_state_model("transmission_monitor", state_model)
+        self._set_on_state_model("transmission_m4_shift", state_model)
+
+        self._set_on_state_model_transmission_fit(state_model)
+
+        self._set_on_state_model("pixel_adjustment_det_1", state_model)
+        self._set_on_state_model("pixel_adjustment_det_2", state_model)
+        self._set_on_state_model("wavelength_adjustment_det_1", state_model)
+        self._set_on_state_model("wavelength_adjustment_det_2", state_model)
+
+        # Q tab
+        self._set_on_state_model("q_1d_min", state_model)
+        self._set_on_state_model("q_1d_max", state_model)
+        self._set_on_state_model_q_1d_rebin_string(state_model)
+        self._set_on_state_model("q_xy_max", state_model)
+        self._set_on_state_model("q_xy_step", state_model)
+        self._set_on_state_model("q_xy_step_type", state_model)
+
+        self._set_on_state_model("gravity_on_off", state_model)
+        self._set_on_state_model("gravity_extra_length", state_model)
+
+        self._set_on_state_model("use_q_resolution", state_model)
+        self._set_on_state_model("q_resolution_source_a", state_model)
+        self._set_on_state_model("q_resolution_sample_a", state_model)
+        self._set_on_state_model("q_resolution_source_h", state_model)
+        self._set_on_state_model("q_resolution_sample_h", state_model)
+        self._set_on_state_model("q_resolution_source_w", state_model)
+        self._set_on_state_model("q_resolution_sample_w", state_model)
+        self._set_on_state_model("q_resolution_delta_r", state_model)
+        self._set_on_state_model("q_resolution_collimation_length", state_model)
+        self._set_on_state_model("q_resolution_moderator_file", state_model)
+
+        # Mask
+        self._set_on_state_model("phi_limit_min", state_model)
+        self._set_on_state_model("phi_limit_max", state_model)
+        self._set_on_state_model("phi_limit_use_mirror", state_model)
+        self._set_on_state_model("radius_limit_min", state_model)
+        self._set_on_state_model("radius_limit_max", state_model)
+
+        return state_model
+
+    def _set_on_state_model_transmission_fit(self, state_model):
+        # Behaviour depends on the selection of the fit
+        if self._view.use_same_transmission_fit_setting_for_sample_and_can():
+            use_fit = self._view.transmission_sample_use_fit
+            fit_type = self._view.transmission_sample_fit_type
+            polynomial_order = self._view.transmission_sample_polynomial_order
+            state_model.transmission_sample_fit_type = fit_type if use_fit else FitType.NoFit
+            state_model.transmission_can_fit_type = fit_type if use_fit else FitType.NoFit
+            state_model.transmission_sample_polynomial_order = polynomial_order
+            state_model.transmission_can_polynomial_order = polynomial_order
+
+            # Wavelength settings
+            if self._view.transmission_sample_use_wavelength:
+                wavelength_min = self._view.transmission_sample_wavelength_min
+                wavelength_max = self._view.transmission_sample_wavelength_max
+                state_model.transmission_sample_wavelength_min = wavelength_min
+                state_model.transmission_sample_wavelength_max = wavelength_max
+                state_model.transmission_can_wavelength_min = wavelength_min
+                state_model.transmission_can_wavelength_max = wavelength_max
+        else:
+            # Sample
+            use_fit_sample = self._view.transmission_sample_use_fit
+            fit_type_sample = self._view.transmission_sample_fit_type
+            polynomial_order_sample = self._view.transmission_sample_polynomial_order
+            state_model.transmission_sample_fit_type = fit_type_sample if use_fit_sample else FitType.NoFit
+            state_model.transmission_sample_polynomial_order = polynomial_order_sample
+
+            # Wavelength settings
+            if self._view.transmission_sample_use_wavelength:
+                wavelength_min = self._view.transmission_sample_wavelength_min
+                wavelength_max = self._view.transmission_sample_wavelength_max
+                state_model.transmission_sample_wavelength_min = wavelength_min
+                state_model.transmission_sample_wavelength_max = wavelength_max
+
+            # Can
+            use_fit_can = self._view.transmission_can_use_fit
+            fit_type_can = self._view.transmission_can_fit_type
+            polynomial_order_can = self._view.transmission_can_polynomial_order
+            state_model.transmission_can_fit_type = fit_type_can if use_fit_can else FitType.NoFit
+            state_model.transmission_can_polynomial_order = polynomial_order_can
+
+            # Wavelength settings
+            if self._view.transmission_can_use_wavelength:
+                wavelength_min = self._view.transmission_can_wavelength_min
+                wavelength_max = self._view.transmission_can_wavelength_max
+                state_model.transmission_can_wavelength_min = wavelength_min
+                state_model.transmission_can_wavelength_max = wavelength_max
+
+    def _set_on_state_model_q_1d_rebin_string(self, state_model):
+        q_1d_min = self._view.q_1d_min
+        q_1d_max = self._view.q_1d_max
+        q_1d_step = self._view.q_1d_step
+        q_1d_step_type = self._view.q_1d_step_type
+        if q_1d_min and q_1d_max and q_1d_step and q_1d_step_type:
+            q_1d_rebin_string = str(q_1d_min) + ","
+            q_1d_step_type_factor = -1. if q_1d_step_type is RangeStepType.Log else 1.
+            q_1d_rebin_string += str(q_1d_step_type_factor*q_1d_step) + ","
+            q_1d_rebin_string += str(q_1d_max)
+            state_model.q_1d_rebin_string = q_1d_rebin_string
+
+    def _set_on_state_model(self, attribute_name, state_model):
+        attribute = getattr(self._view, attribute_name)
+        if attribute or isinstance(attribute, bool):
+            setattr(state_model, attribute_name, attribute)
+
+    def _get_table_model(self):
+        # 1. Create a new table model
+        user_file = self._view.get_user_file_path()
+        batch_file = self._view.get_batch_file_path()
+
+        table_model = TableModel()
+        table_model.user_file = user_file
+        self.batch_file = batch_file
+
+        # 2. Iterate over each row, create a table row model and insert it
+        number_of_rows = self._view.get_number_of_rows()
+        for row in range(number_of_rows):
+            sample_scatter = self._view.get_cell(row=row, column=0, convert_to=str)
+            sample_transmission = self._view.get_cell(row=row, column=1, convert_to=str)
+            sample_direct = self._view.get_cell(row=row, column=2, convert_to=str)
+            can_scatter = self._view.get_cell(row=row, column=3, convert_to=str)
+            can_transmission = self._view.get_cell(row=row, column=4, convert_to=str)
+            can_direct = self._view.get_cell(row=row, column=5, convert_to=str)
+            output_name = self._view.get_cell(row=row, column=6, convert_to=str)
+
+            # Get the options string
+            # We don't have to add the hidden column here, since it only contains information for the SANS
+            # workflow to operate properly. It however does not contain information for the
+            options_string = self._get_options(row)
+
+            table_index_model = TableIndexModel(row, sample_scatter, sample_transmission, sample_direct,
+                                                can_scatter, can_transmission, can_direct, output_name=output_name,
+                                                options_column_string=options_string)
+            table_model.add_table_entry(row, table_index_model)
+        return table_model
+
+    def _create_states(self, state_model, table_model, row_index=None):
+        """
+        Here we create the states based on the settings in the models
+        :param state_model: the state model object
+        :param table_model: the table model object
+        :param row_index: the selected row, if None then all rows are generated
+        """
+        number_of_rows = self._view.get_number_of_rows()
+        if row_index is not None:
+            # Check if the selected index is valid
+            if row_index >= number_of_rows:
+                return None
+            rows = [row_index]
+        else:
+            rows = range(number_of_rows)
+        states = {}
+        gui_state_director = GuiStateDirector(table_model, state_model, self._facility)
+        for row in rows:
+            self.sans_logger.information("Generating state for row {}".format(row))
+            if not self.is_empty_row(row):
+                try:
+                    state = gui_state_director.create_state(row)
+                    states.update({row: state})
+                except ValueError as e:
+                    self.sans_logger.error("There was a bad entry for row {}. See here for more details: {}".format(row, str(e)))  # noqa
+                    raise RuntimeError("There was a bad entry for row {}. "
+                                       "See here for more details: {}".format(row, str(e)))
+        return states
+
+    def _populate_row_in_table(self, row):
+        """
+        Adds a row to the table
+        """
+        def get_string_entry(_tag, _row):
+            _element = ""
+            if _tag in _row:
+                _element = _row[_tag]
+            return _element
+
+        # 1. Pull out the entries
+        sample_scatter = get_string_entry(BatchReductionEntry.SampleScatter, row)
+        sample_transmission = get_string_entry(BatchReductionEntry.SampleTransmission, row)
+        sample_direct = get_string_entry(BatchReductionEntry.SampleDirect, row)
+        can_scatter = get_string_entry(BatchReductionEntry.CanScatter, row)
+        can_transmission = get_string_entry(BatchReductionEntry.CanTransmission, row)
+        can_direct = get_string_entry(BatchReductionEntry.CanDirect, row)
+        output_name = get_string_entry(BatchReductionEntry.Output, row)
+
+        # 2. Create entry that can be understood by table
+        row_entry = "SampleScatter:{0},SampleTransmission:{1},SampleDirect:{2}," \
+                    "CanScatter:{3},CanTransmission:{4},CanDirect:{5},OutputName:{6}".format(sample_scatter,
+                                                                                             sample_transmission,
+                                                                                             sample_direct,
+                                                                                             can_scatter,
+                                                                                             can_transmission,
+                                                                                             can_direct,
+                                                                                             output_name)
+        self._view.add_row(row_entry)
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Settings
+    # ------------------------------------------------------------------------------------------------------------------
+    def _setup_instrument_specific_settings(self):
+        # Get the first run number of the scatter data for the first table
+        sample_scatter = self._view.get_cell(row=0, column=0, convert_to=str)
+
+        # Check if it exists at all
+        if not sample_scatter:
+            return
+
+        # Get the file information from
+        file_information_factory = SANSFileInformationFactory()
+        try:
+            self._file_information = file_information_factory.create_sans_file_information(sample_scatter)
+        except NotImplementedError:
+            self.sans_logger.warning("Could not get file information from {}.".format(sample_scatter))
+            self._file_information = None
+
+        # Provide the instrument specific settings
+        if self._file_information:
+            # Set the instrument on the table
+            instrument = self._file_information.get_instrument()
+            self._view.set_instrument_settings(instrument)
+
+            # Set the reduction mode
+            reduction_mode_list = get_reduction_mode_strings_for_gui(instrument=instrument)
+            self._view.set_reduction_modes(reduction_mode_list)
+        else:
+            self._view.set_instrument_settings(SANSInstrument.NoInstrument)
+            reduction_mode_list = get_reduction_mode_strings_for_gui()
+            self._view.set_reduction_modes(reduction_mode_list)
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Setting workaround for state in DataProcessorWidget
+    # ------------------------------------------------------------------------------------------------------------------
+    def _remove_dummy_workspaces_and_row_index(self):
+        number_of_rows = self._view.get_number_of_rows()
+        for row in range(number_of_rows):
+            self._remove_from_hidden_options(row, "InputWorkspace")
+            self._remove_from_hidden_options(row, "RowIndex")
+
+    def _set_indices(self):
+        number_of_rows = self._view.get_number_of_rows()
+        for row in range(number_of_rows):
+            to_set = Property.EMPTY_INT if self.is_empty_row(row) else row
+            self._add_to_hidden_options(row, "RowIndex", to_set)
+
+    def _set_dummy_workspace(self):
+        number_of_rows = self._view.get_number_of_rows()
+        for row in range(number_of_rows):
+            self._add_to_hidden_options(row, "InputWorkspace", SANS_DUMMY_INPUT_ALGORITHM_PROPERTY_NAME)
+
+    @staticmethod
+    def _create_dummy_input_workspace():
+        if not AnalysisDataService.doesExist(SANS_DUMMY_INPUT_ALGORITHM_PROPERTY_NAME):
+            workspace = WorkspaceFactory.create("Workspace2D", 1, 1, 1)
+            AnalysisDataService.addOrReplace(SANS_DUMMY_INPUT_ALGORITHM_PROPERTY_NAME, workspace)
+
+    @staticmethod
+    def _delete_dummy_input_workspace():
+        if AnalysisDataService.doesExist(SANS_DUMMY_INPUT_ALGORITHM_PROPERTY_NAME):
+            AnalysisDataService.remove(SANS_DUMMY_INPUT_ALGORITHM_PROPERTY_NAME)
diff --git a/scripts/SANS/sans/gui_logic/presenter/settings_diagnostic_presenter.py b/scripts/SANS/sans/gui_logic/presenter/settings_diagnostic_presenter.py
new file mode 100644
index 0000000000000000000000000000000000000000..2280cc258d61d93aadc79e0b85b29c8bf7dacc65
--- /dev/null
+++ b/scripts/SANS/sans/gui_logic/presenter/settings_diagnostic_presenter.py
@@ -0,0 +1,85 @@
+""" The settings diagnostic tab which visualizes the SANS state object. """
+
+from ui.sans_isis.settings_diagnostic_tab import SettingsDiagnosticTab
+
+
+class SettingsDiagnosticPresenter(object):
+    class ConcreteSettingsDiagnosticTabListener(SettingsDiagnosticTab.SettingsDiagnosticTabListener):
+        def __init__(self, presenter):
+            super(SettingsDiagnosticPresenter.ConcreteSettingsDiagnosticTabListener, self).__init__()
+            self._presenter = presenter
+
+        def on_row_changed(self):
+            self._presenter.on_row_changed()
+
+        def on_update_rows(self):
+            self._presenter.on_update_rows()
+
+        def on_collapse(self):
+            self._presenter.on_collapse()
+
+        def on_expand(self):
+            self._presenter.on_expand()
+
+    def __init__(self, parent_presenter):
+        super(SettingsDiagnosticPresenter, self).__init__()
+        self._view = None
+        self._parent_presenter = parent_presenter
+
+    def on_collapse(self):
+        self._view.collapse()
+
+    def on_expand(self):
+        self._view.expand()
+
+    def on_row_changed(self):
+        row_index = self._view.get_current_row()
+        state = self.get_state(row_index)
+        if state:
+            self.display_state_diagnostic_tree(state)
+
+    def on_update_rows(self):
+        """
+        Update the row selection in the combobox
+        """
+        current_row_index = self._view.get_current_row()
+        valid_row_indices = self._parent_presenter.get_row_indices()
+
+        new_row_index = -1
+        if current_row_index in valid_row_indices:
+            new_row_index = current_row_index
+        elif len(valid_row_indices) > 0:
+            new_row_index = valid_row_indices[0]
+
+        self._view.update_rows(valid_row_indices)
+
+        if new_row_index != -1:
+            self.set_row(new_row_index)
+            self.on_row_changed()
+
+    def set_row(self, index):
+        self._view.set_row(index)
+
+    def set_view(self, view):
+        if view:
+            self._view = view
+
+            # Set up row selection listener
+            listener = SettingsDiagnosticPresenter.ConcreteSettingsDiagnosticTabListener(self)
+            self._view.add_listener(listener)
+
+            # Set the default gui
+            self._set_default_gui()
+
+    def _set_default_gui(self):
+        self._view.update_rows([])
+        self.display_state_diagnostic_tree(state=None)
+
+    def get_state(self, index):
+        return self._parent_presenter.get_state_for_row(index)
+
+    def display_state_diagnostic_tree(self, state):
+        # Convert to dict before passing the state to the view
+        if state is not None:
+            state = state.property_manager
+        self._view.set_tree(state)
diff --git a/scripts/SANS/sans/gui_logic/sans_data_processor_gui_algorithm.py b/scripts/SANS/sans/gui_logic/sans_data_processor_gui_algorithm.py
new file mode 100644
index 0000000000000000000000000000000000000000..865ee1af0da5e50c00906eeba8bb9d2d54e1418a
--- /dev/null
+++ b/scripts/SANS/sans/gui_logic/sans_data_processor_gui_algorithm.py
@@ -0,0 +1,201 @@
+from mantid.kernel import (Direction, Property)
+from mantid.api import (DataProcessorAlgorithm, AlgorithmFactory, MatrixWorkspaceProperty, PropertyMode)
+from sans.common.enums import (SANSFacility, OutputMode)
+from collections import namedtuple
+from sans.gui_logic.presenter.property_manager_service import PropertyManagerService
+from sans.sans_batch import SANSBatchReduction
+
+# ----------------------------------------------------------------------------------------------------------------------
+# Globals
+# ----------------------------------------------------------------------------------------------------------------------
+SANS_DUMMY_INPUT_ALGORITHM_PROPERTY_NAME = '__sans_dummy_gui_workspace'
+SANS_DUMMY_OUTPUT_ALGORITHM_PROPERTY_NAME = '__sans_dummy_gui_workspace'
+
+
+# ----------------------------------------------------------------------------------------------------------------------
+# Set up the white list and black list properties of the data algorithm
+# ----------------------------------------------------------------------------------------------------------------------
+algorithm_list_entry = namedtuple('algorithm_list_entry', 'column_name, algorithm_property, description, '
+                                                          'show_value, default, prefix, property_type')
+
+
+def create_option_column_properties():
+    """
+    Adds a new property which is meant for the Options column.
+
+    This column should correspond to features in our settings section. We need to parse the entries before the
+    runs are processed in order to account for the settings in the Options column in the state creation.
+
+    Important note: If you add it here then you have to add it to the parsing logic, else nothing will happen with it.
+                    The important bit to edit is in gui_state_director. There the set properties are parsed.
+    """
+    props = [algorithm_list_entry(column_name="",
+                                  algorithm_property="WavelengthMin",
+                                  description='The min value of the wavelength when converting from TOF.',
+                                  show_value=True,
+                                  default='',
+                                  prefix='',
+                                  property_type=float),
+             algorithm_list_entry(column_name="",
+                                  algorithm_property="WavelengthMax",
+                                  description='The max value of the wavelength when converting from TOF.',
+                                  show_value=True,
+                                  default='',
+                                  prefix='',
+                                  property_type=float),
+             ]
+    return props
+
+
+def create_properties():
+    properties = [algorithm_list_entry(column_name="SampleScatter",
+                                       algorithm_property="SampleScatter",
+                                       description='The run number of the scatter sample',
+                                       show_value=False,
+                                       default='',
+                                       prefix='',
+                                       property_type=str),
+                  algorithm_list_entry(column_name="SampleTransmission",
+                                       algorithm_property="SampleTransmission",
+                                       description='The run number of the transmission sample',
+                                       show_value=False,
+                                       default='',
+                                       prefix='',
+                                       property_type=str),
+                  algorithm_list_entry(column_name="SampleDirect",
+                                       algorithm_property="SampleDirect",
+                                       description='The run number of the direct sample',
+                                       show_value=False,
+                                       default='',
+                                       prefix='',
+                                       property_type=str),
+                  algorithm_list_entry(column_name="CanScatter",
+                                       algorithm_property="CanScatter",
+                                       description='The run number of the scatter can',
+                                       show_value=False,
+                                       default='',
+                                       prefix='',
+                                       property_type=str),
+                  algorithm_list_entry(column_name="CanTransmission",
+                                       algorithm_property="CanTransmission",
+                                       description='The run number of the transmission can',
+                                       show_value=False,
+                                       default='',
+                                       prefix='',
+                                       property_type=str),
+                  algorithm_list_entry(column_name="CanDirect",
+                                       algorithm_property="CanDirect",
+                                       description='The run number of the direct can',
+                                       show_value=False,
+                                       default='',
+                                       prefix='',
+                                       property_type=str),
+                  algorithm_list_entry(column_name="",
+                                       algorithm_property="UseOptimizations",
+                                       description='If optimizations should be used.',
+                                       show_value=False,
+                                       default=False,
+                                       prefix='',
+                                       property_type=bool),
+                  algorithm_list_entry(column_name="OutputName",
+                                       algorithm_property="OutputName",
+                                       description='An optional custom output workspace name.',
+                                       show_value=False,
+                                       default='',
+                                       prefix='',
+                                       property_type=str),
+                  algorithm_list_entry(column_name="",
+                                       algorithm_property="RowIndex",
+                                       description='The row index (which is automatically populated by the GUI)',
+                                       show_value=False,
+                                       default=Property.EMPTY_INT,
+                                       prefix='',
+                                       property_type=int),
+                  algorithm_list_entry(column_name="",
+                                       algorithm_property="OutputMode",
+                                       description='The output mode.',
+                                       show_value=False,
+                                       default=OutputMode.to_string(OutputMode.PublishToADS),
+                                       prefix='',
+                                       property_type=bool)
+                  ]
+    return properties
+
+
+def get_white_list():
+    return create_properties()
+
+
+def get_black_list():
+    black_list = "InputWorkspace,OutputWorkspace,"
+    properties = create_properties()
+    for prop in properties:
+        if not prop.show_value:
+            black_list += prop.algorithm_property
+            black_list += ","
+    return black_list
+
+
+def get_gui_algorithm_name(facility):
+    if facility is SANSFacility.ISIS:
+        algorithm_name = "SANSGuiDataProcessorAlgorithm"
+        AlgorithmFactory.subscribe(SANSGuiDataProcessorAlgorithm)
+    else:
+        raise RuntimeError("The facility is currently not supported")
+    return algorithm_name
+
+
+class SANSGuiDataProcessorAlgorithm(DataProcessorAlgorithm):
+    def category(self):
+        return 'SANS\\Gui'
+
+    def summary(self):
+        return 'Dynamic SANS Gui algorithm.'
+
+    def PyInit(self):
+        # ------------------------------------------------------------
+        # Dummy workspace properties.
+        # ------------------------------------------------------------
+        self.declareProperty(MatrixWorkspaceProperty("InputWorkspace", SANS_DUMMY_INPUT_ALGORITHM_PROPERTY_NAME,
+                                                     optional=PropertyMode.Optional, direction=Direction.Input),
+                             doc='The input workspace (which is not used)')
+
+        self.declareProperty(MatrixWorkspaceProperty("OutputWorkspace", SANS_DUMMY_OUTPUT_ALGORITHM_PROPERTY_NAME,
+                                                     optional=PropertyMode.Optional, direction=Direction.Output),
+                             doc='The output workspace (which is not used)')
+
+        # ------------------------------------------------------------
+        # Create the properties
+        # ------------------------------------------------------------
+        properties = create_properties()
+        for prop in properties:
+            self.declareProperty(prop.algorithm_property, defaultValue=prop.default,
+                                 direction=Direction.Input, doc=prop.description)
+
+        # ------------------------------------------------------------
+        # Add properties which will show up in the options column
+        # ------------------------------------------------------------
+        properties = create_option_column_properties()
+        for prop in properties:
+            self.declareProperty(prop.algorithm_property, defaultValue=prop.default,
+                                 direction=Direction.Input, doc=prop.description)
+
+    def PyExec(self):
+        # 1. Get the index of the batch reduction
+        index = self.getProperty("RowIndex").value
+
+        if index == Property.EMPTY_INT:
+            return
+
+        # 2. Get the state for the index from the PropertyManagerDataService
+        property_manager_service = PropertyManagerService()
+        state = property_manager_service.get_single_state_from_pmds(index_to_retrieve=index)
+
+        # 3. Get some global settings
+        use_optimizations = self.getProperty("UseOptimizations").value
+        output_mode_as_string = self.getProperty("OutputMode").value
+        output_mode = OutputMode.from_string(output_mode_as_string)
+
+        # 3. Run the sans_batch script
+        sans_batch = SANSBatchReduction()
+        sans_batch(states=state, use_optimizations=use_optimizations, output_mode=output_mode)
diff --git a/scripts/SANS/sans/state/adjustment.py b/scripts/SANS/sans/state/adjustment.py
index 61db729effd2034b53cd1113a02baa8a6f763ffb..91baf0aaf0a95a986aba5405128aed456d58b03b 100644
--- a/scripts/SANS/sans/state/adjustment.py
+++ b/scripts/SANS/sans/state/adjustment.py
@@ -11,7 +11,7 @@ from sans.state.calculate_transmission import StateCalculateTransmission
 from sans.state.normalize_to_monitor import StateNormalizeToMonitor
 from sans.state.wavelength_and_pixel_adjustment import StateWavelengthAndPixelAdjustment
 from sans.state.automatic_setters import (automatic_setters)
-from sans.common.enums import SANSInstrument
+from sans.common.enums import SANSFacility
 
 
 # ----------------------------------------------------------------------------------------------------------------------
@@ -80,10 +80,10 @@ class StateAdjustmentBuilder(object):
 
 
 def get_adjustment_builder(data_info):
-    # The data state has most of the information that we require to define the move. For the factory method, only
+    # The data state has most of the information that we require to define the adjustment. For the factory method, only
     # the instrument is of relevance.
-    instrument = data_info.instrument
-    if instrument is SANSInstrument.LARMOR or instrument is SANSInstrument.LOQ or instrument is SANSInstrument.SANS2D:
+    facility = data_info.facility
+    if facility is SANSFacility.ISIS:
         return StateAdjustmentBuilder()
     else:
         raise NotImplementedError("StateAdjustmentBuilder: Could not find any valid adjustment builder for the "
diff --git a/scripts/SANS/sans/state/calculate_transmission.py b/scripts/SANS/sans/state/calculate_transmission.py
index 11324b09cadfc3d55ec67303c2835f6c69ee9030..23d27101c8f406540afe84b5d4fcb5bc6156fdde 100644
--- a/scripts/SANS/sans/state/calculate_transmission.py
+++ b/scripts/SANS/sans/state/calculate_transmission.py
@@ -28,14 +28,14 @@ class StateTransmissionFit(StateBase):
 
     def __init__(self):
         super(StateTransmissionFit, self).__init__()
-        self.fit_type = FitType.Log
+        self.fit_type = FitType.Logarithmic
         self.polynomial_order = 0
 
     def validate(self):  # noqa
         is_invalid = {}
-        if self.fit_type is not FitType.Polynomial and self.polynomial_order != 0:
-            entry = validation_message("You can only set a polynomial order of you selected polynomial fitting.",
-                                       "Make sure that you select polynomial fitting.",
+        if self.fit_type is FitType.Polynomial and self.polynomial_order == 0:
+            entry = validation_message("You can only select a polynomial fit if you set a polynomial order (2 to 6).",
+                                       "Make sure that you select a polynomial order.",
                                        {"fit_type": self.fit_type,
                                         "polynomial_order": self.polynomial_order})
             is_invalid.update(entry)
@@ -316,6 +316,17 @@ class StateCalculateTransmissionLARMOR(StateCalculateTransmission):
         super(StateCalculateTransmissionLARMOR, self).validate()
 
 
+class StateCalculateTransmissionZOOM(StateCalculateTransmission):
+    def __init__(self):
+        super(StateCalculateTransmissionZOOM, self).__init__()
+        # Set the LOQ full wavelength range
+        self.wavelength_full_range_low = Configurations.ZOOM.wavelength_full_range_low
+        self.wavelength_full_range_high = Configurations.ZOOM.wavelength_full_range_high
+
+    def validate(self):
+        super(StateCalculateTransmissionZOOM, self).validate()
+
+
 # ----------------------------------------------------------------------------------------------------------------------
 # Builder
 # ----------------------------------------------------------------------------------------------------------------------
@@ -378,6 +389,19 @@ class StateCalculateTransmissionBuilderLARMOR(object):
         return copy.copy(self.state)
 
 
+class StateCalculateTransmissionBuilderZOOM(object):
+    @automatic_setters(StateCalculateTransmissionZOOM)
+    def __init__(self, data_info):
+        super(StateCalculateTransmissionBuilderZOOM, self).__init__()
+        self._data = data_info
+        self.state = StateCalculateTransmissionZOOM()
+        set_default_monitors(self.state, self._data)
+
+    def build(self):
+        self.state.validate()
+        return copy.copy(self.state)
+
+
 # ------------------------------------------
 # Factory method for StateCalculateTransmissionBuilder
 # ------------------------------------------
@@ -389,6 +413,8 @@ def get_calculate_transmission_builder(data_info):
         return StateCalculateTransmissionBuilderSANS2D(data_info)
     elif instrument is SANSInstrument.LOQ:
         return StateCalculateTransmissionBuilderLOQ(data_info)
+    elif instrument is SANSInstrument.ZOOM:
+        return StateCalculateTransmissionBuilderZOOM(data_info)
     else:
         raise NotImplementedError("StateCalculateTransmissionBuilder: Could not find any valid transmission "
                                   "builder for the specified StateData object {0}".format(str(data_info)))
diff --git a/scripts/SANS/sans/state/compatibility.py b/scripts/SANS/sans/state/compatibility.py
index e380995377f0e86324756a4a357ab867cd06c914..ca7444acf10873fb3d70c223be8ba31859ac255d 100644
--- a/scripts/SANS/sans/state/compatibility.py
+++ b/scripts/SANS/sans/state/compatibility.py
@@ -10,7 +10,7 @@ from __future__ import (absolute_import, division, print_function)
 import copy
 from sans.state.state_base import (StateBase, rename_descriptor_names, BoolParameter, StringParameter)
 from sans.state.automatic_setters import (automatic_setters)
-from sans.common.enums import SANSInstrument
+from sans.common.enums import SANSFacility
 
 
 # ----------------------------------------------------------------------------------------------------------------------
@@ -45,8 +45,8 @@ class StateCompatibilityBuilder(object):
 
 
 def get_compatibility_builder(data_info):
-    instrument = data_info.instrument
-    if instrument is SANSInstrument.LARMOR or instrument is SANSInstrument.LOQ or instrument is SANSInstrument.SANS2D:
+    facility = data_info.facility
+    if facility is SANSFacility.ISIS:
         return StateCompatibilityBuilder()
     else:
         raise NotImplementedError("StateCompatibilityBuilder: Could not find any valid compatibility builder for the "
diff --git a/scripts/SANS/sans/state/convert_to_q.py b/scripts/SANS/sans/state/convert_to_q.py
index 08f599e2d060cc208735e943f65533c4b3616ce5..ea1dc343c399ec1f00165f3cc8d2bcccc6c6206a 100644
--- a/scripts/SANS/sans/state/convert_to_q.py
+++ b/scripts/SANS/sans/state/convert_to_q.py
@@ -7,7 +7,7 @@ import json
 import copy
 from sans.state.state_base import (StateBase, rename_descriptor_names, BoolParameter, PositiveFloatParameter,
                                    ClassTypeParameter, StringParameter)
-from sans.common.enums import (ReductionDimensionality, RangeStepType, SANSInstrument)
+from sans.common.enums import (ReductionDimensionality, RangeStepType, SANSFacility)
 from sans.state.state_functions import (is_pure_none_or_not_none, is_not_none_and_first_larger_than_second,
                                         validation_message)
 from sans.state.automatic_setters import (automatic_setters)
@@ -167,10 +167,10 @@ class StateConvertToQBuilder(object):
 # Factory method for StateConvertToQBuilder
 # ------------------------------------------
 def get_convert_to_q_builder(data_info):
-    # The data state has most of the information that we require to define the move. For the factory method, only
-    # the instrument is of relevance.
-    instrument = data_info.instrument
-    if instrument is SANSInstrument.LARMOR or instrument is SANSInstrument.LOQ or instrument is SANSInstrument.SANS2D:
+    # The data state has most of the information that we require to define the q conversion.
+    # For the factory method, only the facility/instrument is of relevance.
+    facility = data_info.facility
+    if facility is SANSFacility.ISIS:
         return StateConvertToQBuilder()
     else:
         raise NotImplementedError("StateConvertToQBuilder: Could not find any valid save builder for the "
diff --git a/scripts/SANS/sans/state/data.py b/scripts/SANS/sans/state/data.py
index ff6b8fbf56cd0a54a27e845e5e8b4e534b5d41c5..93e2835f8d71edb5594fef40eadad9ea35d8df1a 100644
--- a/scripts/SANS/sans/state/data.py
+++ b/scripts/SANS/sans/state/data.py
@@ -39,6 +39,7 @@ class StateData(StateBase):
     sample_scatter_run_number = PositiveIntegerParameter()
     sample_scatter_is_multi_period = BoolParameter()
     instrument = ClassTypeParameter(SANSInstrument)
+    facility = ClassTypeParameter(SANSFacility)
     idf_file_path = StringParameter()
     ipf_file_path = StringParameter()
 
@@ -57,12 +58,13 @@ class StateData(StateBase):
         # This should be reset by the builder. Setting this to NoInstrument ensure that we will trip early on,
         # in case this is not set, for example by not using the builders.
         self.instrument = SANSInstrument.NoInstrument
+        self.facility = SANSFacility.NoFacility
 
     def validate(self):
         is_invalid = dict()
 
         # A sample scatter must be specified
-        if self.sample_scatter is None:
+        if not self.sample_scatter:
             entry = validation_message("Sample scatter was not specified.",
                                        "Make sure that the sample scatter file is specified.",
                                        {"sample_scatter": self.sample_scatter})
@@ -109,8 +111,10 @@ def set_information_from_file(data_info):
     file_information_factory = SANSFileInformationFactory()
     file_information = file_information_factory.create_sans_file_information(file_name)
     instrument = file_information.get_instrument()
+    facility = file_information.get_facility()
     run_number = file_information.get_run_number()
     data_info.instrument = instrument
+    data_info.facility = facility
     data_info.sample_scatter_run_number = run_number
     data_info.sample_scatter_is_multi_period = file_information.get_number_of_periods() > 1
     data_info.idf_file_path = file_information.get_idf_file_path()
diff --git a/scripts/SANS/sans/state/mask.py b/scripts/SANS/sans/state/mask.py
index d374a86ccffb38df35151de05213282bf86b1c60..481381d49e419e0a99de0949f8d09c28aac1dc56 100644
--- a/scripts/SANS/sans/state/mask.py
+++ b/scripts/SANS/sans/state/mask.py
@@ -6,7 +6,7 @@ from __future__ import (absolute_import, division, print_function)
 import json
 import copy
 from sans.state.state_base import (StateBase, BoolParameter, StringListParameter, StringParameter,
-                                   PositiveFloatParameter, FloatParameter, FloatListParameter,
+                                   PositiveFloatParameter, FloatParameter, FloatListParameter, FloatWithNoneParameter,
                                    DictParameter, PositiveIntegerListParameter, rename_descriptor_names)
 from sans.state.state_functions import (is_pure_none_or_not_none, validation_message, set_detector_names)
 from sans.state.automatic_setters import (automatic_setters)
@@ -160,7 +160,7 @@ class StateMaskDetector(StateBase):
                     is_invalid, "spectrum_range_start", "spectrum_range_stop", "spectrum_range")
 
         if is_invalid:
-            raise ValueError("StateMoveDetectorISIS: The provided inputs are illegal. "
+            raise ValueError("StateMaskDetector: The provided inputs are illegal. "
                              "Please see: {0}".format(json.dumps(is_invalid)))
 
 
@@ -178,8 +178,8 @@ class StateMask(StateBase):
     mask_files = StringListParameter()
 
     # Angle masking
-    phi_min = FloatParameter()
-    phi_max = FloatParameter()
+    phi_min = FloatWithNoneParameter()
+    phi_max = FloatWithNoneParameter()
     use_mask_phi_mirror = BoolParameter()
 
     # Beam stop
@@ -200,10 +200,6 @@ class StateMask(StateBase):
 
     def __init__(self):
         super(StateMask, self).__init__()
-        # Setup the detectors
-        self.detectors = {DetectorType.to_string(DetectorType.LAB): StateMaskDetector(),
-                          DetectorType.to_string(DetectorType.HAB): StateMaskDetector()}
-
         # IDF Path
         self.idf_path = ""
 
@@ -252,6 +248,52 @@ class StateMask(StateBase):
                              "Please see: {0}".format(json.dumps(is_invalid)))
 
 
+@rename_descriptor_names
+class StateMaskSANS2D(StateMask):
+    def __init__(self):
+        super(StateMaskSANS2D, self).__init__()
+        # Setup the detectors
+        self.detectors = {DetectorType.to_string(DetectorType.LAB): StateMaskDetector(),
+                          DetectorType.to_string(DetectorType.HAB): StateMaskDetector()}
+
+    def validate(self):
+        super(StateMaskSANS2D, self).validate()
+
+
+@rename_descriptor_names
+class StateMaskLOQ(StateMask):
+    def __init__(self):
+        super(StateMaskLOQ, self).__init__()
+        # Setup the detectors
+        self.detectors = {DetectorType.to_string(DetectorType.LAB): StateMaskDetector(),
+                          DetectorType.to_string(DetectorType.HAB): StateMaskDetector()}
+
+    def validate(self):
+        super(StateMaskLOQ, self).validate()
+
+
+@rename_descriptor_names
+class StateMaskLARMOR(StateMask):
+    def __init__(self):
+        super(StateMaskLARMOR, self).__init__()
+        # Setup the detectors
+        self.detectors = {DetectorType.to_string(DetectorType.LAB): StateMaskDetector()}
+
+    def validate(self):
+        super(StateMaskLARMOR, self).validate()
+
+
+@rename_descriptor_names
+class StateMaskZOOM(StateMask):
+    def __init__(self):
+        super(StateMaskZOOM, self).__init__()
+        # Setup the detectors
+        self.detectors = {DetectorType.to_string(DetectorType.LAB): StateMaskDetector()}
+
+    def validate(self):
+        super(StateMaskZOOM, self).validate()
+
+
 # ----------------------------------------------------------------------------------------------------------------------
 # Builder
 # ----------------------------------------------------------------------------------------------------------------------
@@ -267,10 +309,10 @@ def setup_idf_and_ipf_content(move_info, data_info):
 
 class StateMaskBuilder(object):
     @automatic_setters(StateMask)
-    def __init__(self, data_info):
+    def __init__(self, data_info, state):
         super(StateMaskBuilder, self).__init__()
         self._data = data_info
-        self.state = StateMask()
+        self.state = state
         setup_idf_and_ipf_content(self.state, data_info)
 
     def set_single_spectra_on_detector(self, single_spectra):
@@ -327,11 +369,17 @@ class StateMaskBuilder(object):
 
 
 def get_mask_builder(data_info):
-    # The data state has most of the information that we require to define the move. For the factory method, only
-    # the instrument is of relevance.
+    # The data state has most of the information that we require to define the mask. For the factory method, only
+    # the facility/instrument is of relevance.
     instrument = data_info.instrument
-    if instrument is SANSInstrument.LARMOR or instrument is SANSInstrument.LOQ or instrument is SANSInstrument.SANS2D:
-        return StateMaskBuilder(data_info)
+    if instrument is SANSInstrument.SANS2D:
+        return StateMaskBuilder(data_info, StateMaskSANS2D())
+    elif instrument is SANSInstrument.LOQ:
+        return StateMaskBuilder(data_info, StateMaskLOQ())
+    elif instrument is SANSInstrument.LARMOR:
+        return StateMaskBuilder(data_info, StateMaskLARMOR())
+    elif instrument is SANSInstrument.ZOOM:
+        return StateMaskBuilder(data_info, StateMaskZOOM())
     else:
         raise NotImplementedError("StateMaskBuilder: Could not find any valid mask builder for the "
                                   "specified StateData object {0}".format(str(data_info)))
diff --git a/scripts/SANS/sans/state/move.py b/scripts/SANS/sans/state/move.py
index 936029815fdaeb6ce77dc06fe177ea65fc5f2afb..31b7a9a3acb1787bd4256c65840c657fe265cf5b 100644
--- a/scripts/SANS/sans/state/move.py
+++ b/scripts/SANS/sans/state/move.py
@@ -186,6 +186,24 @@ class StateMoveLARMOR(StateMove):
         super(StateMoveLARMOR, self).validate()
 
 
+@rename_descriptor_names
+class StateMoveZOOM(StateMove):
+    lab_detector_default_sd_m = FloatParameter()
+
+    def __init__(self):
+        super(StateMoveZOOM, self).__init__()
+        self.lab_detector_default_sd_m = 0.0
+
+        # Set the monitor names
+        self.monitor_names = {}
+
+        # Setup the detectors
+        self.detectors = {DetectorType.to_string(DetectorType.LAB): StateMoveDetector()}
+
+    def validate(self):
+        super(StateMoveZOOM, self).validate()
+
+
 # ----------------------------------------------------------------------------------------------------------------------
 # Builder
 # ----------------------------------------------------------------------------------------------------------------------
@@ -239,6 +257,30 @@ class StateMoveSANS2DBuilder(object):
         return value / 1000.
 
 
+class StateMoveZOOMBuilder(object):
+    @automatic_setters(StateMoveZOOM, exclusions=["detector_name", "detector_name_short", "monitor_names"])
+    def __init__(self, data_info):
+        super(StateMoveZOOMBuilder, self).__init__()
+        self.state = StateMoveZOOM()
+        # TODO: At the moment we set the monitor names up manually here. In principle we have all necessary information
+        #       in the IDF we should be able to parse it and get.
+        invalid_monitor_names = ["monitor5", "monitor6", "monitor7", "monitor8", "monitor9", "monitor10"]
+        invalid_detector_types = [DetectorType.HAB]
+        setup_idf_and_ipf_content(self.state, data_info,
+                                  invalid_detector_types=invalid_detector_types,
+                                  invalid_monitor_names=invalid_monitor_names)
+
+    def build(self):
+        self.state.validate()
+        return copy.copy(self.state)
+
+    def convert_pos1(self, value):
+        return value / 1000.
+
+    def convert_pos2(self, value):
+        return value / 1000.
+
+
 class StateMoveLARMORBuilder(object):
     @automatic_setters(StateMoveLARMOR, exclusions=["detector_name", "detector_name_short", "monitor_names"])
     def __init__(self, data_info):
@@ -281,6 +323,8 @@ def get_move_builder(data_info):
         return StateMoveSANS2DBuilder(data_info)
     elif instrument is SANSInstrument.LARMOR:
         return StateMoveLARMORBuilder(data_info)
+    elif instrument is SANSInstrument.ZOOM:
+        return StateMoveZOOMBuilder(data_info)
     else:
         raise NotImplementedError("StateMoveBuilder: Could not find any valid move builder for the "
                                   "specified StateData object {0}".format(str(data_info)))
diff --git a/scripts/SANS/sans/state/normalize_to_monitor.py b/scripts/SANS/sans/state/normalize_to_monitor.py
index 64732fb580ad97dcd592d3df69daf5d5baf108ca..5c1aaedae558f975a3146d7a7de1688c7bcda3ca 100644
--- a/scripts/SANS/sans/state/normalize_to_monitor.py
+++ b/scripts/SANS/sans/state/normalize_to_monitor.py
@@ -202,7 +202,7 @@ class StateNormalizeToMonitorBuilderLOQ(object):
 
 def get_normalize_to_monitor_builder(data_info):
     instrument = data_info.instrument
-    if instrument is SANSInstrument.LARMOR or instrument is SANSInstrument.SANS2D:
+    if instrument is SANSInstrument.LARMOR or instrument is SANSInstrument.SANS2D or instrument is SANSInstrument.ZOOM:
         return StateNormalizeToMonitorBuilder(data_info)
     elif instrument is SANSInstrument.LOQ:
         return StateNormalizeToMonitorBuilderLOQ(data_info)
diff --git a/scripts/SANS/sans/state/reduction_mode.py b/scripts/SANS/sans/state/reduction_mode.py
index c894d1ebf1d025ebf6b751e556e8dad0b3620ec6..f41d763c2a75a497fb6e3ccaa032cb6ec1fae09d 100644
--- a/scripts/SANS/sans/state/reduction_mode.py
+++ b/scripts/SANS/sans/state/reduction_mode.py
@@ -10,7 +10,7 @@ import copy
 from sans.state.state_base import (StateBase, ClassTypeParameter, FloatParameter, DictParameter,
                                    FloatWithNoneParameter, rename_descriptor_names)
 from sans.common.enums import (ReductionMode, ISISReductionMode, ReductionDimensionality, FitModeForMerge,
-                               SANSInstrument, DetectorType)
+                               SANSFacility, DetectorType)
 from sans.common.xml_parsing import get_named_elements_from_ipf_file
 from sans.state.automatic_setters import (automatic_setters)
 
@@ -119,10 +119,10 @@ class StateReductionModeBuilder(object):
 
 
 def get_reduction_mode_builder(data_info):
-    # The data state has most of the information that we require to define the move. For the factory method, only
-    # the instrument is of relevance.
-    instrument = data_info.instrument
-    if instrument is SANSInstrument.LARMOR or instrument is SANSInstrument.LOQ or instrument is SANSInstrument.SANS2D:
+    # The data state has most of the information that we require to define the reduction_mode.
+    # For the factory method, only the facility/instrument is of relevance.
+    facility = data_info.facility
+    if facility is SANSFacility.ISIS:
         return StateReductionModeBuilder(data_info)
     else:
         raise NotImplementedError("StateReductionBuilder: Could not find any valid reduction builder for the "
diff --git a/scripts/SANS/sans/state/save.py b/scripts/SANS/sans/state/save.py
index ada952bf27d8fb957044347ed1bafa4f7fba520a..4ed3812cd3c563bb1a6379e6d5e9de7c44f8825e 100644
--- a/scripts/SANS/sans/state/save.py
+++ b/scripts/SANS/sans/state/save.py
@@ -6,7 +6,7 @@ from __future__ import (absolute_import, division, print_function)
 import copy
 from sans.state.state_base import (StateBase, BoolParameter, StringParameter, StringWithNoneParameter,
                                    ClassTypeListParameter, rename_descriptor_names)
-from sans.common.enums import (SaveType, SANSInstrument)
+from sans.common.enums import (SaveType, SANSFacility)
 from sans.state.automatic_setters import (automatic_setters)
 
 
@@ -46,10 +46,10 @@ class StateSaveBuilder(object):
 
 
 def get_save_builder(data_info):
-    # The data state has most of the information that we require to define the move. For the factory method, only
-    # the instrument is of relevance.
-    instrument = data_info.instrument
-    if instrument is SANSInstrument.LARMOR or instrument is SANSInstrument.LOQ or instrument is SANSInstrument.SANS2D:
+    # The data state has most of the information that we require to define the save. For the factory method, only
+    # the facility/instrument is of relevance.
+    facility = data_info.facility
+    if facility is SANSFacility.ISIS:
         return StateSaveBuilder()
     else:
         raise NotImplementedError("StateSaveBuilder: Could not find any valid save builder for the "
diff --git a/scripts/SANS/sans/state/scale.py b/scripts/SANS/sans/state/scale.py
index d3fda2846507ea04ee9024bcfdd4de1d563e17bf..43fb51bbeebdd20d36a3235c683fb3039588459f 100644
--- a/scripts/SANS/sans/state/scale.py
+++ b/scripts/SANS/sans/state/scale.py
@@ -3,7 +3,7 @@
 from __future__ import (absolute_import, division, print_function)
 import copy
 from sans.state.state_base import (StateBase, rename_descriptor_names, PositiveFloatParameter, ClassTypeParameter)
-from sans.common.enums import (SampleShape, SANSInstrument)
+from sans.common.enums import (SampleShape, SANSFacility)
 from sans.common.file_information import (SANSFileInformationFactory)
 from sans.state.automatic_setters import (automatic_setters)
 
@@ -71,10 +71,10 @@ class StateScaleBuilder(object):
 # Factory method for SANStateScaleBuilder
 # ---------------------------------------
 def get_scale_builder(data_info):
-    # The data state has most of the information that we require to define the move. For the factory method, only
-    # the instrument is of relevance.
-    instrument = data_info.instrument
-    if instrument is SANSInstrument.LARMOR or instrument is SANSInstrument.LOQ or instrument is SANSInstrument.SANS2D:
+    # The data state has most of the information that we require to define the scaling. For the factory method, only
+    # the facility/instrument is of relevance.
+    facility = data_info.facility
+    if facility is SANSFacility.ISIS:
         return StateScaleBuilder(data_info)
     else:
         raise NotImplementedError("StateScaleBuilder: Could not find any valid scale builder for the "
diff --git a/scripts/SANS/sans/state/slice_event.py b/scripts/SANS/sans/state/slice_event.py
index 9677ff61bb152cbfffbcdf6c1f4be5fbc23ca6a0..8738e759c5a1bcdd254a2cd907694e4a70ffa1dd 100644
--- a/scripts/SANS/sans/state/slice_event.py
+++ b/scripts/SANS/sans/state/slice_event.py
@@ -5,7 +5,7 @@ import json
 import copy
 from sans.state.state_base import (StateBase, rename_descriptor_names, FloatListParameter)
 from sans.state.state_functions import (is_pure_none_or_not_none, validation_message)
-from sans.common.enums import SANSInstrument
+from sans.common.enums import SANSFacility
 from sans.state.automatic_setters import (automatic_setters)
 
 
@@ -90,8 +90,8 @@ class StateSliceEventBuilder(object):
 # Factory method for SANStateDataBuilder
 # ------------------------------------------
 def get_slice_event_builder(data_info):
-    instrument = data_info.instrument
-    if instrument is SANSInstrument.LARMOR or instrument is SANSInstrument.LOQ or instrument is SANSInstrument.SANS2D:
+    facility = data_info.facility
+    if facility is SANSFacility.ISIS:
         return StateSliceEventBuilder()
     else:
         raise NotImplementedError("StateSliceEventBuilder: Could not find any valid slice builder for the "
diff --git a/scripts/SANS/sans/state/state.py b/scripts/SANS/sans/state/state.py
index e186dd215e24e991df237e2ad2658a88a3643c3a..3888fbb09e9718c80da380669b641a147be60576 100644
--- a/scripts/SANS/sans/state/state.py
+++ b/scripts/SANS/sans/state/state.py
@@ -7,7 +7,7 @@ import json
 import pickle
 import inspect
 import copy
-from sans.common.enums import SANSInstrument
+from sans.common.enums import SANSFacility
 from sans.state.state_base import (StateBase, TypedParameter,
                                    rename_descriptor_names, validator_sub_state)
 from sans.state.data import StateData
@@ -113,8 +113,8 @@ class StateBuilder(object):
 # Factory method for SANStateDataBuilder
 # ------------------------------------------
 def get_state_builder(data_info):
-    instrument = data_info.instrument
-    if instrument is SANSInstrument.LARMOR or instrument is SANSInstrument.LOQ or instrument is SANSInstrument.SANS2D:
+    facility = data_info.facility
+    if facility is SANSFacility.ISIS:
         return StateBuilder()
     else:
         raise NotImplementedError("SANSStateBuilder: Could not find any valid state builder for the "
diff --git a/scripts/SANS/sans/state/state_functions.py b/scripts/SANS/sans/state/state_functions.py
index 4703c51eec75e57a848b7fb25c17faded07746c3..6f58b961f59455f01807fdf27353a835dc5a3dfc 100644
--- a/scripts/SANS/sans/state/state_functions.py
+++ b/scripts/SANS/sans/state/state_functions.py
@@ -98,7 +98,6 @@ def set_detector_names(state, ipf_path, invalid_detector_types=None):
             detector_name_short = found_detector_names[detector_name_short_tag]
         except KeyError:
             continue
-
         state.detectors[detector_type].detector_name = detector_name
         state.detectors[detector_type].detector_name_short = detector_name_short
 
diff --git a/scripts/SANS/sans/state/wavelength.py b/scripts/SANS/sans/state/wavelength.py
index 4ea26bcd9eec92b8c15a63eaa0bd1a7cf37fcd52..5294698c587ecca7857b68e75b901ab926c53c86 100644
--- a/scripts/SANS/sans/state/wavelength.py
+++ b/scripts/SANS/sans/state/wavelength.py
@@ -5,7 +5,7 @@ import json
 import copy
 
 from sans.state.state_base import (StateBase, PositiveFloatParameter, ClassTypeParameter, rename_descriptor_names)
-from sans.common.enums import (RebinType, RangeStepType, SANSInstrument)
+from sans.common.enums import (RebinType, RangeStepType, SANSFacility)
 from sans.state.state_functions import (is_not_none_and_first_larger_than_second, one_is_none, validation_message)
 from sans.state.automatic_setters import (automatic_setters)
 
@@ -63,8 +63,8 @@ class StateWavelengthBuilder(object):
 
 
 def get_wavelength_builder(data_info):
-    instrument = data_info.instrument
-    if instrument is SANSInstrument.LARMOR or instrument is SANSInstrument.LOQ or instrument is SANSInstrument.SANS2D:
+    facility = data_info.facility
+    if facility is SANSFacility.ISIS:
         return StateWavelengthBuilder()
     else:
         raise NotImplementedError("StateWavelengthBuilder: Could not find any valid wavelength builder for the "
diff --git a/scripts/SANS/sans/state/wavelength_and_pixel_adjustment.py b/scripts/SANS/sans/state/wavelength_and_pixel_adjustment.py
index a735869b97cee92455faf8b71e1cd21a34028fa4..f97a30caf22bb779207ba8249678b8ec5368f761 100644
--- a/scripts/SANS/sans/state/wavelength_and_pixel_adjustment.py
+++ b/scripts/SANS/sans/state/wavelength_and_pixel_adjustment.py
@@ -8,7 +8,7 @@ import copy
 from sans.state.state_base import (StateBase, rename_descriptor_names, StringParameter,
                                    ClassTypeParameter, PositiveFloatParameter, DictParameter)
 from sans.state.state_functions import (is_not_none_and_first_larger_than_second, one_is_none, validation_message)
-from sans.common.enums import (RangeStepType, DetectorType, SANSInstrument)
+from sans.common.enums import (RangeStepType, DetectorType, SANSFacility)
 from sans.state.automatic_setters import (automatic_setters)
 
 
@@ -96,8 +96,8 @@ class StateWavelengthAndPixelAdjustmentBuilder(object):
 
 
 def get_wavelength_and_pixel_adjustment_builder(data_info):
-    instrument = data_info.instrument
-    if instrument is SANSInstrument.LARMOR or instrument is SANSInstrument.SANS2D or instrument is SANSInstrument.LOQ:
+    facility = data_info.facility
+    if facility is SANSFacility.ISIS:
         return StateWavelengthAndPixelAdjustmentBuilder(data_info)
     else:
         raise NotImplementedError("StateWavelengthAndPixelAdjustmentBuilder: Could not find any valid "
diff --git a/scripts/SANS/sans/test_helper/common.py b/scripts/SANS/sans/test_helper/common.py
new file mode 100644
index 0000000000000000000000000000000000000000..58e53993ae20e4347f95888a373a4d58d9fcec06
--- /dev/null
+++ b/scripts/SANS/sans/test_helper/common.py
@@ -0,0 +1,16 @@
+import mantid
+import os
+
+
+def remove_file(test_file_path):
+    if os.path.exists(test_file_path):
+        os.remove(test_file_path)
+
+
+def save_to_csv(content):
+    test_file_path = os.path.join(mantid.config.getString('defaultsave.directory'), 'sans_batch_test_file.csv')
+    remove_file(test_file_path)
+
+    with open(test_file_path, 'w') as f:
+        f.write(content)
+    return test_file_path
diff --git a/scripts/SANS/sans/test_helper/mock_objects.py b/scripts/SANS/sans/test_helper/mock_objects.py
new file mode 100644
index 0000000000000000000000000000000000000000..bc3b45a0aef75f5b0537eb0a10a47b9328c06813
--- /dev/null
+++ b/scripts/SANS/sans/test_helper/mock_objects.py
@@ -0,0 +1,215 @@
+from __future__ import (absolute_import)
+
+from ui.sans_isis.sans_data_processor_gui import SANSDataProcessorGui
+from ui.sans_isis.settings_diagnostic_tab import SettingsDiagnosticTab
+from ui.sans_isis.masking_table import MaskingTable
+from sans.gui_logic.presenter.run_tab_presenter import RunTabPresenter
+from sans.common.enums import (RangeStepType, OutputMode)
+from sans.test_helper.test_director import TestDirector
+
+import sys
+if sys.version_info.major == 3:
+    from unittest import mock
+else:
+    import mock
+
+
+def create_mock_settings_diagnostic_tab():
+    view = mock.create_autospec(SettingsDiagnosticTab, spec_set=False)
+    view.get_current_row = mock.MagicMock(return_value=3)
+    return view
+
+
+def create_mock_masking_table():
+    view = mock.create_autospec(MaskingTable, spec_set=False)
+    view.get_current_row = mock.MagicMock(return_value=3)
+    return view
+
+
+def get_cell_mock(row, column, convert_to=None):
+    _ = convert_to  # noqa
+    if row == 0:
+        # For the first row we return the
+        # all of hte sample data
+        if column == 0:
+            return "SANS2D00022024"
+        elif column == 1:
+            return "SANS2D00022048"
+        elif column == 2:
+            return "SANS2D00022048"
+        else:
+            return ""
+    else:
+        # For the other rows, we only return sample scatter
+        if column == 0:
+            return "SANS2D00022024"
+        else:
+            return ""
+
+
+mock_listener_list = []
+
+
+def on_load_user_file_mock():
+    for listener in mock_listener_list:
+        listener.on_user_file_load()
+
+
+def on_load_batch_file_mock():
+    for listener in mock_listener_list:
+        listener.on_batch_file_load()
+
+
+def add_listener_mock(listener):
+    mock_listener_list.append(listener)
+
+
+def create_mock_view(user_file_path, batch_file_path=None):
+    view = mock.create_autospec(SANSDataProcessorGui, spec_set=False)
+    view.get_user_file_path = mock.Mock(return_value=user_file_path)
+    view.get_cell = mock.MagicMock(side_effect=get_cell_mock)
+    view.get_batch_file_path = mock.MagicMock(return_value=batch_file_path)
+    view.get_number_of_rows = mock.MagicMock(return_value=2)
+
+    # Add the settings diagnostic mock
+    settings_diagnostic_tab = create_mock_settings_diagnostic_tab()
+    view.settings_diagnostic_tab = settings_diagnostic_tab
+
+    # Add the masking table view
+    masking_table = create_mock_masking_table()
+    view.masking_table = masking_table
+
+    # ---------------------
+    # Mocking properties
+    # ---------------------
+    _event_slices = mock.PropertyMock(return_value="")
+    type(view).event_slices = _event_slices
+
+    _merge_scale = mock.PropertyMock(return_value=1.)
+    type(view).merge_scale = _merge_scale
+
+    _merge_shift = mock.PropertyMock(return_value=0.)
+    type(view).merge_shift = _merge_shift
+
+    _merge_q_range_start = mock.PropertyMock(return_value=None)
+    type(view).merge_q_range_start = _merge_q_range_start
+
+    _merge_q_range_stop = mock.PropertyMock(return_value=None)
+    type(view).merge_q_range_stop = _merge_q_range_stop
+
+    _merge_q_range_stop = mock.PropertyMock(return_value=None)
+    type(view).merge_q_range_stop = _merge_q_range_stop
+
+    _sample_height = mock.PropertyMock(return_value=None)
+    type(view).sample_height = _sample_height
+
+    _sample_width = mock.PropertyMock(return_value=None)
+    type(view).sample_width = _sample_width
+
+    _sample_thickness = mock.PropertyMock(return_value=None)
+    type(view).sample_thickness = _sample_thickness
+
+    _sample_shape = mock.PropertyMock(return_value=None)
+    type(view).sample_shape = _sample_shape
+
+    _pixel_adjustment_det_1 = mock.PropertyMock(return_value="")
+    type(view).pixel_adjustment_det_1 = _pixel_adjustment_det_1
+
+    _pixel_adjustment_det_2 = mock.PropertyMock(return_value="")
+    type(view).pixel_adjustment_det_2 = _pixel_adjustment_det_2
+
+    _wavelength_adjustment_det_1 = mock.PropertyMock(return_value="")
+    type(view).wavelength_adjustment_det_1 = _wavelength_adjustment_det_1
+
+    _wavelength_adjustment_det_2 = mock.PropertyMock(return_value="")
+    type(view).wavelength_adjustment_det_2 = _wavelength_adjustment_det_2
+
+    _gravity_extra_length = mock.PropertyMock(return_value=None)
+    type(view).gravity_extra_length = _gravity_extra_length
+
+    _q_resolution_source_h = mock.PropertyMock(return_value=None)
+    type(view).q_resolution_source_h = _q_resolution_source_h
+
+    _q_resolution_sample_h = mock.PropertyMock(return_value=None)
+    type(view).q_resolution_sample_h = _q_resolution_sample_h
+
+    _q_resolution_source_w = mock.PropertyMock(return_value=None)
+    type(view).q_resolution_source_w = _q_resolution_source_w
+
+    _q_resolution_sample_w = mock.PropertyMock(return_value=None)
+    type(view).q_resolution_sample_w = _q_resolution_sample_w
+
+    _phi_limit_min = mock.PropertyMock(return_value=None)
+    type(view).phi_limit_min = _phi_limit_min
+
+    _phi_limit_max = mock.PropertyMock(return_value=None)
+    type(view).phi_limit_max = _phi_limit_max
+
+    _phi_limit_max = mock.PropertyMock(return_value=None)
+    type(view).phi_limit_max = _phi_limit_max
+
+    _q_1d_step = mock.PropertyMock(return_value=.001)
+    type(view).q_1d_step = _q_1d_step
+
+    _q_1d_step_type = mock.PropertyMock(return_value=RangeStepType.Lin)
+    type(view)._q_1d_step_type = _q_1d_step_type
+
+    return view, settings_diagnostic_tab, masking_table
+
+
+def create_mock_view2(user_file_path, batch_file_path=None):
+    global mock_listener_list
+    mock_listener_list = []
+    view, _, _ = create_mock_view(user_file_path, batch_file_path)
+
+    view.add_listener = mock.MagicMock(side_effect=add_listener_mock)
+    view._on_user_file_load = mock.MagicMock(side_effect=on_load_user_file_mock)
+    view._on_batch_file_load = mock.MagicMock(side_effect=on_load_batch_file_mock)
+
+    _output_mode = mock.PropertyMock(return_value=OutputMode.PublishToADS)
+    type(view).output_mode = _output_mode
+
+    return view
+
+
+class FakeState(object):
+    dummy_state = "dummy_state"
+
+    def __init__(self):
+        super(FakeState, self).__init__()
+
+    @property
+    def property_manager(self):
+        return self.dummy_state
+
+
+def get_state_for_row_mock(row_index):
+    return FakeState() if row_index == 3 else ""
+
+
+def get_state_for_row_mock_with_real_state(row_index):
+    _ = row_index  # noqa
+    test_director = TestDirector()
+    return test_director.construct()
+
+
+def create_run_tab_presenter_mock(use_fake_state=True):
+    presenter = mock.create_autospec(RunTabPresenter, spec_set=False)
+    presenter.get_row_indices = mock.MagicMock(return_value=[0, 1, 3])
+    if use_fake_state:
+        presenter.get_state_for_row = mock.MagicMock(side_effect=get_state_for_row_mock)
+    else:
+        presenter.get_state_for_row = mock.MagicMock(side_effect=get_state_for_row_mock_with_real_state)
+    return presenter
+
+
+class FakeParentPresenter(object):
+    def __init__(self):
+        super(FakeParentPresenter, self).__init__()
+
+    def get_row_indices(self):
+        # We assume that row 2 is empty
+        return [0, 1, 3]
+
+    def get_state_for_row(self, row_index):
+        return FakeState() if row_index == 3 else ""
diff --git a/scripts/SANS/sans/test_helper/user_file_test_helper.py b/scripts/SANS/sans/test_helper/user_file_test_helper.py
new file mode 100644
index 0000000000000000000000000000000000000000..6bc2f87ab7373f4c307fa840f96c943ead755750
--- /dev/null
+++ b/scripts/SANS/sans/test_helper/user_file_test_helper.py
@@ -0,0 +1,89 @@
+from __future__ import (absolute_import, division, print_function)
+import os
+import mantid
+
+sample_user_file = ("PRINT for changer\n"
+                    "MASK/CLEAR \n"
+                    "MASK/CLEAR/TIME\n"
+                    "L/WAV 1.5 12.5 0.125/LIN\n"
+                    "L/Q .001,.001, .0126, -.08, .2\n"
+                    "!L/Q .001 .8 .08/log\n"
+                    "L/QXY 0 0.05 .001/lin\n"
+                    "BACK/M1 35000 65000\n"
+                    "BACK/M2 85000 98000\n"
+                    "BACK/MON/TIMES 3500 4500\n"
+                    "BACK/TRANS 123 466\n"
+                    "DET/REAR\n"
+                    "GRAVITY/ON\n"
+                    "!FIT/TRANS/OFF\n"
+                    "FIT/TRANS/LOG 1.5 12.5\n"
+                    "FIT/MONITOR 1000 2000\n"
+                    "mask/rear h0\n"
+                    "mask/rear h190>h191\n"
+                    "mask/rear h167>h172\n"
+                    "mask/rear v0\n"
+                    "mask/rear v191\n"
+                    "mask/front h0\n"
+                    "mask/front h190>h191\n"
+                    "mask/front v0\n"
+                    "mask/front v191\n"
+                    "! dead wire near top\n"
+                    "mask/front h156>h159\n"
+                    "!masking off beamstop arm - 12mm wide @ 19degrees\n"
+                    "!mask/rear/line 12 19\n"
+                    "! spot on rhs beam stop at 11m\n"
+                    "! mask h57>h66+v134>v141\n"
+                    "!\n"
+                    "! mask for Bragg at 12m, 26/03/11, 3 time channels\n"
+                    "mask/time 17500 22000\n"
+                    "!\n"
+                    "L/R 12 15\n"
+                    "L/Q/RCut 200\n"
+                    "L/Q/WCut 8.0\n"
+                    "!PRINT REMOVED RCut=200 WCut=8\n"
+                    "!\n"
+                    "MON/DIRECT=DIRECTM1_15785_12m_31Oct12_v12.dat\n"
+                    "MON/TRANS/SPECTRUM=1/INTERPOLATE\n"
+                    "MON/SPECTRUM=1/INTERPOLATE\n"
+                    "!TRANS/TRANSPEC=3\n"
+                    "TRANS/TRANSPEC=4/SHIFT=-70\n"
+                    "TRANS/RADIUS=7.0\n"
+                    "TRANS/ROI=test.xml, test2.xml\n"
+                    "TRANS/MASK=test3.xml, test4.xml\n"
+                    "!\n"
+                    "set centre 155.45 -169.6\n"
+                    "!\n"
+                    "! 25/10/13 centre gc 22021, fit gdw20 22023\n"
+                    "set scales 0.074 1.0 1.0 1.0 1.0\n"
+                    "! correction to actual sample position, notionally 81mm before shutter\n"
+                    "SAMPLE/OFFSET +53.0\n"
+                    "! Correction to SANS2D encoders in mm\n"
+                    "DET/CORR/REAR/X -16.0\n"
+                    "DET/CORR/REAR/Z 47.0\n"
+                    "DET/CORR/FRONT/X -44.0\n"
+                    "DET/CORR/FRONT/Y -20.0\n"
+                    "DET/CORR/FRONT/Z 47.0\n"
+                    "DET/CORR/FRONT/ROT 0.0\n"
+                    "!\n"
+                    "!! 01/10/13 MASKSANS2d_133F M3 by M1 trans Hellsing, Rennie, Jackson, L1=L2=12m A1=20 and A2=8mm\n"
+                    "L/EVENTSTIME 7000.0,500.0,60000.0\n"
+                    "SAMPLE/PATH/ON\n"
+                    "QRESOL/ON \n"
+                    "QRESOL/DELTAR=11 \n"
+                    "QRESOL/LCOLLIM=12 \n"
+                    "QRESOL/MODERATOR=moderator_rkh_file.txt\n"
+                    "QRESOL/A1=13\n"
+                    "QRESOL/A2=14\n"
+                    "TUBECALIBFILE=TUBE_SANS2D_BOTH_31681_25Sept15.nxs"
+                    )
+
+
+def create_user_file(user_file_content):
+    user_file_path = os.path.join(mantid.config.getString('defaultsave.directory'), 'sample_sans_user_file.txt')
+    if os.path.exists(user_file_path):
+        os.remove(user_file_path)
+
+    with open(user_file_path, 'w') as f:
+        f.write(user_file_content)
+
+    return user_file_path
diff --git a/scripts/SANS/sans/user_file/settings_tags.py b/scripts/SANS/sans/user_file/settings_tags.py
index b54a81f16e5b73d5fed28e6c8cf83a832c288458..615561c12c4c2a79f5670b4db51c9ec9bebf364e 100644
--- a/scripts/SANS/sans/user_file/settings_tags.py
+++ b/scripts/SANS/sans/user_file/settings_tags.py
@@ -44,6 +44,7 @@ monitor_file = namedtuple('monitor_file', 'file_path, detector_type')
 # Det
 det_fit_range = namedtuple('det_fit_range', 'start, stop, use_fit')
 
+
 # ------------------------------------------------------------------
 # --- State director keys ------------------------------------------
 # ------------------------------------------------------------------
@@ -135,6 +136,7 @@ class BackId(object):
 # -- OTHER - not settable in user file
 @serializable_enum("reduction_dimensionality", "use_full_wavelength_range", "event_slices",
                    "use_compatibility_mode", "save_types", "save_as_zero_error_free", "user_specified_output_name",
-                   "user_specified_output_name_suffix", "use_reduction_mode_as_suffix")
+                   "user_specified_output_name_suffix", "use_reduction_mode_as_suffix", "sample_width", "sample_height",
+                   "sample_thickness", "sample_shape")
 class OtherId(object):
     pass
diff --git a/scripts/SANS/sans/user_file/state_director.py b/scripts/SANS/sans/user_file/state_director.py
index 48f2919f616f515ab8f24ab21ee726f28ed43801..80fba55930f57b5801cefd27deeddf7eea33475f 100644
--- a/scripts/SANS/sans/user_file/state_director.py
+++ b/scripts/SANS/sans/user_file/state_director.py
@@ -955,6 +955,32 @@ class StateDirectorISIS(object):
             scales = scales[-1]
             self._scale_builder.set_scale(scales.s)
 
+        # We can also have settings for the sample geometry (Note that at the moment this is not settable via the
+        # user file nor the command line interface
+        if OtherId.sample_shape in user_file_items:
+            sample_shape = user_file_items[OtherId.sample_shape]
+            check_if_contains_only_one_element(sample_shape, OtherId.sample_shape)
+            sample_shape = sample_shape[-1]
+            self._scale_builder.set_shape(sample_shape)
+
+        if OtherId.sample_width in user_file_items:
+            sample_width = user_file_items[OtherId.sample_width]
+            check_if_contains_only_one_element(sample_width, OtherId.sample_width)
+            sample_width = sample_width[-1]
+            self._scale_builder.set_width(sample_width)
+
+        if OtherId.sample_height in user_file_items:
+            sample_height = user_file_items[OtherId.sample_height]
+            check_if_contains_only_one_element(sample_height, OtherId.sample_height)
+            sample_height = sample_height[-1]
+            self._scale_builder.set_height(sample_height)
+
+        if OtherId.sample_thickness in user_file_items:
+            sample_thickness = user_file_items[OtherId.sample_thickness]
+            check_if_contains_only_one_element(sample_thickness, OtherId.sample_thickness)
+            sample_thickness = sample_thickness[-1]
+            self._scale_builder.set_thickness(sample_thickness)
+
     def _set_up_convert_to_q_state(self, user_file_items):
         # Get the radius cut off if any is present
         set_single_entry(self._convert_to_q_builder, "set_radius_cutoff", LimitsId.radius_cut, user_file_items,
@@ -1031,9 +1057,10 @@ class StateDirectorISIS(object):
             mon_spectrum = user_file_items[MonId.spectrum]
             mon_spec = [spec for spec in mon_spectrum if not spec.is_trans]
             mon_spec = mon_spec[-1]
-            rebin_type = RebinType.InterpolatingRebin if mon_spec.interpolate else RebinType.Rebin
-            self._normalize_to_monitor_builder.set_rebin_type(rebin_type)
-            self._normalize_to_monitor_builder.set_incident_monitor(mon_spec.spectrum)
+            if mon_spec:
+                rebin_type = RebinType.InterpolatingRebin if mon_spec.interpolate else RebinType.Rebin
+                self._normalize_to_monitor_builder.set_rebin_type(rebin_type)
+                self._normalize_to_monitor_builder.set_incident_monitor(mon_spec.spectrum)
 
         # The prompt peak correction values
         set_prompt_peak_correction(self._normalize_to_monitor_builder, user_file_items)
@@ -1078,9 +1105,10 @@ class StateDirectorISIS(object):
             mon_spectrum = user_file_items[MonId.spectrum]
             mon_spec = [spec for spec in mon_spectrum if spec.is_trans]
             mon_spec = mon_spec[-1]
-            rebin_type = RebinType.InterpolatingRebin if mon_spec.interpolate else RebinType.Rebin
-            self._calculate_transmission_builder.set_rebin_type(rebin_type)
-            self._calculate_transmission_builder.set_incident_monitor(mon_spec.spectrum)
+            if mon_spec:
+                rebin_type = RebinType.InterpolatingRebin if mon_spec.interpolate else RebinType.Rebin
+                self._calculate_transmission_builder.set_rebin_type(rebin_type)
+                self._calculate_transmission_builder.set_incident_monitor(mon_spec.spectrum)
 
         # The general background settings
         set_background_tof_general(self._calculate_transmission_builder, user_file_items)
diff --git a/scripts/SANS/sans/user_file/user_file_parser.py b/scripts/SANS/sans/user_file/user_file_parser.py
index b629974ddf24e72a0f7d11ae49c783e3b121c6b9..e84ebb81ffdbd8806c55bfaf374b59b7b60c5e16 100644
--- a/scripts/SANS/sans/user_file/user_file_parser.py
+++ b/scripts/SANS/sans/user_file/user_file_parser.py
@@ -1439,8 +1439,8 @@ class QResolutionParser(UserFileComponentParser):
         self._w2_pattern = re.compile(start_string + self._w2 + float_number + end_string)
 
         # Moderator
-        self._moderator = "\\s*MODERATOR\\s*=\\s*"
-        self._file = "[\\w]+(\\.TXT)"
+        self._moderator = "\\s*MODERATOR\\s*=\\s*(\")?"
+        self._file = "[\\w]+(\\.TXT)(\")?"
         self._moderator_pattern = re.compile(start_string + self._moderator + self._file)
 
     def parse_line(self, line):
@@ -1532,7 +1532,9 @@ class QResolutionParser(UserFileComponentParser):
 
     def _extract_moderator(self, line, original_line):
         moderator_capital = re.sub(self._moderator, "", line)
+        moderator_capital = re.sub("\"", "", moderator_capital)
         moderator = re.search(moderator_capital, original_line, re.IGNORECASE).group(0)
+        # Remove quotation marks
         return {QResolutionId.moderator: moderator}
 
     @staticmethod
@@ -1682,7 +1684,7 @@ class FitParser(UserFileComponentParser):
 
     def _get_fit_type(self, line):
         if re.search(self._log, line) is not None:
-            fit_type = FitType.Log
+            fit_type = FitType.Logarithmic
         elif re.search(self._lin, line) is not None:
             fit_type = FitType.Linear
         elif re.search(self._polynomial, line) is not None:
@@ -2101,6 +2103,28 @@ class LARMORParser(UserFileComponentParser):
         return "\\s*" + LARMORParser.get_type() + "(\\s*)"
 
 
+class ZOOMParser(UserFileComponentParser):
+    """
+    The ZOOMParser is a hollow parser to ensure backwards compatibility
+    """
+    Type = "ZOOM"
+
+    def __init__(self):
+        super(ZOOMParser, self).__init__()
+
+    def parse_line(self, line):
+        return {}
+
+    @staticmethod
+    def get_type():
+        return ZOOMParser.Type
+
+    @staticmethod
+    @abc.abstractmethod
+    def get_type_pattern():
+        return "\\s*" + ZOOMParser.get_type() + "(\\s*)"
+
+
 class IgnoredParser(object):
     """
     The IgnoredParser deals with known commands which are not relevant any longer, but might appear in legacy files.
@@ -2185,7 +2209,8 @@ class UserFileParser(object):
                          PrintParser.get_type(): PrintParser(),
                          SANS2DParser.get_type(): SANS2DParser(),
                          LOQParser.get_type(): LOQParser(),
-                         LARMORParser.get_type(): LARMORParser()}
+                         LARMORParser.get_type(): LARMORParser(),
+                         ZOOMParser.get_type(): ZOOMParser()}
         self._ignored_parser = IgnoredParser()
 
     def _get_correct_parser(self, line):
diff --git a/scripts/TemporaryREF_MScripts/testCenterREF_M.py b/scripts/TemporaryREF_MScripts/testCenterREF_M.py
index 65053f0c0e3f97849437c3c7d2625fb6a77ac2ce..fd3ab5d44112542bf4cd3d9aa686bf98922e7277 100644
--- a/scripts/TemporaryREF_MScripts/testCenterREF_M.py
+++ b/scripts/TemporaryREF_MScripts/testCenterREF_M.py
@@ -1,4 +1,5 @@
 #pylint: disable=invalid-name
+from __future__ import (absolute_import, division, print_function)
 import numpy as np
 import mantid
 
diff --git a/scripts/reducer_singleton.py b/scripts/reducer_singleton.py
index b0fdb5d7bc21e06a069041a3246466f3fe7cc738..0b56eb873391a00ffcf7f39296973cca26496603 100644
--- a/scripts/reducer_singleton.py
+++ b/scripts/reducer_singleton.py
@@ -1,4 +1,5 @@
 # pylint: disable=invalid-name
+from __future__ import (absolute_import, division, print_function)
 import random
 import string
 import os
diff --git a/scripts/reduction/__init__.py b/scripts/reduction/__init__.py
index 7093c3f8f1e8c37211b312d9be753a6b330e7be0..4ae0a9f79eda5934f1de5f33004c7de01f2040f9 100644
--- a/scripts/reduction/__init__.py
+++ b/scripts/reduction/__init__.py
@@ -1,3 +1,4 @@
+from __future__ import (absolute_import, division, print_function)
 from reduction.reducer import *
 from reduction.instrument import *
 from reduction.find_data import find_data, find_file
diff --git a/scripts/reduction/command_interface.py b/scripts/reduction/command_interface.py
index d74822233093395f4490bbd5e32833c2829ce9f3..1c3a611d5989cbb9fc3cb4e6bd6e68eaba949bb9 100644
--- a/scripts/reduction/command_interface.py
+++ b/scripts/reduction/command_interface.py
@@ -2,7 +2,7 @@
 """
     List of user commands.
 """
-
+from __future__ import (absolute_import, division, print_function)
 from reduction.reducer import Reducer
 
 
diff --git a/scripts/reduction/find_data.py b/scripts/reduction/find_data.py
index dcc9eabf4a443ed1ba04f9730d388b37bb431375..ce0e43263dc9a513deddc9bdcdfa4c1eb4f79803 100644
--- a/scripts/reduction/find_data.py
+++ b/scripts/reduction/find_data.py
@@ -1,4 +1,5 @@
 #pylint: disable=invalid-name,redefined-builtin
+from __future__ import (absolute_import, division, print_function)
 import os
 import mantid.api as api
 from mantid.simpleapi import *
diff --git a/scripts/reduction/instrument.py b/scripts/reduction/instrument.py
index bd3cb432240cdeb032c3115b57b3710f29afca7a..9616ec3c3b97cdc823c32e80f3cbddd42e642798 100644
--- a/scripts/reduction/instrument.py
+++ b/scripts/reduction/instrument.py
@@ -1,3 +1,4 @@
+from __future__ import (absolute_import, division, print_function)
 import mantid.simpleapi as api
 from mantid.kernel import *
 from mantid.api import *
@@ -11,7 +12,7 @@ def instrument_factory(name):
     if name in globals():
         return globals()[name]()
     else:
-        raise RuntimeError("Instrument %s doesn't exist\n  %s" % (name, sys.exc_value))
+        raise RuntimeError("Instrument %s doesn't exist\n  %s" % (name, sys.exc_info()[1]))
 
 
 class Instrument(object):
diff --git a/scripts/reduction/instruments/example/ExampleRedStep.py b/scripts/reduction/instruments/example/ExampleRedStep.py
index fedd12538ca20b0b2fd34318c2a9cd329f219ef7..50a4d586400abefd0f2e2f263a34494555905f10 100644
--- a/scripts/reduction/instruments/example/ExampleRedStep.py
+++ b/scripts/reduction/instruments/example/ExampleRedStep.py
@@ -1,4 +1,5 @@
 #pylint: disable=no-init
+from __future__ import (absolute_import, division, print_function)
 from mantid.kernel import *
 from mantid.api import *
 from mantid.simpleapi import *
@@ -40,4 +41,4 @@ class ExampleLoader(PythonAlgorithm):
         output_ws = self.getProperty("OutputWorkspace").value
         LoadAscii(filename, output_ws)
 
-        print filename, output_ws
+        print(filename, output_ws)
diff --git a/scripts/reduction/instruments/example/example_reducer.py b/scripts/reduction/instruments/example/example_reducer.py
index 3aedebe89e0f7c3212542ad42c2d0e42c74c6b19..edfe5edf9eb1568dcdc1274c9a9d665b3d83d3d0 100644
--- a/scripts/reduction/instruments/example/example_reducer.py
+++ b/scripts/reduction/instruments/example/example_reducer.py
@@ -2,6 +2,7 @@
 """
     Simple Reducer example
 """
+from __future__ import (absolute_import, division, print_function)
 from reduction import Reducer
 from reduction.instruments.example.ExampleRedStep import ExampleRedStep
 # Validate_step is a decorator that allows both Python algorithms and ReductionStep objects to be passed to the Reducer.
diff --git a/scripts/reduction/instruments/inelastic/direct_command_interface.py b/scripts/reduction/instruments/inelastic/direct_command_interface.py
index 8b8888409c075b533b2ae458a8ed828340338dee..45182235f124522fbd7647a40a24fdcd63b96c43 100644
--- a/scripts/reduction/instruments/inelastic/direct_command_interface.py
+++ b/scripts/reduction/instruments/inelastic/direct_command_interface.py
@@ -2,6 +2,7 @@
 """
     Command set for Direct Geometry reduction
 """
+from __future__ import (absolute_import, division, print_function)
 # Import the specific commands that we need
 from mantid.api import AlgorithmManager
 from reduction.command_interface import *
@@ -59,4 +60,4 @@ def CalculateEi(guess=None):
 
 
 def GetEiFromLog():
-    print "GetEiFromLog(): *** NOT IMPLEMENTED *** "
+    print("GetEiFromLog(): *** NOT IMPLEMENTED *** ")
diff --git a/scripts/reduction/instruments/inelastic/inelastic_reducer.py b/scripts/reduction/instruments/inelastic/inelastic_reducer.py
index 95fb75941f1444b8336b11207b368828697940fb..769aa884b0b80a0a990e534c4f4a20e1577dee9f 100644
--- a/scripts/reduction/instruments/inelastic/inelastic_reducer.py
+++ b/scripts/reduction/instruments/inelastic/inelastic_reducer.py
@@ -2,6 +2,7 @@
 """
     Inelastic specific implementation of the Reducer.
 """
+from __future__ import (absolute_import, division, print_function)
 from reduction import Reducer
 # Validate_step is a decorator that allows both Python algorithms and
 # ReductionStep objects to be passed to the Reducer.
diff --git a/scripts/reduction/instruments/reflectometer/wks_utility.py b/scripts/reduction/instruments/reflectometer/wks_utility.py
index 3606adbb775cb800b6c5483b24e7e9d08e2346d4..c1ec57fb120ec996484ceafd75077812bb3bd583 100644
--- a/scripts/reduction/instruments/reflectometer/wks_utility.py
+++ b/scripts/reduction/instruments/reflectometer/wks_utility.py
@@ -1,8 +1,10 @@
 #pylint: disable=too-many-lines,invalid-name,too-many-arguments, too-many-locals, unused-argument
+from __future__ import (absolute_import, division, print_function)
 from numpy import zeros, arctan2, arange, shape, sqrt, fliplr, asfarray, mean, sum, NAN
 from mantid.simpleapi import *
 import math
 import os.path
+from six.moves import range
 
 h = 6.626e-34 #m^2 kg s^-1
 m = 1.675e-27 #kg
@@ -37,7 +39,7 @@ def getSequenceRuns(run_numbers):
 
 def getProtonCharge(st=None):
     """
-        Returns the proton charge of the given workspace in picoCoulomb
+    Returns the proton charge of the given workspace in picoCoulomb
     """
     if st is not None:
         mt_run = st.getRun()
@@ -61,7 +63,7 @@ def getIndex(value, array):
 
 def getSh(mt, top_tag, bottom_tag):
     """
-        returns the height and units of the given slit#
+    returns the height and units of the given slit#
     """
     mt_run = mt.getRun()
     st = mt_run.getProperty(top_tag).value
@@ -73,7 +75,7 @@ def getSh(mt, top_tag, bottom_tag):
 
 def getSheight(mt, index):
     """
-        return the DAS hardware slits height of slits # index
+    return the DAS hardware slits height of slits # index
     """
     mt_run = mt.getRun()
     if index == 2:
@@ -95,7 +97,7 @@ def getSheight(mt, index):
 
 def getS1h(mt=None):
     """
-        returns the height and units of the slit #1
+    returns the height and units of the slit #1
     """
     if mt is not None:
 #        _h, units = getSh(mt, 's1t', 's1b')
@@ -106,7 +108,7 @@ def getS1h(mt=None):
 
 def getS2h(mt=None):
     """
-        returns the height and units of the slit #2
+    returns the height and units of the slit #2
     """
     if mt is not None:
         [isSi, _h] = getSheight(mt, 2)
@@ -116,8 +118,8 @@ def getS2h(mt=None):
 
 def getSwidth(mt, index):
     """
-        returns the width and units of the given index slits
-        defined by the DAS hardware
+    returns the width and units of the given index slits
+    defined by the DAS hardware
     """
     mt_run = mt.getRun()
     if index==2:
@@ -138,7 +140,7 @@ def getSwidth(mt, index):
 
 def getSw(mt, left_tag, right_tag):
     """
-        returns the width and units of the given slits
+    returns the width and units of the given slits
     """
     mt_run = mt.getRun()
     sl = mt_run.getProperty(left_tag).value
@@ -150,7 +152,7 @@ def getSw(mt, left_tag, right_tag):
 
 def getS1w(mt=None):
     """
-        returns the width and units of the slit #1
+    returns the width and units of the slit #1
     """
     if mt is not None:
 #        _w, units = getSw(mt, 's1l', 's1r')
@@ -161,7 +163,7 @@ def getS1w(mt=None):
 
 def getS2w(mt=None):
     """
-        returns the width and units of the slit #2
+    returns the width and units of the slit #2
     """
     if mt is not None:
         [isSi, _w] = getSwidth(mt, 2)
@@ -180,7 +182,7 @@ def getLambdaValue(mt_name):
 
 def getPixelXPixelY(mt1, maxX=304, maxY=256):
     """
-        returns the PixelX_vs_PixelY array of the workspace data specified
+    returns the PixelX_vs_PixelY array of the workspace data specified
     """
     pixelX_vs_pixelY = zeros((maxY, maxX))
     for x in range(maxX):
@@ -193,7 +195,7 @@ def getPixelXPixelY(mt1, maxX=304, maxY=256):
 
 def getPixelXPixelYError(mt1):
     """
-        returns the PixelX_vs_PixelY_error array of the workspace data specified
+    returns the PixelX_vs_PixelY_error array of the workspace data specified
     """
     pixel_error = zeros((256, 304))
     for x in range(304):
@@ -206,7 +208,7 @@ def getPixelXPixelYError(mt1):
 
 def getPixelXTOF(mt1, maxX=304, maxY=256):
     """
-        returns the PixelX_vs_TOF array of the workspace data specified
+    returns the PixelX_vs_TOF array of the workspace data specified
     """
     _init = mt1.readY(0)[:]
     pixelX_vs_tof = zeros((maxY, len(_init)))
@@ -220,8 +222,8 @@ def getPixelXTOF(mt1, maxX=304, maxY=256):
 
 def findQaxisMinMax(q_axis):
     """
-        Find the position of the common Qmin and Qmax in
-        each q array
+    Find the position of the common Qmin and Qmax in
+    each q array
     """
 
     nbr_row = shape(q_axis)[0]
@@ -258,13 +260,10 @@ def cleanup_data(InputWorkspace=None,
     _tof_axis = mti.readX(0)[:]
     nbr_tof = shape(_tof_axis)[0]-1
 
-    tof_range = range(nbr_tof-1)
-    x_range = range(maxY)
-
     _new_y = zeros((maxY, nbr_tof))
     _new_e = zeros((maxY, nbr_tof))
-    for px in x_range:
-        for tof in tof_range:
+    for px in range(maxY):
+        for tof in range(nbr_tof-1):
             _y = mti.readY(px)[tof]
             if _y != 0:
                 _e = mti.readE(px)[tof]
@@ -293,8 +292,8 @@ def createIntegratedWorkspace(mt1,
                               maxX=304, maxY=256,
                               bCleaning=False):
     """
-        This creates the integrated workspace over the second pixel range (304 here) and
-        returns the new workspace handle
+    This creates the integrated workspace over the second pixel range (304 here) and
+    returns the new workspace handle
     """
 
     _tof_axis = mt1.readX(0)[:]
@@ -348,8 +347,8 @@ def convertWorkspaceToQ(ws_data,
                         geo_correction=False,
                         q_binning=None):
     """
-        This creates the integrated workspace over the second pixel range (304 here) and
-        returns the new workspace handle
+    This creates the integrated workspace over the second pixel range (304 here) and
+    returns the new workspace handle
     """
 
     mt1 = ws_data
@@ -431,7 +430,7 @@ def convertWorkspaceToQ(ws_data,
             _q_axis = 1e-10 * _const * math.sin(theta) / (_tof_axis * 1e-6)
         else:
             _q_axis = _tof_axis
-            print 'should not reach this condition !'
+            print('should not reach this condition !')
 
         y_size = toYpixel - fromYpixel + 1
         y_range = arange(y_size) + fromYpixel
@@ -507,8 +506,7 @@ def create_grouping(workspace=None, xmin=0, xmax=None, filename=".refl_grouping.
 
 def angleUnitConversion(value, from_units='degree', to_units='rad'):
     """
-        This function converts the angle units
-
+    This function converts the angle units
     """
 
     if from_units == to_units:
@@ -537,7 +535,6 @@ def convertToThetaVsLambda(_tof_axis,
     """
     This function converts the pixel/tof array
     to theta/lambda
-
     """
     # h = 6.626e-34 #m^2 kg s^-1
     # m = 1.675e-27 #kg
@@ -585,9 +582,7 @@ def convertToRvsQWithCorrection(mt, dMD= -1, theta= -1.0, tof=None, yrange=None,
     sz_tof = len(tof)
     q_array = zeros((len(yrange), sz_tof - 1))
 
-    yrange = range(len(yrange))
-    for y in yrange:
-        _px = yrange[y]
+    for _px in range(len(yrange)):
         dangle = ref_beamdiv_correct(cpix, mt, dSD, _px)
 
         if dangle is not None:
@@ -600,7 +595,7 @@ def convertToRvsQWithCorrection(mt, dMD= -1, theta= -1.0, tof=None, yrange=None,
             tof2 = tof[t+1]
             tofm = (tof1+tof2)/2.
             _Q = _const * math.sin(_theta) / (tofm*1e-6)
-            q_array[y, t] = _Q * 1e-10
+            q_array[_px, t] = _Q * 1e-10
 
     return q_array
 
@@ -800,122 +795,6 @@ def isWithinPrecisionRange(value_file, value_run, precision):
     else:
         return False
 
-#def applySF(InputWorkspace,
-            #incidentMedium,
-            #sfFile,
-            #valuePrecision,
-            #slitsWidthFlag):
-    #"""
-    #Function that apply scaling factor to data using sfCalculator.txt
-    #file created by the sfCalculator procedure
-    #"""
-
-    ##check if config file is there
-    #if os.path.isfile(sfFile):
-
-        ##parse file and put info into array
-        #f = open(sfFile, 'r')
-        #sfFactorTable = []
-        #for line in f.read().split('\n'):
-            #if len(line) > 0 and line[0] != '#':
-                #sfFactorTable.append(line.split(' '))
-        #f.close()
-
-        #sz_table = shape(sfFactorTable)
-        #nbr_row = sz_table[0]
-
-        #_incidentMedium = incidentMedium.strip()
-
-        #_lr = getLambdaValue(mtd[InputWorkspace])
-        #_lr_value = _lr[0]
-        #_lr_value = float("{0:.2f}".format(_lr_value))
-
-        ##retrieve s1h and s2h values
-        #s1h = getS1h(mtd[InputWorkspace])
-        #s2h = getS2h(mtd[InputWorkspace])
-
-        #s1h_value = abs(s1h)
-        #s2h_value = abs(s2h)
-
-        ##retrieve s1w and s2w values
-        #s1w = getS1w(mtd[InputWorkspace])
-        #s2w = getS2w(mtd[InputWorkspace])
-
-        #s1w_value = abs(s1w)
-        #s2w_value = abs(s2w)
-
-##        print sfFactorTable
-
-        #print '--> Data Lambda Requested: {0:2f}'.format(_lr_value)
-        #print '--> Data S1H: {0:2f}'.format(s1h_value)
-        #print '--> Data S2H: {0:2f}'.format(s2h_value)
-        #print '--> Data S1W: {0:2f}'.format(s1w_value)
-        #print '--> Data S2W: {0:2f}'.format(s2w_value)
-
-        #print 'mERDDEEEEDEDEED'
-        #for i in range(nbr_row):
-
-            #_file_incidentMedium = getFieldValue(sfFactorTable,i,0)
-            #if _file_incidentMedium.strip() == _incidentMedium.strip():
-                #print '--- incident medium match ---'
-                #_file_lambdaRequested = getFieldValue(sfFactorTable,i,1)
-                #if (isWithinPrecisionRange(_file_lambdaRequested,
-                                           #_lr_value,
-                                           #valuePrecision)):
-                    #print '--- lambda requested match ---'
-                    #_file_s1h = getFieldValue(sfFactorTable,i,2)
-                    #if(isWithinPrecisionRange(_file_s1h,
-                                              #s1h_value,
-                                              #valuePrecision)):
-                        #print '--- S1H match ---'
-                        #_file_s2h = getFieldValue(sfFactorTable,i,3)
-                        #if(isWithinPrecisionRange(_file_s2h,
-                                                  #s2h_value,
-                                                  #valuePrecision)):
-                            #print '--- S2H match ---'
-                            #if slitsWidthFlag:
-                                #print '--- (with Width flag) ----'
-                                #_file_s1w = getFieldValue(sfFactorTable,i,4)
-                                #if(isWithinPrecisionRange(_file_s1w,
-                                                          #s1w_value,
-                                                          #valuePrecision)):
-                                    #print '--- S1W match ---'
-                                    #_file_s2w = getFieldValue(sfFactorTable,i,5)
-                                    #if(isWithinPrecisionRange(_file_s2w,
-                                                              #s2w_value,
-                                                              #valuePrecision)):
-                                        #print '--- S2W match ---'
-
-                                        #print '--> Found a perfect match'
-                                        #a = float(getFieldValue(sfFactorTable,i,6))
-                                        #b = float(getFieldValue(sfFactorTable,i,7))
-                                        #a_error = float(getFieldValue(sfFactorTable,i,8))
-                                        #b_error = float(getFieldValue(sfFactorTable,i,9))
-
-                                        #OutputWorkspace = _applySFtoArray(InputWorkspace,
-                                                                          #a, b, a_error, b_error)
-
-                                        #return OutputWorkspace
-
-                            #else:
-
-                                #print '--> Found a perfect match'
-                                #a = float(getFieldValue(sfFactorTable,i,6))
-                                #b = float(getFieldValue(sfFactorTable,i,7))
-                                #a_error = float(getFieldValue(sfFactorTable,i,8))
-                                #b_error = float(getFieldValue(sfFactorTable,i,9))
-
-                                #OutputWorkspace = _applySFtoArray(InputWorkspace,
-                                                                  #a, b, a_error, b_error)
-
-                                #return OutputWorkspace
-
-    #else:
-
-        #print '-> scaling factor file for requested lambda NOT FOUND!'
-
-    #return InputWorkspace
-
 
 def _applySFtoArray(workspace, a, b, a_error, b_error):
     """
@@ -960,14 +839,14 @@ def loadNeXus(runNumbers, type):
     else:
         wks_name = 'ws_event_norm'
 
-    print '-> loading ', type
+    print('-> loading ', type)
     if (type == 'data') and len(runNumbers) > 1:
 
         _list = []
         for _run in runNumbers:
             _list.append(str(_run))
         list_run = ','.join(_list)
-        print '--> working with runs: ' + str(list_run)
+        print('--> working with runs:', str(list_run))
 
         _index = 0
         for _run in runNumbers:
@@ -991,7 +870,7 @@ def loadNeXus(runNumbers, type):
                 DeleteWorkspace(tmp)
     else:
 
-        print '--> Working with run: ' + str(runNumbers)
+        print('--> Working with run: ' + str(runNumbers))
 
         try:
             data_file = FileFinder.findRuns("REF_L%d" %runNumbers)[0]
@@ -1012,7 +891,7 @@ def rebinNeXus(inputWorkspace, params, type):
     params[1]: bin size
     params[2]: max value
     """
-    print '--> rebin ', type
+    print('--> rebin ', type)
     ws_histo_data = Rebin(InputWorkspace=inputWorkspace,
                           Params=params,
                           PreserveEvents=True)
@@ -1024,7 +903,7 @@ def cropTOF(inputWorkspace, min, max, type):
     will crop the nexus (workspace) using min and max value
     used here to crop the TOF range
     """
-    print '--> crop ' , type , ' workspace in TOF'
+    print('--> crop ' , type , ' workspace in TOF')
     ws_histo_data = CropWorkspace(InputWorkspace = inputWorkspace,
                                   XMin = min,
                                   XMax = max)
@@ -1035,7 +914,7 @@ def normalizeNeXus(inputWorkspace, type):
     """
     normalize nexus by proton charge
     """
-    print '--> normalize ', type
+    print('--> normalize ', type)
     ws_histo_data = NormaliseByCurrent(InputWorkspace=inputWorkspace)
     return ws_histo_data
 
@@ -1052,7 +931,7 @@ def integrateOverLowResRange(mt1,
         is 0 !
     """
 
-    print '--> integrated over low res range of ', type
+    print('--> integrated over low res range of ', type)
     _tof_axis = mt1.readX(0)[:].copy()
 #     t_range = arange(nbr_tof-1)
 
@@ -1071,7 +950,7 @@ def integrateOverLowResRange(mt1,
     x_size = toXpixel - fromXpixel + 1
     x_range = arange(x_size) + fromXpixel
 
-    y_range = range(sz_y_axis)
+    y_range = arange(sz_y_axis)
 
     for x in x_range:
         for y in y_range:
@@ -1108,10 +987,10 @@ def substractBackground(tof_axis, y_axis, y_error_axis,
     backMax = backRange[1]-1
 
     if not backFlag:
-        print '---> no ', type, ' background requested!'
+        print('---> no ', type, ' background requested!')
         return [y_axis[peakMin:peakMax+1,:], y_error_axis[peakMin:peakMax+1,:]]
 
-    print '--> background subtraction of ', type
+    print('--> background subtraction of ', type)
 
     # retrieve data
     _tofAxis = tof_axis
@@ -1167,7 +1046,7 @@ def substractBackground(tof_axis, y_axis, y_error_axis,
             final_y_error_axis[x,t] = float(math.sqrt(pow(y_error_axis[peakMin+x,t],2) + pow(background_error,2)))
 
 #         if t == nbrTof-2:
-#             print float(y_axis[peakMin + x,t]) - float(background)
+#             print(float(y_axis[peakMin + x,t]) - float(background))
 
     return [final_y_axis, final_y_error_axis]
 
@@ -1262,7 +1141,7 @@ def divideDataByNormalization(data_y_axis,
                               av_norm,
                               av_norm_error):
 
-    print '-> divide data by normalization'
+    print('-> divide data by normalization')
 
     data_size = data_y_axis.shape
     nbr_pixel = data_size[0]
@@ -1400,7 +1279,7 @@ def divideData1DbyNormalization(inte_data_y_axis,
                                 av_norm,
                                 av_norm_error):
 
-    print '-> divide data by normalization'
+    print('-> divide data by normalization')
 
     nbrPixel = inte_data_y_axis.shape
 
@@ -1437,7 +1316,7 @@ def applyScalingFactor(tof_axis,
     #sf_file = 'NaN'
     if os.path.isfile(sf_file):
 
-        print '-> scaling factor file FOUND! (', sf_file, ')'
+        print('-> scaling factor file FOUND! (', sf_file, ')')
 
         #parse file and put info into array
         f = open(sf_file, 'r')
@@ -1470,52 +1349,52 @@ def applyScalingFactor(tof_axis,
         s1w_value = abs(s1w)
         s2w_value = abs(s2w)
 
-        print '--> Data Lambda Requested: {0:2f}'.format(_lr_value)
-        print '--> Data S1H: {0:2f}'.format(s1h_value)
+        print('--> Data Lambda Requested: {0:2f}'.format(_lr_value))
+        print('--> Data S1H: {0:2f}'.format(s1h_value))
         if isSih:
-            print '--> Data SiH: {0:2f}'.format(s2h_value)
+            print('--> Data SiH: {0:2f}'.format(s2h_value))
         else:
-            print '--> Data S2H: {0:2f}'.format(s2h_value)
-        print '--> Data S1W: {0:2f}'.format(s1w_value)
+            print('--> Data S2H: {0:2f}'.format(s2h_value))
+        print('--> Data S1W: {0:2f}'.format(s1w_value))
         if isSiw:
-            print '--> Data SiW: {0:2f}'.format(s2w_value)
+            print('--> Data SiW: {0:2f}'.format(s2w_value))
         else:
-            print '--> Data S2W: {0:2f}'.format(s2w_value)
+            print('--> Data S2W: {0:2f}'.format(s2w_value))
 
         for i in range(nbr_row):
 
             _file_incidentMedium = getFieldValue(sfFactorTable,i,0)
             if _file_incidentMedium.strip() == _incidentMedium.strip():
-                print '*** incident medium match ***'
+                print('*** incident medium match ***')
                 _file_lambdaRequested = getFieldValue(sfFactorTable,i,1)
                 if (isWithinPrecisionRange(_file_lambdaRequested,
                                            _lr_value,
                                            valuePrecision)):
-                    print '*** lambda requested match ***'
+                    print('*** lambda requested match ***')
                     _file_s1h = getFieldValue(sfFactorTable,i,2)
                     if(isWithinPrecisionRange(_file_s1h,
                                               s1h_value,
                                               valuePrecision)):
-                        print '*** s1h match ***'
+                        print('*** s1h match ***')
                         _file_s2h = getFieldValue(sfFactorTable,i,3)
                         if(isWithinPrecisionRange(_file_s2h,
                                                   s2h_value,
                                                   valuePrecision)):
-                            print '*** s2h match ***'
+                            print('*** s2h match ***')
                             if slitsWidthFlag:
-                                print '*** (with slits width flag) ***'
+                                print('*** (with slits width flag) ***')
                                 _file_s1w = getFieldValue(sfFactorTable,i,4)
                                 if(isWithinPrecisionRange(_file_s1w,
                                                           s1w_value,
                                                           valuePrecision)):
-                                    print '*** s1w match ***'
+                                    print('*** s1w match ***')
                                     _file_s2w = getFieldValue(sfFactorTable,i,5)
                                     if(isWithinPrecisionRange(_file_s2w,
                                                               s2w_value,
                                                               valuePrecision)):
-                                        print '*** s2w match ***'
+                                        print('*** s2w match ***')
 
-                                        print '--> Found a perfect match'
+                                        print('--> Found a perfect match')
                                         a = float(getFieldValue(sfFactorTable,i,6))
                                         b = float(getFieldValue(sfFactorTable,i,7))
                                         a_error = float(getFieldValue(sfFactorTable,i,8))
@@ -1531,7 +1410,7 @@ def applyScalingFactor(tof_axis,
 
                             else:
 
-                                print '--> Found a perfect match'
+                                print('--> Found a perfect match')
                                 a = float(getFieldValue(sfFactorTable,i,6))
                                 b = float(getFieldValue(sfFactorTable,i,7))
                                 a_error = float(getFieldValue(sfFactorTable,i,8))
@@ -1548,7 +1427,7 @@ def applyScalingFactor(tof_axis,
 
     else:
 
-        print '-> scaling factor file for requested lambda NOT FOUND!'
+        print('-> scaling factor file for requested lambda NOT FOUND!')
         return [tof_axis, y_data, y_data_error]
 
 
@@ -1652,7 +1531,7 @@ def getCentralPixel(ws_event_data, dataPeakRange, is_new_geometry):
         start_pixel = start_pixel + 1
         _den += pixelXtof_roi[i]
     data_cpix = _num / _den
-    print '--> central pixel is {0:.1f}'.format(data_cpix)
+    print('--> central pixel is {0:.1f}'.format(data_cpix))
 
     return data_cpix
 
@@ -1663,7 +1542,7 @@ def getDistances(ws_event_data):
     and the distance between the sample and the detector
     """
 
-    print '--> calculating dMD (moderator-detector) and dSD (sample-detector)'
+    print('--> calculating dMD (moderator-detector) and dSD (sample-detector)')
     sample = ws_event_data.getInstrument().getSample()
     source = ws_event_data.getInstrument().getSource()
     dSM = sample.getDistance(source)
@@ -1688,7 +1567,7 @@ def  getTheta(ws_event_data, angleOffsetDeg):
     """
     will calculate the theta angle offset
     """
-    print '--> retrieving thi and tthd'
+    print('--> retrieving thi and tthd')
     mt_run = ws_event_data.getRun()
     thi_value = mt_run.getProperty('thi').value[0]
     thi_units = mt_run.getProperty('thi').units
@@ -1697,26 +1576,26 @@ def  getTheta(ws_event_data, angleOffsetDeg):
     thi_rad = angleUnitConversion(value=thi_value,
                                   from_units=thi_units,
                                   to_units='rad')
-    print '---> thi (rad): ', thi_rad
+    print('---> thi (rad): ', thi_rad)
     tthd_rad = angleUnitConversion(value=tthd_value,
                                    from_units=tthd_units,
                                    to_units='rad')
-    print '---> tthd (rad): ', tthd_rad
+    print('---> tthd (rad): ', tthd_rad)
 
     theta = math.fabs(tthd_rad - thi_rad)/2.
     angleOffsetRad = (angleOffsetDeg * math.pi) / 180.
     theta += angleOffsetRad
-    print '---> theta (rad): ', theta
+    print('---> theta (rad): ', theta)
 
     return theta
 
 
 def getSlitsSize(mt):
-    print '---> retrieving slits size'
+    print('---> retrieving slits size')
     first_slit_size = getSheight(mt, '1')
     last_slit_size = getSheight(mt,'2')
-    print '----> first_slit_size: ' , first_slit_size
-    print '----> last_slit_size: ' , last_slit_size
+    print('----> first_slit_size: ' , first_slit_size)
+    print('----> last_slit_size: ' , last_slit_size)
     return [first_slit_size, last_slit_size]
 
 
@@ -1725,7 +1604,7 @@ def getQrange(ws_histo_data, theta, dMD, q_min, q_step):
     will determine the true q axis according to the qMin and qStep specified
     and the geometry of the instrument
     """
-    print '---> calculating Qrange'
+    print('---> calculating Qrange')
     _tof_axis = ws_histo_data.readX(0)
     _const = float(4) * math.pi * m * dMD / h
     sz_tof = shape(_tof_axis)[0]
@@ -1739,9 +1618,9 @@ def getQrange(ws_histo_data, theta, dMD, q_min, q_step):
     q_max = max(_q_axis)
     if q_min >= q_max:
         q_min = min(_q_axis)
-    print '----> q_min: ', q_min
-    print '----> q_step: ', q_step
-    print '----> q_max: ', q_max
+    print('----> q_min: ', q_min)
+    print('----> q_step: ', q_step)
+    print('----> q_max: ', q_max)
 
     return [q_min, q_step, q_max]
 
@@ -1873,8 +1752,7 @@ def getQaxis(dMD, dSD, theta,
     sz_tof = len(tof_axis)
     q_array = zeros((len(y_range), sz_tof))
 
-    index_y = range(len(y_range))
-    for y in index_y:
+    for y in range(len(y_range)):
         _px = y_range[y]
         dangle = ref_beamdiv_correct(central_pixel,
                                      dSD,
@@ -1932,7 +1810,7 @@ def integrateOverPeakRange(wks, dataPeakRange):
 #    final_y_error_axis[:] = NAN
 
     # range(nbr_q -2) + 1 to get rid of first and last q values (edge effect)
-    rangeOfQ = range(nbr_q-1)
+    rangeOfQ = arange(nbr_q-1)
 #    for q in rangeOfQ[1:-1]:
     for q in rangeOfQ:
 
@@ -2104,15 +1982,15 @@ def cleanupData1D(final_data_y_axis, final_data_y_error_axis):
         final_data_y_axis[t] = _data_tmp
         final_data_y_error_axis[t] = _error_tmp
 
-#        print 'final_data_y_axis[t]: ' , _data_tmp , ' final_data_y_error_axis[t]: ' , _error_tmp
+#        print('final_data_y_axis[t]: ' , _data_tmp , ' final_data_y_error_axis[t]: ' , _error_tmp)
 
     return [final_data_y_axis, final_data_y_error_axis]
 
 
 def isNexusTakeAfterRefDate(nexus_date):
     '''
-   This function parses the output.date and returns true if this date is after the ref date
-   '''
+    This function parses the output.date and returns true if this date is after the ref date
+    '''
     nexus_date_acquistion = nexus_date.split('T')[0]
 
     if nexus_date_acquistion > ref_date:
diff --git a/scripts/reduction/instruments/sans/sans_reducer.py b/scripts/reduction/instruments/sans/sans_reducer.py
index ed4643c7b862078031e8281482be981a76131d39..a03efbd2a464abe73c3517cbdf2da8994b41f2d1 100644
--- a/scripts/reduction/instruments/sans/sans_reducer.py
+++ b/scripts/reduction/instruments/sans/sans_reducer.py
@@ -3,6 +3,7 @@
     a predefined set of reduction steps to be followed. The actual ReductionStep objects
     executed for each of those steps can be modified.
 """
+from __future__ import (absolute_import, division, print_function)
 from reduction import Reducer
 from reduction import ReductionStep
 from reduction import validate_step
diff --git a/scripts/reduction/instruments/sans/sans_reduction_steps.py b/scripts/reduction/instruments/sans/sans_reduction_steps.py
index c4a28117080744cb5d9ff4a9c711720142a38938..f3d77e985982fc6cda7b961ef943d66e17de04f4 100644
--- a/scripts/reduction/instruments/sans/sans_reduction_steps.py
+++ b/scripts/reduction/instruments/sans/sans_reduction_steps.py
@@ -2,6 +2,7 @@
 """
     Implementation of reduction steps for SANS
 """
+from __future__ import (absolute_import, division, print_function)
 import math
 import pickle
 from reduction import ReductionStep
@@ -305,7 +306,7 @@ class Mask(ReductionStep):
             mask_str = run.getProperty("rectangular_masks").value
             try:
                 rectangular_masks = pickle.loads(mask_str)
-            except (StandardError, Warning):
+            except (Exception, Warning):
                 rectangular_masks = []
                 toks = mask_str.split(',')
                 for item in toks:
@@ -316,7 +317,7 @@ class Mask(ReductionStep):
             for rec in rectangular_masks:
                 try:
                     self.add_pixel_rectangle(rec[0], rec[1], rec[2], rec[3])
-                except (StandardError, Warning):
+                except (Exception, Warning):
                     mantid.logger.notice("Badly defined mask from configuration file: %s" % str(rec))
 
         for shape in self._xml:
@@ -553,9 +554,9 @@ class ConvertToQ(ReductionStep):
         if (not self._grav_set) or override:
             self._use_gravity = bool(flag)
         else:
-            msg = "User file can't override previous gravity setting, do gravity correction remains " + str(
-                self._use_gravity)
-            print msg
+            msg = "User file can't override previous gravity setting, do gravity correction remains " \
+                  + str(self._use_gravity)
+            print(msg)
             sanslog.warning(msg)
 
     def execute(self, reducer, workspace):
@@ -609,7 +610,7 @@ class ConvertToQ(ReductionStep):
             try:
                 if AnalysisDataService.doesExist(wk):
                     AnalysisDataService.remove(wk)
-            except (StandardError, Warning):
+            except (Exception, Warning):
                 # if the workspace can't be deleted this function does nothing
                 pass
 
diff --git a/scripts/reduction/reducer.py b/scripts/reduction/reducer.py
index 0854667337f60305e66c3d5a3275ab5abea4e606..113c601df3cb4860377c6c6e8ff366c4f0da87f1 100644
--- a/scripts/reduction/reducer.py
+++ b/scripts/reduction/reducer.py
@@ -20,6 +20,7 @@
     instrument settings.
 
 """
+from __future__ import (absolute_import, division, print_function)
 import os
 import sys
 import time
@@ -509,7 +510,7 @@ class Reducer(object):
                     if result is not None and len(str(result)) > 0:
                         self.log_text += "%s\n" % str(result)
                 except:
-                    self.log_text += "\n%s\n" % sys.exc_value
+                    self.log_text += "\n%s\n" % sys.exc_info()[1]
                     raise
 
         # any clean up, possibly removing workspaces
diff --git a/scripts/reduction_workflow/command_interface.py b/scripts/reduction_workflow/command_interface.py
index 490fe35491c5f6fc1e1abeb0d30b4e3f78540c40..711d5a8dcd9751debf71cfcabd6d18d575caa5b9 100644
--- a/scripts/reduction_workflow/command_interface.py
+++ b/scripts/reduction_workflow/command_interface.py
@@ -2,7 +2,7 @@
 """
     List of user commands.
 """
-
+from __future__ import (absolute_import, division, print_function)
 from reduction_workflow.reducer import Reducer
 
 
diff --git a/scripts/reduction_workflow/instruments/sans/hfir_command_interface.py b/scripts/reduction_workflow/instruments/sans/hfir_command_interface.py
index 8a5a5326a2acded2a3014fd45971abae9853c9cd..b0cf2f87008d0a853430fff27e06ff9c98d32857 100644
--- a/scripts/reduction_workflow/instruments/sans/hfir_command_interface.py
+++ b/scripts/reduction_workflow/instruments/sans/hfir_command_interface.py
@@ -4,7 +4,7 @@
 List of common user commands for HFIR SANS
 
 """
-
+from __future__ import (absolute_import, division, print_function)
 import os.path
 import mantid
 
diff --git a/scripts/reduction_workflow/instruments/sans/hfir_instrument.py b/scripts/reduction_workflow/instruments/sans/hfir_instrument.py
index 44eb3422d6546efe702e053624d58491e99d7da3..442bcd71cb2da508b0d6dbfa334d54d3cd54da62 100644
--- a/scripts/reduction_workflow/instruments/sans/hfir_instrument.py
+++ b/scripts/reduction_workflow/instruments/sans/hfir_instrument.py
@@ -1,4 +1,5 @@
 # pylint: disable=invalid-name,too-many-arguments,too-many-branches
+from __future__ import (absolute_import, division, print_function)
 import sys
 from mantid.kernel import Logger
 
diff --git a/scripts/reduction_workflow/instruments/sans/sns_command_interface.py b/scripts/reduction_workflow/instruments/sans/sns_command_interface.py
index ae30908e0f8ab998ef21285833a77f75bd2210c3..5af57ec224172740e5d2d05781241ba7f22123b1 100644
--- a/scripts/reduction_workflow/instruments/sans/sns_command_interface.py
+++ b/scripts/reduction_workflow/instruments/sans/sns_command_interface.py
@@ -3,39 +3,41 @@
     Command set for EQSANS reduction
 """
 # Import the specific commands that we need - some of these are used in systemtests
+from __future__ import (absolute_import, division, print_function)
 from reduction_workflow.command_interface import *
 
-from hfir_command_interface import SolidAngle
-from hfir_command_interface import SetBeamCenter as BaseSetBeamCenter
-
 # The following imports allow users to import this file and have all functionality automatically imported
 # Do not remove these imports as it will break user scripts which rely on them
 
-from hfir_command_interface import DarkCurrent, NoDarkCurrent, NoNormalization, NoSolidAngle  # noqa: F401
-from hfir_command_interface import DirectBeamCenter, ScatteringBeamCenter  # noqa: F401
-from hfir_command_interface import SensitivityCorrection, SetSensitivityBeamCenter  # noqa: F401
-from hfir_command_interface import SensitivityDirectBeamCenter, SensitivityScatteringBeamCenter  # noqa: F401
-from hfir_command_interface import NoSensitivityCorrection, DivideByThickness  # noqa: F401
+from .hfir_command_interface import DarkCurrent, NoDarkCurrent, NoNormalization  # noqa: F401
+from .hfir_command_interface import SolidAngle, NoSolidAngle  # noqa: F401
+from .hfir_command_interface import DirectBeamCenter, ScatteringBeamCenter  # noqa: F401
+from .hfir_command_interface import SetBeamCenter as BaseSetBeamCenter  # noqa: F401
+
+from .hfir_command_interface import SensitivityCorrection, SetSensitivityBeamCenter  # noqa: F401
+from .hfir_command_interface import SensitivityDirectBeamCenter, SensitivityScatteringBeamCenter  # noqa: F401
+from .hfir_command_interface import NoSensitivityCorrection, DivideByThickness  # noqa: F401
 
-from hfir_command_interface import IQxQy, NoIQxQy, SaveIq, NoSaveIq, SaveIqAscii  # noqa: F401
+from .hfir_command_interface import IQxQy, NoIQxQy, SaveIq, NoSaveIq, SaveIqAscii  # noqa: F401
 
-from hfir_command_interface import DirectBeamTransmission, TransmissionDarkCurrent  # noqa: F401
-from hfir_command_interface import ThetaDependentTransmission  # noqa: F401
-from hfir_command_interface import SetTransmissionBeamCenter, TransmissionDirectBeamCenter  # noqa: F401
-from hfir_command_interface import SetTransmission, NoTransmission  # noqa: F401
+from .hfir_command_interface import DirectBeamTransmission, TransmissionDarkCurrent  # noqa: F401
+from .hfir_command_interface import ThetaDependentTransmission  # noqa: F401
+from .hfir_command_interface import SetTransmissionBeamCenter, TransmissionDirectBeamCenter  # noqa: F401
+from .hfir_command_interface import SetTransmission, NoTransmission  # noqa: F401
 
-from hfir_command_interface import Background, NoBackground, NoBckTransmission  # noqa: F401
-from hfir_command_interface import SetBckTransmission, BckDirectBeamTransmission  # noqa: F401
-from hfir_command_interface import SetBckTransmissionBeamCenter, BckThetaDependentTransmission  # noqa: F401
-from hfir_command_interface import BckTransmissionDirectBeamCenter, BckTransmissionDarkCurrent  # noqa: F401
+from .hfir_command_interface import Background, NoBackground, NoBckTransmission  # noqa: F401
+from .hfir_command_interface import SetBckTransmission, BckDirectBeamTransmission  # noqa: F401
+from .hfir_command_interface import SetBckTransmissionBeamCenter, BckThetaDependentTransmission  # noqa: F401
+from .hfir_command_interface import BckTransmissionDirectBeamCenter, BckTransmissionDarkCurrent  # noqa: F401
 
-from hfir_command_interface import SetSampleDetectorOffset, SetSampleDetectorDistance  # noqa: F401
-from hfir_command_interface import Mask, MaskRectangle, MaskDetectors, MaskDetectorSide  # noqa: F401
-from hfir_command_interface import SetAbsoluteScale, SetDirectBeamAbsoluteScale  # noqa: F401
-from hfir_command_interface import Stitch
+from .hfir_command_interface import SetSampleDetectorOffset, SetSampleDetectorDistance  # noqa: F401
+from .hfir_command_interface import Mask, MaskRectangle, MaskDetectors, MaskDetectorSide  # noqa: F401
+from .hfir_command_interface import SetAbsoluteScale, SetDirectBeamAbsoluteScale  # noqa: F401
+from .hfir_command_interface import Stitch  # noqa: F401
 
 from reduction_workflow.find_data import find_data
 
+
 def EQSANS(keep_events=False, property_manager=None):
     Clear()
     ReductionSingleton().set_instrument("EQSANS",
diff --git a/scripts/reduction_workflow/reducer.py b/scripts/reduction_workflow/reducer.py
index 8122561d4a42df036fe4e287f39d80e9f823ca68..593866de850338a485c405cabfd2b4514ada7321 100644
--- a/scripts/reduction_workflow/reducer.py
+++ b/scripts/reduction_workflow/reducer.py
@@ -2,6 +2,7 @@
 """
     Base reduction class. Uses version 2 python API.
 """
+from __future__ import (absolute_import, division, print_function)
 import os
 import sys
 import time
@@ -120,13 +121,13 @@ class Reducer(object):
             alg = AlgorithmManager.create(self.setup_algorithm)
             alg.initialize()
             props = [p.name for p in alg.getProperties()]
-            for key in self.reduction_properties.keys():
+            for key in list(self.reduction_properties.keys()):
                 if key in props:
                     try:
                         alg.setProperty(key, self.reduction_properties[key])
                     except:
                         msg = "Error setting %s=%s" % (key, str(self.reduction_properties[key]))
-                        msg += "\n  %s" % sys.exc_value
+                        msg += "\n  %s" % sys.exc_info()[1]
                         Logger("Reducer").error(msg)
                 else:
                     Logger("Reducer").warning("Setup algorithm has no %s property" % key)
@@ -162,7 +163,7 @@ class Reducer(object):
             return
 
         _first_ws_name = None
-        for ws in self._data_files.keys():
+        for ws in list(self._data_files.keys()):
             if _first_ws_name is None:
                 _first_ws_name = ws
             alg = AlgorithmManager.create(self.reduction_algorithm)
diff --git a/scripts/test/ISISPowderAbsorptionTest.py b/scripts/test/ISISPowderAbsorptionTest.py
index ccf1c68bcb3535e22f8c0defa7ce66e77e0b9cfc..3e288d8ed1ea5edd9dbd1c1e786657c68162a881 100644
--- a/scripts/test/ISISPowderAbsorptionTest.py
+++ b/scripts/test/ISISPowderAbsorptionTest.py
@@ -17,7 +17,7 @@ class ISISPowderAbsorptionTest(unittest.TestCase):
 
         ws = mantid.CreateSampleWorkspace(Function='Flat background', NumBanks=1, BankPixelWidth=1, XMax=10, BinWidth=1)
         ws = absorb_corrections.run_cylinder_absorb_corrections(ws_to_correct=ws, multiple_scattering=False,
-                                                                sample_details_obj=sample_details)
+                                                                sample_details_obj=sample_details, is_vanadium=True)
 
         self.assertAlmostEqual(ws.dataY(0)[2], 1.16864808, delta=1e-8)
         self.assertAlmostEqual(ws.dataY(0)[5], 1.16872761, delta=1e-8)
diff --git a/scripts/test/SANS/CMakeLists.txt b/scripts/test/SANS/CMakeLists.txt
index 5982d712d802e829a58ec14882f432892a584d6d..ff0930493d4fd95ddbfb743d1621d094eb821fd2 100644
--- a/scripts/test/SANS/CMakeLists.txt
+++ b/scripts/test/SANS/CMakeLists.txt
@@ -1,6 +1,7 @@
 add_subdirectory(algorithm_detail)
-add_subdirectory(command_interface)
 add_subdirectory(common)
+add_subdirectory(command_interface)
+add_subdirectory(gui_logic)
 add_subdirectory(state)
 add_subdirectory(user_file)
 
diff --git a/scripts/test/SANS/algorithm_detail/CMakeLists.txt b/scripts/test/SANS/algorithm_detail/CMakeLists.txt
index e838aff992061b20babb17578e2ae292b7929965..1e97c3fb632701eee09a64c43470a320689a49e4 100644
--- a/scripts/test/SANS/algorithm_detail/CMakeLists.txt
+++ b/scripts/test/SANS/algorithm_detail/CMakeLists.txt
@@ -4,6 +4,7 @@
 
 set ( TEST_PY_FILES
   calculate_transmission_helper_test.py
+  crop_helper_test.py
   merge_reductions_test.py
   q_resolution_calculator_test.py
   scale_helper_test.py
diff --git a/scripts/test/SANS/algorithm_detail/crop_helper_test.py b/scripts/test/SANS/algorithm_detail/crop_helper_test.py
new file mode 100644
index 0000000000000000000000000000000000000000..b22479ff45f211a64b9371fa97f17fa50037930e
--- /dev/null
+++ b/scripts/test/SANS/algorithm_detail/crop_helper_test.py
@@ -0,0 +1,40 @@
+from __future__ import (absolute_import, division, print_function)
+import unittest
+import mantid
+from sans.algorithm_detail.crop_helper import get_component_name
+from sans.common.enums import DetectorType
+from sans.common.constants import EMPTY_NAME
+from sans.common.general_functions import create_unmanaged_algorithm
+from mantid.api import FileFinder
+
+
+class CropHelperTest(unittest.TestCase):
+    def _get_workspace(self, file_name):
+        full_file_name = FileFinder.findRuns(file_name)[0]
+        load_name = "Load"
+        load_options = {"Filename": full_file_name,
+                        "OutputWorkspace": EMPTY_NAME}
+        load_alg = create_unmanaged_algorithm(load_name, **load_options)
+        load_alg.execute()
+        return load_alg.getProperty("OutputWorkspace").value
+
+    def test_that_can_get_component_name_for_sans2d(self):
+        workspace = self._get_workspace("SANS2D00022024")
+        self.assertTrue("front-detector" == get_component_name(workspace, DetectorType.HAB))
+        self.assertTrue("rear-detector" == get_component_name(workspace, DetectorType.LAB))
+
+    def test_that_can_get_component_name_for_loq(self):
+        workspace = self._get_workspace("LOQ48127")
+        self.assertTrue("HAB" == get_component_name(workspace, DetectorType.HAB))
+        self.assertTrue("main-detector-bank" == get_component_name(workspace, DetectorType.LAB))
+
+    def test_that_can_get_component_name_for_larmor(self):
+        workspace = self._get_workspace("LARMOR00002260")
+        self.assertTrue("DetectorBench" == get_component_name(workspace, DetectorType.HAB))
+
+    def test_that_can_get_component_name_for_zoom(self):
+        # TODO when test data is available
+        pass
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/scripts/test/SANS/algorithm_detail/q_resolution_calculator_test.py b/scripts/test/SANS/algorithm_detail/q_resolution_calculator_test.py
index 51fa462f2057eafcb5e56fb520a45b7115d144c9..fcabc2d7cad66e1a7fba1f2816eeb028c29cff0b 100644
--- a/scripts/test/SANS/algorithm_detail/q_resolution_calculator_test.py
+++ b/scripts/test/SANS/algorithm_detail/q_resolution_calculator_test.py
@@ -11,7 +11,7 @@ from math import sqrt
 from sans.algorithm_detail.q_resolution_calculator import (QResolutionCalculatorFactory, NullQResolutionCalculator,
                                                            QResolutionCalculatorISIS, get_aperture_diameters,
                                                            load_sigma_moderator_workspace, create_q_resolution_workspace)
-from sans.common.enums import SANSInstrument
+from sans.common.enums import (SANSInstrument, SANSFacility)
 
 
 class MockContainer:
@@ -75,6 +75,7 @@ class QResolutionCalculatorTest(unittest.TestCase):
         mock_state = MockContainer()
         mock_state.data = MockContainer()
         mock_state.data.instrument = SANSInstrument.LARMOR
+        mock_state.data.facility = SANSFacility.ISIS
         convert_to_q = MockContainer()
         convert_to_q.use_q_resolution = use_q_resolution
         for key, value in kwargs.items():
@@ -82,11 +83,11 @@ class QResolutionCalculatorTest(unittest.TestCase):
         mock_state.convert_to_q = convert_to_q
         return mock_state
 
-    def test_that_raises_when_unknown_instrument_is_chosen(self):
+    def test_that_raises_when_unknown_facility_is_chosen(self):
         # Arrange
         mock_state = MockContainer()
         mock_state.data = MockContainer()
-        mock_state.data.instrument = None
+        mock_state.data.facility = None
         factory = QResolutionCalculatorFactory()
 
         # Act + Assert
diff --git a/scripts/test/SANS/command_interface/command_interface_state_director_test.py b/scripts/test/SANS/command_interface/command_interface_state_director_test.py
index ffcf56e17b9d1fc9dee733a5fbc8ba8bc1d1afd3..db7ae06105cad1535d5e8079e558c7aeb089b788 100644
--- a/scripts/test/SANS/command_interface/command_interface_state_director_test.py
+++ b/scripts/test/SANS/command_interface/command_interface_state_director_test.py
@@ -69,7 +69,7 @@ class CommandInterfaceStateDirectorTest(unittest.TestCase):
 
         # # Trans fit
         command = NParameterCommand(command_id=NParameterCommandId.trans_fit, values=[FitData.Can, 10.4, 12.54,
-                                                                                      FitType.Log, 0])
+                                                                                      FitType.Logarithmic, 0])
         self._assert_raises_nothing(command_interface.add_command, command)
 
         # Front detector rescale
@@ -135,7 +135,7 @@ class CommandInterfaceStateDirectorTest(unittest.TestCase):
         self.assertTrue(state.move.detectors[DetectorType.to_string(DetectorType.HAB)].sample_centre_pos2
                         == 23.54/1000.)
         self.assertTrue(state.adjustment.calculate_transmission.fit[DataType.to_string(DataType.Can)].fit_type
-                        is FitType.Log)
+                        is FitType.Logarithmic)
         self.assertTrue(state.adjustment.calculate_transmission.fit[DataType.to_string(DataType.Can)].polynomial_order
                         == 0)
 
diff --git a/scripts/test/SANS/common/enums_test.py b/scripts/test/SANS/common/enums_test.py
index 781b0f02cbfa29aacf219c06d1c7cc519b1ff523..6b39c4dcee941d4ef6147b082bb3a7e50bc69fb3 100644
--- a/scripts/test/SANS/common/enums_test.py
+++ b/scripts/test/SANS/common/enums_test.py
@@ -1,6 +1,5 @@
 from __future__ import (absolute_import, division, print_function)
 import unittest
-import mantid
 
 from sans.common.enums import serializable_enum, string_convertible
 
diff --git a/scripts/test/SANS/common/general_functions_test.py b/scripts/test/SANS/common/general_functions_test.py
index 542f53a58a893829e9c61936321d82d105302180..b75c32c0ff617b176095b31b031a8650c47baca6 100644
--- a/scripts/test/SANS/common/general_functions_test.py
+++ b/scripts/test/SANS/common/general_functions_test.py
@@ -6,9 +6,13 @@ from mantid.kernel import (V3D, Quat)
 from mantid.api import AnalysisDataService
 from sans.common.general_functions import (quaternion_to_angle_and_axis, create_unmanaged_algorithm, add_to_sample_log,
                                            get_standard_output_workspace_name, sanitise_instrument_name,
-                                           get_reduced_can_workspace_from_ads, write_hash_into_reduced_can_workspace)
+                                           get_reduced_can_workspace_from_ads, write_hash_into_reduced_can_workspace,
+                                           convert_instrument_and_detector_type_to_bank_name,
+                                           convert_bank_name_to_detector_type_isis,
+                                           get_facility)
 from sans.common.constants import (SANS2D, LOQ, LARMOR)
-from sans.common.enums import (ISISReductionMode, ReductionDimensionality, OutputParts)
+from sans.common.enums import (ISISReductionMode, ReductionDimensionality, OutputParts,
+                               SANSInstrument, DetectorType, SANSFacility)
 from sans.test_helper.test_director import TestDirector
 from sans.state.data import StateData
 
@@ -191,7 +195,7 @@ class SANSFunctionsTest(unittest.TestCase):
                                               reduction_mode=ISISReductionMode.LAB)
         # Act
         workspace, workspace_count, workspace_norm = get_reduced_can_workspace_from_ads(state, output_parts=True,
-                                                                            reduction_mode=ISISReductionMode.LAB)
+                                                                              reduction_mode=ISISReductionMode.LAB)  # noqa
 
         # Assert
         self.assertTrue(workspace is not None)
@@ -228,6 +232,37 @@ class SANSFunctionsTest(unittest.TestCase):
         # Clean up
         SANSFunctionsTest._remove_workspaces()
 
+    def test_that_convert_instrument_and_detector_type_to_bank_name_produces_expected_results(self):
+        self.assertTrue("front-detector" == convert_instrument_and_detector_type_to_bank_name(SANSInstrument.SANS2D,
+                                                                                              DetectorType.HAB))
+        self.assertTrue("rear-detector" == convert_instrument_and_detector_type_to_bank_name(SANSInstrument.SANS2D,
+                                                                                             DetectorType.LAB))
+        self.assertTrue("HAB" == convert_instrument_and_detector_type_to_bank_name(SANSInstrument.LOQ,
+                                                                                   DetectorType.HAB))
+        self.assertTrue("main-detector-bank" == convert_instrument_and_detector_type_to_bank_name(SANSInstrument.LOQ,
+                                                                                                  DetectorType.LAB))
+        self.assertTrue("DetectorBench" == convert_instrument_and_detector_type_to_bank_name(SANSInstrument.LARMOR,
+                                                                                             DetectorType.LAB))
+        self.assertTrue("rear-detector" == convert_instrument_and_detector_type_to_bank_name(SANSInstrument.ZOOM,
+                                                                                             DetectorType.LAB))
+
+    def test_that_converts_detector_name_to_type(self):
+        self.assertTrue(convert_bank_name_to_detector_type_isis("rEar-detector") is DetectorType.LAB)
+        self.assertTrue(convert_bank_name_to_detector_type_isis("MAIN-detector-BANK") is DetectorType.LAB)
+        self.assertTrue(convert_bank_name_to_detector_type_isis("DeTectorBench") is DetectorType.LAB)
+        self.assertTrue(convert_bank_name_to_detector_type_isis("rear") is DetectorType.LAB)
+        self.assertTrue(convert_bank_name_to_detector_type_isis("MAIN") is DetectorType.LAB)
+        self.assertTrue(convert_bank_name_to_detector_type_isis("FRoNT-DETECTOR") is DetectorType.HAB)
+        self.assertTrue(convert_bank_name_to_detector_type_isis("HaB") is DetectorType.HAB)
+        self.assertTrue(convert_bank_name_to_detector_type_isis("front") is DetectorType.HAB)
+        self.assertRaises(RuntimeError, convert_bank_name_to_detector_type_isis, "test")
+
+    def test_that_gets_facility(self):
+        self.assertTrue(get_facility(SANSInstrument.SANS2D) is SANSFacility.ISIS)
+        self.assertTrue(get_facility(SANSInstrument.LOQ) is SANSFacility.ISIS)
+        self.assertTrue(get_facility(SANSInstrument.LARMOR) is SANSFacility.ISIS)
+        self.assertTrue(get_facility(SANSInstrument.ZOOM) is SANSFacility.ISIS)
+        self.assertTrue(get_facility(SANSInstrument.NoInstrument) is SANSFacility.NoFacility)
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/scripts/test/SANS/gui_logic/CMakeLists.txt b/scripts/test/SANS/gui_logic/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..29555556194c187b15694e70b2fc7a851397b397
--- /dev/null
+++ b/scripts/test/SANS/gui_logic/CMakeLists.txt
@@ -0,0 +1,19 @@
+##
+## Tests for SANS
+##
+
+set ( TEST_PY_FILES
+  gui_state_director_test.py
+  gui_common_test.py
+  main_presenter_test.py
+  masking_table_presenter_test.py
+  property_manager_service_test.py
+  run_tab_presenter_test.py
+  state_gui_model_test.py
+  settings_diagnostic_presenter_test.py
+  table_model_test.py
+)
+
+check_tests_valid ( ${CMAKE_CURRENT_SOURCE_DIR} ${TEST_PY_FILES} )
+
+pyunittest_add_test ( ${CMAKE_CURRENT_SOURCE_DIR} PythonSANS ${TEST_PY_FILES} )
\ No newline at end of file
diff --git a/scripts/test/SANS/gui_logic/gui_common_test.py b/scripts/test/SANS/gui_logic/gui_common_test.py
new file mode 100644
index 0000000000000000000000000000000000000000..30101d3aabfcc8a8cef6a8ed04ccfbe3732dd234
--- /dev/null
+++ b/scripts/test/SANS/gui_logic/gui_common_test.py
@@ -0,0 +1,68 @@
+from __future__ import (absolute_import, division, print_function)
+
+import unittest
+
+import mantid
+
+from sans.gui_logic.gui_common import (get_reduction_mode_strings_for_gui, get_reduction_selection,
+                                       get_string_for_gui_from_reduction_mode)
+from sans.common.enums import (SANSInstrument, ISISReductionMode)
+
+
+class GuiCommonTest(unittest.TestCase):
+    def _assert_same(self, collection1, collection2):
+        for element1, element2 in zip(collection1, collection2):
+            self.assertTrue(element1 == element2)
+
+    def _assert_same_map(self, map1, map2):
+        self.assertTrue(len(map1) == len(map2))
+
+        for key, value in map1.items():
+            self.assertTrue(key in map2)
+            self.assertTrue(map1[key] == map2[key])
+
+    def do_test_reduction_mode_string(self, instrument, reduction_mode, reduction_mode_string):
+        setting = get_string_for_gui_from_reduction_mode(reduction_mode, instrument)
+        self.assertTrue(setting == reduction_mode_string)
+
+    def test_that_gets_reduction_mode_string_for_gui(self):
+        sans_settings = get_reduction_mode_strings_for_gui(SANSInstrument.SANS2D)
+        self._assert_same(sans_settings, ["rear", "front", "Merged", "All"])
+
+        loq_settings = get_reduction_mode_strings_for_gui(SANSInstrument.LOQ)
+        self._assert_same(loq_settings, ["main-detector", "Hab", "Merged", "All"])
+
+        larmor_settings = get_reduction_mode_strings_for_gui(SANSInstrument.LARMOR)
+        self._assert_same(larmor_settings, ["DetectorBench"])
+
+        default_settings = get_reduction_mode_strings_for_gui(SANSInstrument.NoInstrument)
+        self._assert_same(default_settings, ["LAB", "HAB", "Merged", "All"])
+
+    def test_that_gets_correct_reduction_selection(self):
+        sans_settings = get_reduction_selection(SANSInstrument.SANS2D)
+        self._assert_same_map(sans_settings, {ISISReductionMode.LAB: "rear", ISISReductionMode.HAB: "front",
+                                              ISISReductionMode.Merged: "Merged", ISISReductionMode.All: "All"})
+
+        loq_settings = get_reduction_selection(SANSInstrument.LOQ)
+        self._assert_same_map(loq_settings, {ISISReductionMode.LAB: "main-detector", ISISReductionMode.HAB: "Hab",
+                                             ISISReductionMode.Merged: "Merged", ISISReductionMode.All: "All"})
+
+        larmor_settings = get_reduction_selection(SANSInstrument.LARMOR)
+        self._assert_same_map(larmor_settings, {ISISReductionMode.LAB: "DetectorBench"})
+
+        default_settings = get_reduction_selection(SANSInstrument.NoInstrument)
+        self._assert_same_map(default_settings, {ISISReductionMode.LAB: "LAB", ISISReductionMode.HAB: "HAB",
+                                                 ISISReductionMode.Merged: "Merged", ISISReductionMode.All: "All"})
+
+    def test_that_can_get_reduction_mode_string(self):
+        self.do_test_reduction_mode_string(SANSInstrument.SANS2D, ISISReductionMode.LAB, "rear")
+        self.do_test_reduction_mode_string(SANSInstrument.LOQ, ISISReductionMode.HAB, "Hab")
+        self.do_test_reduction_mode_string(SANSInstrument.LARMOR, ISISReductionMode.LAB, "DetectorBench")
+        self.do_test_reduction_mode_string(SANSInstrument.NoInstrument, ISISReductionMode.LAB, "LAB")
+        self.do_test_reduction_mode_string(SANSInstrument.NoInstrument, ISISReductionMode.HAB, "HAB")
+
+
+if __name__ == '__main__':
+    unittest.main()
+
+
diff --git a/scripts/test/SANS/gui_logic/gui_state_director_test.py b/scripts/test/SANS/gui_logic/gui_state_director_test.py
new file mode 100644
index 0000000000000000000000000000000000000000..124523118202ab7c66c722bc8b1c69631e538d42
--- /dev/null
+++ b/scripts/test/SANS/gui_logic/gui_state_director_test.py
@@ -0,0 +1,73 @@
+from __future__ import (absolute_import, division, print_function)
+
+import unittest
+import os
+
+import mantid
+
+from sans.gui_logic.presenter.gui_state_director import GuiStateDirector
+from sans.gui_logic.models.table_model import (TableModel, TableIndexModel)
+from sans.gui_logic.models.state_gui_model import StateGuiModel
+from sans.user_file.user_file_reader import UserFileReader
+from sans.common.enums import SANSFacility
+from sans.state.state import State
+from sans.test_helper.user_file_test_helper import create_user_file, sample_user_file
+
+
+class GuiStateDirectorTest(unittest.TestCase):
+    @staticmethod
+    def _get_table_model(option_string=""):
+        table_index_model = TableIndexModel(0, "SANS2D00022024", "", "",
+                                            "", "", "", "", option_string)
+        table_model = TableModel()
+        table_model.add_table_entry(0, table_index_model)
+        return table_model
+
+    @staticmethod
+    def _get_state_gui_model():
+        user_file_path = create_user_file(sample_user_file)
+        user_file_reader = UserFileReader(user_file_path)
+        user_file_items = user_file_reader.read_user_file()
+        if os.path.exists(user_file_path):
+            os.remove(user_file_path)
+        return StateGuiModel(user_file_items)
+
+    def test_that_can_construct_state_from_models(self):
+        table_model = self._get_table_model()
+        state_model = self._get_state_gui_model()
+        director = GuiStateDirector(table_model, state_model, SANSFacility.ISIS)
+        state = director.create_state(0)
+        self.assertTrue(isinstance(state, State))
+        try:
+            state.validate()
+            has_raised = False
+        except ValueError:
+            has_raised = True
+        self.assertFalse(has_raised)
+        self.assertTrue(state.wavelength.wavelength_low == 1.5)
+        self.assertTrue(state.wavelength.wavelength_high == 12.5)
+
+    def test_that_will_raise_when_models_are_incomplete(self):
+        table_index_model = TableIndexModel(0, "", "", "",
+                                            "", "", "")
+        table_model = TableModel()
+        table_model.add_table_entry(0, table_index_model)
+        state_model = self._get_state_gui_model()
+        director = GuiStateDirector(table_model, state_model, SANSFacility.ISIS)
+        self.assertRaises(ValueError, director.create_state, 0)
+
+    def test_that_column_options_are_set_on_state(self):
+        table_model = self._get_table_model(option_string="WavelengthMin=3.14,WavelengthMax=10.3")
+        state_model = self._get_state_gui_model()
+        director = GuiStateDirector(table_model, state_model, SANSFacility.ISIS)
+
+        state = director.create_state(0)
+        self.assertTrue(isinstance(state, State))
+        self.assertTrue(state.wavelength.wavelength_low == 3.14)
+        self.assertTrue(state.wavelength.wavelength_high == 10.3)
+
+
+if __name__ == '__main__':
+    unittest.main()
+
+
diff --git a/scripts/test/SANS/gui_logic/main_presenter_test.py b/scripts/test/SANS/gui_logic/main_presenter_test.py
new file mode 100644
index 0000000000000000000000000000000000000000..088544c0c3bd26d06ab267c0063bdb6be101d52c
--- /dev/null
+++ b/scripts/test/SANS/gui_logic/main_presenter_test.py
@@ -0,0 +1,71 @@
+from __future__ import (absolute_import, division, print_function)
+
+import unittest
+
+import mantid
+
+from sans.test_helper.mock_objects import (create_mock_view2)
+from sans.gui_logic.presenter.main_presenter import MainPresenter
+from sans.common.enums import SANSFacility
+from sans.test_helper.user_file_test_helper import (create_user_file, sample_user_file)
+from sans.test_helper.common import (remove_file, save_to_csv)
+
+
+class MainPresenterTest(unittest.TestCase):
+    def test_that_gets_correct_gui_algorithm_name(self):
+        presenter = MainPresenter(SANSFacility.ISIS)
+        gui_algorithm_name = presenter.get_gui_algorithm_name()
+        self.assertTrue(gui_algorithm_name == "SANSGuiDataProcessorAlgorithm")
+
+    def test_that_the_white_list_is_correct(self):
+        presenter = MainPresenter(SANSFacility.ISIS)
+        self.assertTrue(presenter.get_number_of_white_list_items() == 0)
+        white_list = presenter.get_white_list()
+        self.assertTrue(presenter.get_number_of_white_list_items() == 10)
+        self.assertTrue(white_list[0].algorithm_property == "SampleScatter")
+        self.assertTrue(white_list[1].algorithm_property == "SampleTransmission")
+        self.assertTrue(white_list[2].algorithm_property == "SampleDirect")
+        self.assertTrue(white_list[3].algorithm_property == "CanScatter")
+        self.assertTrue(white_list[4].algorithm_property == "CanTransmission")
+        self.assertTrue(white_list[5].algorithm_property == "CanDirect")
+        self.assertTrue(white_list[6].algorithm_property == "UseOptimizations")
+        self.assertTrue(white_list[7].algorithm_property == "OutputName")
+        self.assertTrue(white_list[8].algorithm_property == "RowIndex")
+        self.assertTrue(white_list[9].algorithm_property == "OutputMode")
+
+    def test_that_black_list_is_correct(self):
+        presenter = MainPresenter(SANSFacility.ISIS)
+        expected = "InputWorkspace,OutputWorkspace,SampleScatter,SampleTransmission,SampleDirect,CanScatter," \
+                   "CanTransmission,CanDirect,UseOptimizations,OutputName,RowIndex,OutputMode,"
+        self.assertTrue(expected == presenter.get_black_list())
+
+    def test_that_gets_pre_processing_options_are_valid_and_other_options_are_empty(self):
+        # Arrange
+        presenter = MainPresenter(SANSFacility.ISIS)
+        content = "# MANTID_BATCH_FILE add more text here\n" \
+                  "sample_sans,SANS2D00022024,sample_trans,SANS2D00022048," \
+                  "sample_direct_beam,SANS2D00022048,output_as,test_file\n" \
+                  "sample_sans,SANS2D00022024,output_as,test_file2\n"
+        batch_file_path = save_to_csv(content)
+        user_file_path = create_user_file(sample_user_file)
+        view = create_mock_view2(user_file_path, batch_file_path)
+        presenter.set_view(view)
+
+        # Act
+        pre_processing_options = presenter.getProcessingOptions()
+
+        # Assert
+        expected = "UseOptimizations=1,OutputMode=PublishToADS"
+        self.assertTrue(expected == pre_processing_options)
+        self.assertFalse(presenter.getPreprocessingOptionsAsString())
+        self.assertFalse(presenter.getPostprocessingOptions())
+
+        # Clean up
+        remove_file(sample_user_file)
+        remove_file(user_file_path)
+
+
+if __name__ == '__main__':
+    unittest.main()
+
+
diff --git a/scripts/test/SANS/gui_logic/masking_table_presenter_test.py b/scripts/test/SANS/gui_logic/masking_table_presenter_test.py
new file mode 100644
index 0000000000000000000000000000000000000000..dac5315ef531b18abc6060b3350cef933b7fa10d
--- /dev/null
+++ b/scripts/test/SANS/gui_logic/masking_table_presenter_test.py
@@ -0,0 +1,40 @@
+from __future__ import (absolute_import, division, print_function)
+
+import unittest
+import sys
+
+import mantid
+
+from sans.gui_logic.presenter.masking_table_presenter import (MaskingTablePresenter, masking_information)
+from sans.test_helper.mock_objects import (FakeParentPresenter, FakeState, create_mock_masking_table, create_run_tab_presenter_mock)
+if sys.version_info.major == 3:
+    from unittest import mock
+else:
+    import mock
+
+
+class MaskingTablePresenterTest(unittest.TestCase):
+    def test_that_can_get_state_for_index(self):
+        parent_presenter = create_run_tab_presenter_mock()
+        presenter = MaskingTablePresenter(parent_presenter)
+        state = presenter.get_state(3)
+        self.assertTrue(isinstance(state, FakeState))
+
+    def test_that_sets_table_when_row_changes(self):
+        # Arrange
+        parent_presenter = create_run_tab_presenter_mock(use_fake_state=False)
+        view = create_mock_masking_table()
+        presenter = MaskingTablePresenter(parent_presenter)
+        # Act + Assert
+        presenter.set_view(view)
+        self.assertTrue(view.set_table.call_count == 1)
+        presenter.on_row_changed()
+        self.assertTrue(view.set_table.call_count == 2)
+        first_call = mock.call([])
+        second_call = mock.call([masking_information(first='Beam stop', second='', third='infinite-cylinder, r = 10.0'),
+                                 masking_information(first='Corners', second='', third='infinite-cylinder, r = 20.0')])  # noqa
+        view.set_table.assert_has_calls([first_call, second_call])
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/scripts/test/SANS/gui_logic/property_manager_service_test.py b/scripts/test/SANS/gui_logic/property_manager_service_test.py
new file mode 100644
index 0000000000000000000000000000000000000000..97852827cfd8f105b5c8a2bc8ed0c407fd197f8f
--- /dev/null
+++ b/scripts/test/SANS/gui_logic/property_manager_service_test.py
@@ -0,0 +1,99 @@
+from __future__ import (absolute_import, division, print_function)
+
+import unittest
+
+import mantid
+from mantid.kernel import PropertyManagerDataService, PropertyManagerProperty
+from mantid.api import Algorithm
+
+from sans.gui_logic.presenter.property_manager_service import PropertyManagerService
+from sans.state.data import get_data_builder
+from sans.test_helper.test_director import TestDirector
+from sans.common.enums import SANSFacility
+
+
+class FakeAlgorithm(Algorithm):
+    def PyInit(self):
+        self.declareProperty(PropertyManagerProperty("Args"))
+
+    def PyExec(self):
+        pass
+
+
+def get_example_state():
+    ws_name_sample = "SANS2D00022024"
+    data_builder = get_data_builder(SANSFacility.ISIS)
+    data_builder.set_sample_scatter(ws_name_sample)
+    data = data_builder.build()
+
+    # Get the sample state
+    test_director = TestDirector()
+    test_director.set_states(data_state=data)
+    return test_director.construct()
+
+
+class PropertyManagerServiceTest(unittest.TestCase):
+    def test_that_add_states_to_pmds(self):
+        self.assertTrue(len(PropertyManagerDataService.getObjectNames()) == 0)
+        states = {0: get_example_state(), 1: get_example_state()}
+        pms = PropertyManagerService()
+        pms.add_states_to_pmds(states)
+        self.assertTrue(len(PropertyManagerDataService.getObjectNames()) == 2)
+        self._remove_all_property_managers()
+
+    def test_that_removes_sans_property_managers_from_pmds(self):
+        self.assertTrue(len(PropertyManagerDataService.getObjectNames()) == 0)
+        states = {0: get_example_state(), 1: get_example_state()}
+        pms = PropertyManagerService()
+        pms.add_states_to_pmds(states)
+        pms.remove_sans_property_managers()
+        self.assertTrue(len(PropertyManagerDataService.getObjectNames()) == 0)
+        self._remove_all_property_managers()
+
+    def test_that_can_retrieve_states_from_pmds(self):
+        self.assertTrue(len(PropertyManagerDataService.getObjectNames()) == 0)
+        states = {0: get_example_state(), 1: get_example_state()}
+        pms = PropertyManagerService()
+        pms.add_states_to_pmds(states)
+        retrieved_states = pms.get_states_from_pmds()
+        self.assertTrue(len(retrieved_states) == 2)
+        self.assertTrue(isinstance(retrieved_states[0], type(states[0])))
+        self.assertTrue(len(PropertyManagerDataService.getObjectNames()) == 2)
+        self._remove_all_property_managers()
+
+    def test_that_does_not_delete_pms_which_are_not_sans(self):
+        property_manager = self._get_property_manager()
+        PropertyManagerDataService.addOrReplace("test", property_manager)
+        pms = PropertyManagerService()
+        pms.remove_sans_property_managers()
+        self.assertTrue(len(PropertyManagerDataService.getObjectNames()) == 1)
+        self._remove_all_property_managers()
+
+    def test_that_it_adds_nothing_when_empty_list_is_passed_in(self):
+        pms = PropertyManagerService()
+        number_of_elements_on_pmds_after = len(PropertyManagerDataService.getObjectNames())
+        pms.add_states_to_pmds({})
+        self.assertTrue(number_of_elements_on_pmds_after == 0)
+        self._remove_all_property_managers()
+
+    def test_that_it_returns_empty_list_if_no_states_have_been_added(self):
+        pms = PropertyManagerService()
+        states = pms.get_states_from_pmds()
+        self.assertTrue(states == [])
+        self._remove_all_property_managers()
+
+    @staticmethod
+    def _remove_all_property_managers():
+        for element in PropertyManagerDataService.getObjectNames():
+            PropertyManagerDataService.remove(element)
+
+    @staticmethod
+    def _get_property_manager():
+        alg = FakeAlgorithm()
+        alg.initialize()
+        alg.setProperty("Args", {"test": 1})
+        return alg.getProperty("Args").value
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/scripts/test/SANS/gui_logic/run_tab_presenter_test.py b/scripts/test/SANS/gui_logic/run_tab_presenter_test.py
new file mode 100644
index 0000000000000000000000000000000000000000..f85441bbe41d67b7e52433385648dbfdd374788c
--- /dev/null
+++ b/scripts/test/SANS/gui_logic/run_tab_presenter_test.py
@@ -0,0 +1,313 @@
+from __future__ import (absolute_import, division, print_function)
+
+import unittest
+import sys
+
+import mantid
+from mantid.kernel import config
+from mantid.kernel import PropertyManagerDataService
+
+from sans.gui_logic.presenter.run_tab_presenter import RunTabPresenter
+from sans.common.enums import (SANSFacility, ReductionDimensionality, SaveType, OutputMode, ISISReductionMode,
+                               RangeStepType, FitType)
+from sans.test_helper.user_file_test_helper import (create_user_file, sample_user_file)
+from sans.test_helper.mock_objects import (create_mock_view)
+from sans.test_helper.common import (remove_file, save_to_csv)
+if sys.version_info.major == 3:
+    from unittest import mock
+else:
+    import mock
+
+
+class RunTabPresenterTest(unittest.TestCase):
+    def setUp(self):
+        config.setFacility("ISIS")
+        config.setString("default.instrument", "SANS2D")
+
+    def test_that_will_load_user_file(self):
+        # Setup presenter and mock view
+        user_file_path = create_user_file(sample_user_file)
+        view, settings_diagnostic_tab, _ = create_mock_view(user_file_path)
+        presenter = RunTabPresenter(SANSFacility.ISIS)
+        presenter.set_view(view)
+
+        # Act
+        presenter.on_user_file_load()
+
+        # Assert
+        # Note that the event slices are not set in the user file
+        self.assertFalse(view.event_slices)
+        self.assertTrue(view.reduction_dimensionality is ReductionDimensionality.OneDim)
+        self.assertTrue(view.save_types[0] is SaveType.NXcanSAS)
+        self.assertTrue(view.zero_error_free)
+        self.assertTrue(view.use_optimizations)
+        self.assertTrue(view.reduction_mode is ISISReductionMode.LAB)
+        self.assertTrue(view.merge_scale == 1.)
+        self.assertTrue(view.merge_shift == 0.)
+        self.assertFalse(view.merge_scale_fit)
+        self.assertFalse(view.merge_shift_fit)
+        self.assertTrue(view.event_binning == "7000.0,500.0,60000.0")
+        self.assertTrue(view.wavelength_step_type is RangeStepType.Lin)
+        self.assertTrue(view.wavelength_min == 1.5)
+        self.assertTrue(view.wavelength_max == 12.5)
+        self.assertTrue(view.wavelength_step == 0.125)
+        self.assertTrue(view.absolute_scale == 0.074)
+        self.assertTrue(view.z_offset == 53.)
+        self.assertTrue(view.normalization_incident_monitor == 1)
+        self.assertTrue(view.normalization_interpolate)
+        self.assertTrue(view.transmission_incident_monitor == 1)
+        self.assertTrue(view.transmission_interpolate)
+        self.assertTrue(view.transmission_roi_files == "test2.xml")
+        self.assertTrue(view.transmission_mask_files == "test4.xml")
+        self.assertTrue(view.transmission_radius == 7.)
+        self.assertTrue(view.transmission_monitor == 4)
+        self.assertTrue(view.transmission_m4_shift == -70)
+        self.assertTrue(view.transmission_sample_use_fit)
+        self.assertTrue(view.transmission_sample_fit_type is FitType.Logarithmic)
+        self.assertTrue(view.transmission_sample_polynomial_order == 2)
+        self.assertTrue(view.transmission_sample_wavelength_min == 1.5)
+        self.assertTrue(view.transmission_sample_wavelength_max == 12.5)
+        self.assertTrue(view.transmission_sample_use_wavelength)
+        self.assertFalse(view.pixel_adjustment_det_1)
+        self.assertFalse(view.pixel_adjustment_det_2)
+        self.assertFalse(view.wavelength_adjustment_det_1)
+        self.assertFalse(view.wavelength_adjustment_det_2)
+        self.assertTrue(view.q_1d_min == 0.001)
+        self.assertTrue(view.q_1d_max == 0.2)
+        self.assertTrue(view.q_1d_step == 0.001)
+        self.assertTrue(view.q_xy_max == 0.05)
+        self.assertTrue(view.q_xy_step == 0.001)
+        self.assertTrue(view.q_xy_step_type == RangeStepType.Lin)
+        self.assertTrue(view.gravity_on_off)
+        self.assertTrue(view.use_q_resolution)
+        self.assertTrue(view.q_resolution_sample_a == 14.)
+        self.assertTrue(view.q_resolution_source_a == 13.)
+        self.assertTrue(view.q_resolution_delta_r == 11.)
+        self.assertTrue(view.q_resolution_collimation_length == 12.)
+        self.assertTrue(view.q_resolution_moderator_file == "moderator_rkh_file.txt")
+        self.assertFalse(view.phi_limit_use_mirror)
+        self.assertTrue(view.radius_limit_min == 12.)
+        self.assertTrue(view.radius_limit_min == 12.)
+        self.assertTrue(view.radius_limit_max == 15.)
+
+        # Assert certain function calls
+        self.assertTrue(view.get_user_file_path.call_count == 3)
+        self.assertTrue(view.get_batch_file_path.call_count == 2)  # called twice for the sub presenter updates (masking table and settings diagnostic tab)  # noqa
+        self.assertTrue(view.get_cell.call_count == 36)
+        self.assertTrue(view.get_number_of_rows.call_count == 6)
+
+        # clean up
+        remove_file(user_file_path)
+
+    def test_fails_silently_when_user_file_does_not_exist(self):
+        view, _, _ = create_mock_view("non_existent_user_file")
+
+        presenter = RunTabPresenter(SANSFacility.ISIS)
+        presenter.set_view(view)
+
+        try:
+            presenter.on_user_file_load()
+            has_raised = False
+        except:  # noqa
+            has_raised = True
+        self.assertFalse(has_raised)
+
+    def test_that_loads_batch_file_and_places_it_into_table(self):
+        # Arrange
+        content = "# MANTID_BATCH_FILE add more text here\n" \
+                  "sample_sans,1,sample_trans,2,sample_direct_beam,3," \
+                  "output_as,test_file,user_file,user_test_file\n" \
+                  "sample_sans,1,can_sans,2,output_as,test_file2\n"
+        batch_file_path = save_to_csv(content)
+        user_file_path = create_user_file(sample_user_file)
+        view, settings_diagnostic_tab, masking_table = create_mock_view(user_file_path, batch_file_path)
+        presenter = RunTabPresenter(SANSFacility.ISIS)
+        presenter.set_view(view)
+
+        # Act
+        presenter.on_batch_file_load()
+
+        # Assert
+        self.assertTrue(view.add_row.call_count == 2)
+        expected_first_row = "SampleScatter:1,SampleTransmission:2,SampleDirect:3," \
+                             "CanScatter:,CanTransmission:,CanDirect:,OutputName:test_file"
+        expected_second_row = "SampleScatter:1,SampleTransmission:,SampleDirect:," \
+                              "CanScatter:2,CanTransmission:,CanDirect:,OutputName:test_file2"
+
+        calls = [mock.call(expected_first_row), mock.call(expected_second_row)]
+        view.add_row.assert_has_calls(calls)
+
+        # Clean up
+        remove_file(batch_file_path)
+        remove_file(user_file_path)
+
+    def test_fails_silently_when_batch_file_does_not_exist(self):
+        presenter = RunTabPresenter(SANSFacility.ISIS)
+        user_file_path = create_user_file(sample_user_file)
+        view, settings_diagnostic_tab, masking_table = create_mock_view(user_file_path, "non_existent_batch_file")
+        presenter.set_view(view)
+
+        try:
+            presenter.on_batch_file_load()
+            has_raised = False
+        except:  # noqa
+            has_raised = True
+        self.assertFalse(has_raised)
+
+        # Clean up
+        remove_file(user_file_path)
+
+    def test_that_gets_states_from_view(self):
+        # Arrange
+        content = "# MANTID_BATCH_FILE add more text here\n" \
+                  "sample_sans,SANS2D00022024,sample_trans,SANS2D00022048," \
+                  "sample_direct_beam,SANS2D00022048,output_as,test_file\n" \
+                  "sample_sans,SANS2D00022024,output_as,test_file2\n"
+        batch_file_path = save_to_csv(content)
+        user_file_path = create_user_file(sample_user_file)
+        view, _, _ = create_mock_view(user_file_path, batch_file_path)
+
+        presenter = RunTabPresenter(SANSFacility.ISIS)
+        presenter.set_view(view)
+
+        presenter.on_user_file_load()
+        presenter.on_batch_file_load()
+
+        # Act
+        states = presenter.get_states()
+
+        # Assert
+        self.assertTrue(len(states) == 2)
+        for _, state in states.items():
+            try:
+                state.validate()
+                has_raised = False
+            except:  # noqa
+                has_raised = True
+            self.assertFalse(has_raised)
+
+        # Check state 0
+        state0 = states[0]
+        self.assertTrue(state0.data.sample_scatter == "SANS2D00022024")
+        self.assertTrue(state0.data.sample_transmission == "SANS2D00022048")
+        self.assertTrue(state0.data.sample_direct == "SANS2D00022048")
+        self.assertTrue(state0.data.can_scatter is None)
+        self.assertTrue(state0.data.can_transmission is None)
+        self.assertTrue(state0.data.can_direct is None)
+
+        # Check state 1
+        state1 = states[1]
+        self.assertTrue(state1.data.sample_scatter == "SANS2D00022024")
+        self.assertTrue(state1.data.sample_transmission is None)
+        self.assertTrue(state1.data.sample_direct is None)
+        self.assertTrue(state1.data.can_scatter is None)
+        self.assertTrue(state1.data.can_transmission is None)
+        self.assertTrue(state1.data.can_direct is None)
+
+        # Check some entries
+        self.assertTrue(state0.slice.start_time is None)
+        self.assertTrue(state0.slice.end_time is None)
+        self.assertTrue(state0.reduction.reduction_dimensionality is ReductionDimensionality.OneDim)
+
+        # Clean up
+        remove_file(batch_file_path)
+        remove_file(user_file_path)
+
+    def test_that_can_get_state_for_index_if_index_exists(self):
+        # Arrange
+        content = "# MANTID_BATCH_FILE add more text here\n" \
+                  "sample_sans,SANS2D00022024,sample_trans,SANS2D00022048," \
+                  "sample_direct_beam,SANS2D00022048,output_as,test_file\n" \
+                  "sample_sans,SANS2D00022024,output_as,test_file2\n"
+        batch_file_path = save_to_csv(content)
+        user_file_path = create_user_file(sample_user_file)
+        view, _, _ = create_mock_view(user_file_path, batch_file_path)
+
+        presenter = RunTabPresenter(SANSFacility.ISIS)
+        presenter.set_view(view)
+
+        presenter.on_user_file_load()
+        presenter.on_batch_file_load()
+
+        # Act
+        state = presenter.get_state_for_row(1)
+
+        # Assert
+        self.assertTrue(state.data.sample_scatter == "SANS2D00022024")
+        self.assertTrue(state.data.sample_transmission is None)
+        self.assertTrue(state.data.sample_direct is None)
+        self.assertTrue(state.data.can_scatter is None)
+        self.assertTrue(state.data.can_transmission is None)
+        self.assertTrue(state.data.can_direct is None)
+
+        # Clean up
+        remove_file(batch_file_path)
+        remove_file(user_file_path)
+
+    def test_that_returns_none_when_index_does_not_exist(self):
+        # Arrange
+        # Arrange
+        content = "# MANTID_BATCH_FILE add more text here\n" \
+                  "sample_sans,SANS2D00022024,sample_trans,SANS2D00022048," \
+                  "sample_direct_beam,SANS2D00022048,output_as,test_file\n" \
+                  "sample_sans,SANS2D00022024,output_as,test_file2\n"
+        batch_file_path = save_to_csv(content)
+        user_file_path = create_user_file(sample_user_file)
+        view, _, _ = create_mock_view(user_file_path, batch_file_path)
+
+        presenter = RunTabPresenter(SANSFacility.ISIS)
+        presenter.set_view(view)
+
+        presenter.on_user_file_load()
+        presenter.on_batch_file_load()
+
+        # Act
+        state = presenter.get_state_for_row(3)
+
+        # Assert
+        self.assertTrue(state is None)
+
+        # Clean up
+        remove_file(batch_file_path)
+        remove_file(user_file_path)
+
+    def test_that_populates_the_property_manager_data_service_when_processing_is_called(self):
+        # Arrange
+        self._clear_property_manager_data_service()
+        content = "# MANTID_BATCH_FILE add more text here\n" \
+                  "sample_sans,SANS2D00022024,sample_trans,SANS2D00022048," \
+                  "sample_direct_beam,SANS2D00022048,output_as,test_file\n" \
+                  "sample_sans,SANS2D00022024,output_as,test_file2\n"
+        batch_file_path = save_to_csv(content)
+        user_file_path = create_user_file(sample_user_file)
+        view, _, _ = create_mock_view(user_file_path, batch_file_path)
+
+        presenter = RunTabPresenter(SANSFacility.ISIS)
+        presenter.set_view(view)
+
+        # This is not the nicest of tests, but better to test this functionality than not
+        presenter.on_user_file_load()
+        presenter.on_batch_file_load()
+
+        # Act
+        presenter.on_processed_clicked()
+
+        # Assert
+        # We should have two states in the PropertyManagerDataService
+        self.assertTrue(len(PropertyManagerDataService.getObjectNames()) == 2)
+
+        # clean up
+        remove_file(sample_user_file)
+        remove_file(user_file_path)
+
+        self._clear_property_manager_data_service()
+
+    @staticmethod
+    def _clear_property_manager_data_service():
+        for element in PropertyManagerDataService.getObjectNames():
+            if PropertyManagerDataService.doesExist(element):
+                PropertyManagerDataService.remove(element)
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/scripts/test/SANS/gui_logic/settings_diagnostic_presenter_test.py b/scripts/test/SANS/gui_logic/settings_diagnostic_presenter_test.py
new file mode 100644
index 0000000000000000000000000000000000000000..74633f93ad4446db6c5f900de41a1060c3be5315
--- /dev/null
+++ b/scripts/test/SANS/gui_logic/settings_diagnostic_presenter_test.py
@@ -0,0 +1,38 @@
+from __future__ import (absolute_import, division, print_function)
+
+import unittest
+
+import mantid
+
+from sans.gui_logic.presenter.settings_diagnostic_presenter import SettingsDiagnosticPresenter
+from sans.test_helper.mock_objects import (create_run_tab_presenter_mock, FakeState, create_mock_settings_diagnostic_tab)
+
+
+class SettingsDiagnosticPresenterTest(unittest.TestCase):
+    def test_that_can_get_state_for_index(self):
+        parent_presenter = create_run_tab_presenter_mock()
+        presenter = SettingsDiagnosticPresenter(parent_presenter)
+        state = presenter.get_state(3)
+        self.assertTrue(isinstance(state, FakeState))
+
+    def test_that_updates_tree_view_when_row_selection_changes(self):
+        parent_presenter = create_run_tab_presenter_mock()
+        view = create_mock_settings_diagnostic_tab()
+        presenter = SettingsDiagnosticPresenter(parent_presenter)
+        presenter.set_view(view)
+        self.assertTrue(view.set_tree.call_count == 1)
+        presenter.on_row_changed()
+        self.assertTrue(view.set_tree.call_count == 2)
+
+    def test_that_updates_rows_when_triggered(self):
+        parent_presenter = create_run_tab_presenter_mock()
+        view = create_mock_settings_diagnostic_tab()
+        presenter = SettingsDiagnosticPresenter(parent_presenter)
+        presenter.set_view(view)
+        self.assertTrue(view.update_rows.call_count == 1)
+        presenter.on_update_rows()
+        self.assertTrue(view.update_rows.call_count == 2)
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/scripts/test/SANS/gui_logic/state_gui_model_test.py b/scripts/test/SANS/gui_logic/state_gui_model_test.py
new file mode 100644
index 0000000000000000000000000000000000000000..e2b004ee5f278b388d59ed2caa8c96cb2e24f460
--- /dev/null
+++ b/scripts/test/SANS/gui_logic/state_gui_model_test.py
@@ -0,0 +1,499 @@
+from __future__ import (absolute_import, division, print_function)
+import unittest
+
+import mantid
+
+from sans.gui_logic.models.state_gui_model import StateGuiModel
+from sans.user_file.settings_tags import (OtherId, event_binning_string_values, DetectorId, det_fit_range)
+from sans.common.enums import (ReductionDimensionality, ISISReductionMode, RangeStepType, SampleShape, SaveType,
+                               FitType)
+
+
+class StateGuiModelTest(unittest.TestCase):
+    # ==================================================================================================================
+    # ==================================================================================================================
+    # FRONT TAB
+    # ==================================================================================================================
+    # ==================================================================================================================
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Compatibility Mode
+    # ------------------------------------------------------------------------------------------------------------------
+    def test_that_default_compatibility_mode_is_false(self):
+        state_gui_model = StateGuiModel({"test": [1]})
+        self.assertFalse(state_gui_model.compatibility_mode)
+
+    def test_that_can_set_compatibility_mode(self):
+        state_gui_model = StateGuiModel({"test": [1]})
+        state_gui_model.compatibility_mode = True
+        self.assertTrue(state_gui_model.compatibility_mode)
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Save options
+    # ------------------------------------------------------------------------------------------------------------------
+    def test_that_can_zero_error_free_saving_is_default(self):
+        state_gui_model = StateGuiModel({"test": [1]})
+        self.assertTrue(state_gui_model.zero_error_free)
+
+    def test_that_can_zero_error_free_saving_can_be_changed(self):
+        state_gui_model = StateGuiModel({OtherId.save_as_zero_error_free: [True]})
+        state_gui_model.zero_error_free = False
+        self.assertFalse(state_gui_model.zero_error_free)
+
+    def test_that_default_save_type_is_NXcanSAS(self):
+        state_gui_model = StateGuiModel({"test": [1]})
+        self.assertTrue(state_gui_model.save_types == [SaveType.NXcanSAS])
+
+    def test_that_can_select_multiple_save_types(self):
+        state_gui_model = StateGuiModel({"test": [1]})
+        state_gui_model.save_types = [SaveType.RKH, SaveType.NXcanSAS]
+        self.assertTrue(state_gui_model.save_types == [SaveType.RKH, SaveType.NXcanSAS])
+
+    # ==================================================================================================================
+    # ==================================================================================================================
+    # General TAB
+    # ==================================================================================================================
+    # ==================================================================================================================
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Event slices
+    # ------------------------------------------------------------------------------------------------------------------
+    def test_that_if_no_slice_event_is_present_an_empty_string_is_returned(self):
+        state_gui_model = StateGuiModel({"test": 1})
+        self.assertTrue(state_gui_model.event_slices == "")
+
+    def test_that_slice_event_can_be_retrieved_if_it_exists(self):
+        state_gui_model = StateGuiModel({OtherId.event_slices: [event_binning_string_values(value="test")]})
+        self.assertTrue(state_gui_model.event_slices == "test")
+
+    def test_that_slice_event_can_be_updated(self):
+        state_gui_model = StateGuiModel({OtherId.event_slices: [event_binning_string_values(value="test")]})
+        state_gui_model.event_slices = "test2"
+        self.assertTrue(state_gui_model.event_slices == "test2")
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Reduction dimensionality
+    # ------------------------------------------------------------------------------------------------------------------
+    def test_that_is_1D_reduction_by_default(self):
+        state_gui_model = StateGuiModel({"test": [1]})
+        self.assertTrue(state_gui_model.reduction_dimensionality is ReductionDimensionality.OneDim)
+
+    def test_that_is_set_to_2D_reduction(self):
+        state_gui_model = StateGuiModel({"test": [1]})
+        state_gui_model.reduction_dimensionality = ReductionDimensionality.TwoDim
+        self.assertTrue(state_gui_model.reduction_dimensionality is ReductionDimensionality.TwoDim)
+
+    def test_that_raises_when_not_setting_with_reduction_dim_enum(self):
+        def red_dim_wrapper():
+            state_gui_model = StateGuiModel({"test": [1]})
+            state_gui_model.reduction_dimensionality = "string"
+        self.assertRaises(ValueError, red_dim_wrapper)
+
+    def test_that_can_update_reduction_dimensionality(self):
+        state_gui_model = StateGuiModel({OtherId.reduction_dimensionality: [ReductionDimensionality.OneDim]})
+        self.assertTrue(state_gui_model.reduction_dimensionality is ReductionDimensionality.OneDim)
+        state_gui_model.reduction_dimensionality = ReductionDimensionality.TwoDim
+        self.assertTrue(state_gui_model.reduction_dimensionality is ReductionDimensionality.TwoDim)
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Event binning for compatibility mode
+    # ------------------------------------------------------------------------------------------------------------------
+    def test_that_event_binning_default_settings_are_emtpy(self):
+        state_gui_model = StateGuiModel({"test": [1]})
+        self.assertTrue(state_gui_model.event_binning == "")
+
+    def test_that_event_binning_can_be_set(self):
+        state_gui_model = StateGuiModel({"test": [1]})
+        state_gui_model.event_binning = "1,-1,10"
+        self.assertTrue(state_gui_model.event_binning == "1,-1,10")
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Reduction mode
+    # ------------------------------------------------------------------------------------------------------------------
+    def test_that_is_set_to_lab_by_default(self):
+        state_gui_model = StateGuiModel({"test": [1]})
+        self.assertTrue(state_gui_model.reduction_mode is ISISReductionMode.LAB)
+
+    def test_that_can_be_set_to_something_else(self):
+        state_gui_model = StateGuiModel({"test": [1]})
+        state_gui_model.reduction_mode = ISISReductionMode.Merged
+        self.assertTrue(state_gui_model.reduction_mode is ISISReductionMode.Merged)
+
+    def test_that_raises_when_setting_with_wrong_input(self):
+        def red_mode_wrapper():
+            state_gui_model = StateGuiModel({"test": [1]})
+            state_gui_model.reduction_mode = "string"
+        self.assertRaises(ValueError, red_mode_wrapper)
+
+    def test_that_can_update_reduction_mode(self):
+        state_gui_model = StateGuiModel({DetectorId.reduction_mode: [ISISReductionMode.HAB]})
+        self.assertTrue(state_gui_model.reduction_mode is ISISReductionMode.HAB)
+        state_gui_model.reduction_mode = ISISReductionMode.All
+        self.assertTrue(state_gui_model.reduction_mode is ISISReductionMode.All)
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Reduction dimensionality
+    # ------------------------------------------------------------------------------------------------------------------
+    def test_that_defaults_for_merge_are_empty_and_false(self):
+        state_gui_model = StateGuiModel({"test": [1]})
+        self.assertTrue(state_gui_model.merge_scale == "")
+        self.assertTrue(state_gui_model.merge_shift == "")
+        self.assertFalse(state_gui_model.merge_scale_fit)
+        self.assertFalse(state_gui_model.merge_shift_fit)
+        self.assertTrue(state_gui_model.merge_q_range_start == "")
+        self.assertTrue(state_gui_model.merge_q_range_stop == "")
+
+    def test_that_can_set_and_reset_merged_settings(self):
+        state_gui_model = StateGuiModel({DetectorId.shift_fit: [det_fit_range(start=1., stop=2., use_fit=True)],
+                                         DetectorId.rescale_fit: [det_fit_range(start=1.4, stop=7., use_fit=False)],
+                                         DetectorId.rescale: [12.],
+                                         DetectorId.shift: [234.]})
+        self.assertTrue(state_gui_model.merge_scale == 12.)
+        self.assertTrue(state_gui_model.merge_shift == 234.)
+        self.assertFalse(state_gui_model.merge_scale_fit)
+        self.assertTrue(state_gui_model.merge_shift_fit)
+        self.assertTrue(state_gui_model.merge_q_range_start == 1.)
+        self.assertTrue(state_gui_model.merge_q_range_stop == 7.)
+
+        state_gui_model.merge_scale = 12.3
+        state_gui_model.merge_shift = 3.
+        state_gui_model.merge_scale_fit = True
+        state_gui_model.merge_shift_fit = False
+        state_gui_model.merge_q_range_start = 2.
+        state_gui_model.merge_q_range_stop = 8.
+
+        self.assertTrue(state_gui_model.merge_scale == 12.3)
+        self.assertTrue(state_gui_model.merge_shift == 3.)
+        self.assertTrue(state_gui_model.merge_scale_fit)
+        self.assertFalse(state_gui_model.merge_shift_fit)
+        self.assertTrue(state_gui_model.merge_q_range_start == 2.)
+        self.assertTrue(state_gui_model.merge_q_range_stop == 8.)
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Wavelength
+    # ------------------------------------------------------------------------------------------------------------------
+    def test_that_default_wavelength_settings_are_empty(self):
+        state_gui_model = StateGuiModel({"test": [1]})
+        self.assertTrue(not state_gui_model.wavelength_min)
+        self.assertTrue(not state_gui_model.wavelength_max)
+        self.assertTrue(not state_gui_model.wavelength_step)
+
+    def test_that_default_wavelength_step_type_is_linear(self):
+        state_gui_model = StateGuiModel({"test": [1]})
+        self.assertTrue(state_gui_model.wavelength_step_type is RangeStepType.Lin)
+
+    def test_that_can_set_wavelength(self):
+        state_gui_model = StateGuiModel({"test": [1]})
+        state_gui_model.wavelength_min = 1.
+        state_gui_model.wavelength_max = 2.
+        state_gui_model.wavelength_step = .5
+        state_gui_model.wavelength_step_type = RangeStepType.Lin
+        state_gui_model.wavelength_step_type = RangeStepType.Log
+        self.assertTrue(state_gui_model.wavelength_min == 1.)
+        self.assertTrue(state_gui_model.wavelength_max == 2.)
+        self.assertTrue(state_gui_model.wavelength_step == .5)
+        self.assertTrue(state_gui_model.wavelength_step_type is RangeStepType.Log)
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Scale
+    # ------------------------------------------------------------------------------------------------------------------
+    def test_that_absolute_scale_has_an_empty_default_value(self):
+        state_gui_model = StateGuiModel({"test": [1]})
+        self.assertTrue(not state_gui_model.absolute_scale)
+
+    def test_that_can_set_absolute_scale(self):
+        state_gui_model = StateGuiModel({"test": [1]})
+        state_gui_model.absolute_scale = .5
+        self.assertTrue(state_gui_model.absolute_scale == .5)
+
+    def test_that_default_extents_are_empty(self):
+        state_gui_model = StateGuiModel({"test": [1]})
+        self.assertTrue(not state_gui_model.sample_width)
+        self.assertTrue(not state_gui_model.sample_height)
+        self.assertTrue(not state_gui_model.sample_thickness)
+        self.assertTrue(not state_gui_model.z_offset)
+
+    def test_that_default_sample_shape_is_cylinder_axis_up(self):
+        state_gui_model = StateGuiModel({"test": [1]})
+        self.assertTrue(state_gui_model.sample_shape is None)
+
+    def test_that_can_set_the_sample_geometry(self):
+        state_gui_model = StateGuiModel({"test": [1]})
+        state_gui_model.sample_width = 1.2
+        state_gui_model.sample_height = 1.6
+        state_gui_model.sample_thickness = 1.8
+        state_gui_model.z_offset = 1.78
+        state_gui_model.sample_shape = SampleShape.Cuboid
+        self.assertTrue(state_gui_model.sample_width == 1.2)
+        self.assertTrue(state_gui_model.sample_height == 1.6)
+        self.assertTrue(state_gui_model.sample_thickness == 1.8)
+        self.assertTrue(state_gui_model.z_offset == 1.78)
+        self.assertTrue(state_gui_model.sample_shape is SampleShape.Cuboid)
+
+    # ==================================================================================================================
+    # ==================================================================================================================
+    # ADJUSTMENT TAB
+    # ==================================================================================================================
+    # ==================================================================================================================
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Normalize to monitor
+    # ------------------------------------------------------------------------------------------------------------------
+    def test_that_normalize_to_monitor_defaults_are_empty_for_monitor_and_false_for_interpolating_rebin(self):
+        state_gui_model = StateGuiModel({"test": [1]})
+        self.assertTrue(state_gui_model.normalization_incident_monitor == "")
+        self.assertFalse(state_gui_model.normalization_interpolate)
+
+    def test_that_can_set_normalize_to_monitor(self):
+        state_gui_model = StateGuiModel({"test": [1]})
+        state_gui_model.normalization_incident_monitor = 2
+        state_gui_model.normalization_interpolate = True
+        self.assertTrue(state_gui_model.normalization_incident_monitor == 2)
+        self.assertTrue(state_gui_model.normalization_interpolate)
+        # Reassign
+        state_gui_model.normalization_incident_monitor = 3
+        self.assertTrue(state_gui_model.normalization_incident_monitor == 3)
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Transmission
+    # ------------------------------------------------------------------------------------------------------------------
+    def test_that_transmission_monitor_defaults_are_empty_and_false_for_interpolating_rebin(self):
+        state_gui_model = StateGuiModel({"test": [1]})
+        self.assertTrue(state_gui_model.transmission_incident_monitor == "")
+        self.assertFalse(state_gui_model.transmission_interpolate)
+
+    def test_that_can_set_transmission_monitor(self):
+        state_gui_model = StateGuiModel({"test": [1]})
+        state_gui_model.transmission_incident_monitor = 2
+        state_gui_model.transmission_interpolate = True
+        self.assertTrue(state_gui_model.transmission_incident_monitor == 2)
+        self.assertTrue(state_gui_model.transmission_interpolate)
+        # # Reassign
+        state_gui_model.transmission_incident_monitor = 3
+        self.assertTrue(state_gui_model.transmission_incident_monitor == 3)
+
+    def test_that_can_set_normalization_and_transmission_monitor_and_rebin_type_settings(self):
+        pass
+
+    def test_that_the_default_transmission_roi_and_mask_files_and_radius_are_empty(self):
+        state_gui_model = StateGuiModel({"test": [1]})
+        self.assertTrue(state_gui_model.transmission_roi_files == "")
+        self.assertTrue(state_gui_model.transmission_mask_files == "")
+        self.assertTrue(state_gui_model.transmission_radius == "")
+
+    def test_that_can_set_transmission_roi_mask_and_radius(self):
+        state_gui_model = StateGuiModel({"test": [1]})
+        state_gui_model.transmission_roi_files = "roi.xml"
+        state_gui_model.transmission_mask_files = "mask.xml"
+        state_gui_model.transmission_radius = 8.
+        self.assertTrue(state_gui_model.transmission_roi_files == "roi.xml")
+        self.assertTrue(state_gui_model.transmission_mask_files == "mask.xml")
+        self.assertTrue(state_gui_model.transmission_radius == 8)
+
+    def test_that_default_transmission_monitor_is_3(self):
+        state_gui_model = StateGuiModel({"test": [1]})
+        self.assertTrue(state_gui_model.transmission_monitor == 3)
+
+    def test_that_transmission_monitor_can_be_set(self):
+        state_gui_model = StateGuiModel({"test": [1]})
+        state_gui_model.transmission_monitor = 4
+        self.assertTrue(state_gui_model.transmission_monitor == 4)
+
+    def test_that_transmission_m4_shift_default_is_empty(self):
+        state_gui_model = StateGuiModel({"test": [1]})
+        self.assertTrue(state_gui_model.transmission_m4_shift == "")
+
+    def test_that_transmission_m4_shift_can_be_set(self):
+        state_gui_model = StateGuiModel({"test": [1]})
+        state_gui_model.transmission_m4_shift = 234
+        self.assertTrue(state_gui_model.transmission_m4_shift == 234)
+
+    def test_that_default_for_adjustment_files_are_empty(self):
+        state_gui_model = StateGuiModel({"test": [1]})
+        self.assertTrue(state_gui_model.wavelength_adjustment_det_1 == "")
+        self.assertTrue(state_gui_model.wavelength_adjustment_det_2 == "")
+        self.assertTrue(state_gui_model.pixel_adjustment_det_1 == "")
+        self.assertTrue(state_gui_model.pixel_adjustment_det_2 == "")
+
+    def test_that_adjustment_files_can_be_set(self):
+        state_gui_model = StateGuiModel({"test": [1]})
+        state_gui_model.wavelength_adjustment_det_1 = "wav1.txt"
+        state_gui_model.wavelength_adjustment_det_2 = "wav2.txt"
+        state_gui_model.pixel_adjustment_det_1 = "pix1.txt"
+        state_gui_model.pixel_adjustment_det_2 = "pix2.txt"
+        self.assertTrue(state_gui_model.wavelength_adjustment_det_1 == "wav1.txt")
+        self.assertTrue(state_gui_model.wavelength_adjustment_det_2 == "wav2.txt")
+        self.assertTrue(state_gui_model.pixel_adjustment_det_1 == "pix1.txt")
+        self.assertTrue(state_gui_model.pixel_adjustment_det_2 == "pix2.txt")
+
+    def test_transmission_fit_defaults(self):
+        state_gui_model = StateGuiModel({"test": [1]})
+        self.assertTrue(state_gui_model.transmission_sample_fit_type is FitType.NoFit)
+        self.assertTrue(state_gui_model.transmission_can_fit_type is FitType.NoFit)
+        self.assertTrue(state_gui_model.transmission_sample_polynomial_order == 2)
+        self.assertTrue(state_gui_model.transmission_can_polynomial_order == 2)
+
+    def test_that_can_set_transmission_fit_options(self):
+        state_gui_model = StateGuiModel({"test": [1]})
+        state_gui_model.transmission_sample_fit_type = FitType.Logarithmic
+        state_gui_model.transmission_can_fit_type = FitType.Linear
+        state_gui_model.transmission_sample_polynomial_order = 2
+        state_gui_model.transmission_can_polynomial_order = 2
+        self.assertTrue(state_gui_model.transmission_sample_fit_type is FitType.Logarithmic)
+        self.assertTrue(state_gui_model.transmission_can_fit_type is FitType.Linear)
+        self.assertTrue(state_gui_model.transmission_sample_polynomial_order == 2)
+        self.assertTrue(state_gui_model.transmission_can_polynomial_order == 2)
+
+    def test_that_transmission_fit_wavelength_defaults_to_empty(self):
+        state_gui_model = StateGuiModel({"test": [1]})
+        self.assertTrue(state_gui_model.transmission_sample_wavelength_min == "")
+        self.assertTrue(state_gui_model.transmission_sample_wavelength_max == "")
+        self.assertTrue(state_gui_model.transmission_can_wavelength_min == "")
+        self.assertTrue(state_gui_model.transmission_can_wavelength_max == "")
+
+    def test_that_transmission_fit_wavelength_can_be_set(self):
+        state_gui_model = StateGuiModel({"test": [1]})
+        state_gui_model.transmission_sample_wavelength_min = 1.3
+        state_gui_model.transmission_sample_wavelength_max = 10.3
+        state_gui_model.transmission_can_wavelength_min = 1.3
+        state_gui_model.transmission_can_wavelength_max = 10.3
+
+        self.assertTrue(state_gui_model.transmission_sample_wavelength_min == 1.3)
+        self.assertTrue(state_gui_model.transmission_sample_wavelength_max == 10.3)
+        self.assertTrue(state_gui_model.transmission_can_wavelength_min == 1.3)
+        self.assertTrue(state_gui_model.transmission_can_wavelength_max == 10.3)
+
+    # ==================================================================================================================
+    # ==================================================================================================================
+    # Q TAB
+    # ==================================================================================================================
+    # ==================================================================================================================
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Q limits
+    # ------------------------------------------------------------------------------------------------------------------
+    def test_that_q_limits_default_to_empty(self):
+        state_gui_model = StateGuiModel({"test": [1]})
+        self.assertTrue(state_gui_model.q_1d_min == "")
+        self.assertTrue(state_gui_model.q_1d_max == "")
+        self.assertTrue(state_gui_model.q_1d_rebin_string == "")
+
+        self.assertTrue(state_gui_model.q_xy_max == "")
+        self.assertTrue(state_gui_model.q_xy_step == "")
+        self.assertTrue(state_gui_model.q_xy_step_type is None)
+
+    def test_that_can_set_the_q_limits(self):
+        state_gui_model = StateGuiModel({"test": [1]})
+        state_gui_model.q_1d_min = 11.2
+        state_gui_model.q_1d_max = 123.3
+        state_gui_model.q_1d_rebin_string = "test"
+        state_gui_model.q_xy_max = 1.
+        state_gui_model.q_xy_step = 122.
+        state_gui_model.q_xy_step_type = RangeStepType.Log
+
+        self.assertTrue(state_gui_model.q_1d_min == 11.2)
+        self.assertTrue(state_gui_model.q_1d_max == 123.3)
+        self.assertTrue(state_gui_model.q_1d_rebin_string == "test")
+        self.assertTrue(state_gui_model.q_xy_max == 1.)
+        self.assertTrue(state_gui_model.q_xy_step == 122.)
+        self.assertTrue(state_gui_model.q_xy_step_type is RangeStepType.Log)
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Gravity
+    # ------------------------------------------------------------------------------------------------------------------
+    def test_that_gravity_extra_length_empty_by_default_and_usage_true_by_default(self):
+        state_gui_model = StateGuiModel({"test": [1]})
+        self.assertTrue(state_gui_model.gravity_on_off)
+        self.assertTrue(state_gui_model.gravity_extra_length == "")
+
+    def test_that_can_set_gravity(self):
+        state_gui_model = StateGuiModel({"test": [1]})
+        state_gui_model.gravity_on_off = False
+        state_gui_model.gravity_extra_length = 1.
+        self.assertFalse(state_gui_model.gravity_on_off)
+        self.assertTrue(state_gui_model.gravity_extra_length == 1.)
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Q resolution
+    # ------------------------------------------------------------------------------------------------------------------
+    def test_that_q_resolution_settings_show_empty_defaults(self):
+        state_gui_model = StateGuiModel({"test": [1]})
+        self.assertFalse(state_gui_model.use_q_resolution)
+        self.assertTrue(state_gui_model.q_resolution_source_a == "")
+        self.assertTrue(state_gui_model.q_resolution_sample_a == "")
+        self.assertTrue(state_gui_model.q_resolution_source_h == "")
+        self.assertTrue(state_gui_model.q_resolution_sample_h == "")
+        self.assertTrue(state_gui_model.q_resolution_source_w == "")
+        self.assertTrue(state_gui_model.q_resolution_sample_w == "")
+        self.assertTrue(state_gui_model.q_resolution_collimation_length == "")
+        self.assertTrue(state_gui_model.q_resolution_delta_r == "")
+        self.assertTrue(state_gui_model.q_resolution_moderator_file == "")
+
+    def test_that_q_resolution_can_be_set_correctly(self):
+        state_gui_model = StateGuiModel({"test": [1]})
+        state_gui_model.use_q_resolution = True
+        state_gui_model.q_resolution_source_a = 1.5
+        state_gui_model.q_resolution_sample_a = 2.5
+        state_gui_model.q_resolution_source_h = 1.5
+        state_gui_model.q_resolution_sample_h = 2.5
+        state_gui_model.q_resolution_source_w = 1.5
+        state_gui_model.q_resolution_sample_w = 2.5
+        state_gui_model.q_resolution_collimation_length = 1.7
+        state_gui_model.q_resolution_delta_r = 12.4
+        state_gui_model.q_resolution_moderator_file = "test.txt"
+
+        self.assertTrue(state_gui_model.use_q_resolution)
+        self.assertTrue(state_gui_model.q_resolution_source_a == 1.5)
+        self.assertTrue(state_gui_model.q_resolution_sample_a == 2.5)
+        self.assertTrue(state_gui_model.q_resolution_source_h == 1.5)
+        self.assertTrue(state_gui_model.q_resolution_sample_h == 2.5)
+        self.assertTrue(state_gui_model.q_resolution_source_w == 1.5)
+        self.assertTrue(state_gui_model.q_resolution_sample_w == 2.5)
+        self.assertTrue(state_gui_model.q_resolution_collimation_length == 1.7)
+        self.assertTrue(state_gui_model.q_resolution_delta_r == 12.4)
+        self.assertTrue(state_gui_model.q_resolution_moderator_file == "test.txt")
+
+    # ==================================================================================================================
+    # ==================================================================================================================
+    # MASK TAB
+    # ==================================================================================================================
+    # ==================================================================================================================
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Phi mask
+    # ------------------------------------------------------------------------------------------------------------------
+    def test_that_phi_mask_defaults_to_empty_and_false_for_use_mirror(self):
+        state_gui_model = StateGuiModel({"test": [1]})
+        self.assertTrue(state_gui_model.phi_limit_min == "")
+        self.assertTrue(state_gui_model.phi_limit_max == "")
+        self.assertFalse(state_gui_model.phi_limit_use_mirror)
+
+    def test_that_phi_mask_can_be_set(self):
+        state_gui_model = StateGuiModel({"test": [1]})
+        state_gui_model.phi_limit_min = 12.
+        state_gui_model.phi_limit_max = 13.
+        state_gui_model.phi_limit_use_mirror = True
+        self.assertTrue(state_gui_model.phi_limit_min == 12.)
+        self.assertTrue(state_gui_model.phi_limit_max == 13.)
+        self.assertTrue(state_gui_model.phi_limit_use_mirror)
+
+    # ------------------------------------------------------------------------------------------------------------------
+    # Radius mask
+    # ------------------------------------------------------------------------------------------------------------------
+    def test_that_radius_mask_defaults_to_empty(self):
+        state_gui_model = StateGuiModel({"test": [1]})
+        self.assertTrue(state_gui_model.radius_limit_min == "")
+        self.assertTrue(state_gui_model.radius_limit_max == "")
+
+    def test_that_radius_mask_can_be_set(self):
+        state_gui_model = StateGuiModel({"test": [1]})
+        state_gui_model.radius_limit_min = 12.
+        state_gui_model.radius_limit_max = 13.
+        self.assertTrue(state_gui_model.radius_limit_min == 12.)
+        self.assertTrue(state_gui_model.radius_limit_max == 13.)
+
+
+if __name__ == '__main__':
+    unittest.main()
+
+
diff --git a/scripts/test/SANS/gui_logic/table_model_test.py b/scripts/test/SANS/gui_logic/table_model_test.py
new file mode 100644
index 0000000000000000000000000000000000000000..11569c6bb83ccbbfba2beed9e8038dfa86f93fdd
--- /dev/null
+++ b/scripts/test/SANS/gui_logic/table_model_test.py
@@ -0,0 +1,73 @@
+from __future__ import (absolute_import, division, print_function)
+
+import unittest
+
+import mantid
+
+from sans.gui_logic.models.table_model import (TableModel, TableIndexModel)
+
+
+class TableModelTest(unittest.TestCase):
+    def test_user_file_can_be_set(self):
+        self._do_test_file_setting(self._user_file_wrapper, "user_file")
+
+    def test_batch_file_can_be_set(self):
+        self._do_test_file_setting(self._batch_file_wrapper, "batch_file")
+
+    def test_that_raises_if_table_index_does_not_exist(self):
+        table_model = TableModel()
+        table_index_model = TableIndexModel(0, "", "", "",
+                                            "", "", "")
+        table_model.add_table_entry(0, table_index_model)
+        self.assertRaises(ValueError, table_model.get_table_entry, 1)
+
+    def test_that_can_get_table_index_model_for_valid_index(self):
+        table_model = TableModel()
+        table_index_model = TableIndexModel(0, "", "", "",
+                                            "", "", "")
+        table_model.add_table_entry(0, table_index_model)
+        returned_model = table_model.get_table_entry(0)
+        self.assertTrue(returned_model.index == 0)
+
+    def test_that_can_set_the_options_column_model(self):
+        table_index_model = TableIndexModel(0, "", "", "",
+                                            "", "", "", "", "WavelengthMin=1, WavelengthMax=3, NotRegister2=1")
+        options_column_model = table_index_model.options_column_model
+        options = options_column_model.get_options()
+        self.assertTrue(len(options) == 2)
+        self.assertTrue(options["WavelengthMin"] == 1.)
+        self.assertTrue(options["WavelengthMax"] == 3.)
+
+    def test_that_raises_for_missing_equal(self):
+        args = [0, "", "", "", "", "", "", "", "WavelengthMin=1, WavelengthMax=3, NotRegister2"]
+        self.assertRaises(ValueError,  TableIndexModel, *args)
+
+    def _do_test_file_setting(self, func, prop):
+        # Test that can set to empty string
+        table_model = TableModel()
+        try:
+            setattr(table_model, prop, "")
+            has_raised = False
+        except:
+            has_raised = True
+        self.assertFalse(has_raised)
+
+        # Test raises for non-existent file path
+        self.assertRaises(ValueError, func, "/home/test")
+
+        # Test that can be set to valid value
+        setattr(table_model, prop, __file__)
+        self.assertTrue(getattr(table_model, prop) == __file__)
+
+    @staticmethod
+    def _batch_file_wrapper(value):
+        table_model = TableModel()
+        table_model.batch_file = value
+
+    @staticmethod
+    def _user_file_wrapper(value):
+        table_model = TableModel()
+        table_model.user_file = value
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/scripts/test/SANS/state/calculate_transmission_test.py b/scripts/test/SANS/state/calculate_transmission_test.py
index 7b39efb37f17f51fd14c816460b03e7800e2a248..fdaa2353d9ca575cb5c3e80139e43e6d062b0483 100644
--- a/scripts/test/SANS/state/calculate_transmission_test.py
+++ b/scripts/test/SANS/state/calculate_transmission_test.py
@@ -175,7 +175,7 @@ class StateCalculateTransmissionTest(unittest.TestCase):
                                                    "background_TOF_monitor_stop": {"1": 2., "2": 2.}})
 
     def test_that_polynomial_order_can_only_be_set_with_polynomial_setting(self):
-        self.check_bad_and_good_values(bad_fit={"fit_type": FitType.Log, "polynomial_order": 4},
+        self.check_bad_and_good_values(bad_fit={"fit_type": FitType.Polynomial, "polynomial_order": 0},
                                        good_fit={"fit_type": FitType.Polynomial,  "polynomial_order": 4})
 
     def test_that_raises_for_inconsistent_wavelength_in_fit(self):
diff --git a/scripts/test/SANS/state/mask_test.py b/scripts/test/SANS/state/mask_test.py
index 112079b7b6219dd248c4484dd04dc9af38c43553..f6ab89fe9330e9c9dc15518cf323512925d1acac 100644
--- a/scripts/test/SANS/state/mask_test.py
+++ b/scripts/test/SANS/state/mask_test.py
@@ -2,7 +2,7 @@ from __future__ import (absolute_import, division, print_function)
 import unittest
 import mantid
 
-from sans.state.mask import (StateMask, get_mask_builder)
+from sans.state.mask import (StateMaskSANS2D, get_mask_builder)
 from sans.state.data import get_data_builder
 from sans.common.enums import (SANSFacility, SANSInstrument, DetectorType)
 from state_test_helper import (assert_validate_error, assert_raises_nothing)
@@ -27,7 +27,7 @@ class StateMaskTest(unittest.TestCase):
 
     @staticmethod
     def _get_mask_state(general_entries, detector_entries):
-        state = StateMask()
+        state = StateMaskSANS2D()
         # Setup the general mask settings
         mask_settings = {"radius_min": 12., "radius_max": 17.,
                          "bin_mask_general_start": [1., 2., 3.], "bin_mask_general_stop": [2., 3., 4.],
diff --git a/scripts/test/SANS/state/move_test.py b/scripts/test/SANS/state/move_test.py
index 9a9bbd4e9577ff160afb44a5e3606713a4049496..0bd63eb101b5deedb58d87292f2a571ffbc3626b 100644
--- a/scripts/test/SANS/state/move_test.py
+++ b/scripts/test/SANS/state/move_test.py
@@ -2,8 +2,8 @@ from __future__ import (absolute_import, division, print_function)
 import unittest
 import mantid
 
-from sans.state.move import (StateMoveLOQ, StateMoveSANS2D, StateMoveLARMOR, StateMove, StateMoveDetector,
-                             get_move_builder)
+from sans.state.move import (StateMoveLOQ, StateMoveSANS2D, StateMoveLARMOR, StateMoveZOOM, StateMove,
+                             StateMoveDetector, get_move_builder)
 from sans.state.data import get_data_builder
 from sans.common.enums import (CanonicalCoordinates, SANSFacility, DetectorType)
 from state_test_helper import assert_validate_error, assert_raises_nothing
@@ -97,6 +97,17 @@ class StateMoveWorkspaceLARMORTest(unittest.TestCase):
         self.assertTrue(state.monitor_names == {})
 
 
+class StateMoveWorkspaceZOOMTest(unittest.TestCase):
+    def test_that_is_sans_state_data_object(self):
+        state = StateMoveZOOM()
+        self.assertTrue(isinstance(state, StateMove))
+
+    def test_that_can_set_and_get_values(self):
+        state = StateMoveZOOM()
+        self.assertTrue(len(state.detectors) == 1)
+        self.assertTrue(state.monitor_names == {})
+
+
 # ----------------------------------------------------------------------------------------------------------------------
 # Builder
 # ----------------------------------------------------------------------------------------------------------------------
@@ -169,6 +180,10 @@ class StateMoveBuilderTest(unittest.TestCase):
         self.assertTrue(state.monitor_names[str(5)] == "monitor5")
         self.assertTrue(len(state.monitor_names) == 5)
 
+    def test_that_state_for_zoom_can_be_built(self):
+        # TODO when data becomes available
+        pass
+
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/scripts/test/SANS/state/state_test.py b/scripts/test/SANS/state/state_test.py
index 6a8a730a73cead06daa0433b90eb9d5ed5aa44de..2337e31ccc37e2d0c583933025a94ebb7cb6c8e1 100644
--- a/scripts/test/SANS/state/state_test.py
+++ b/scripts/test/SANS/state/state_test.py
@@ -18,7 +18,8 @@ from sans.state.adjustment import (StateAdjustment)
 from sans.state.convert_to_q import (StateConvertToQ)
 
 from state_test_helper import assert_validate_error, assert_raises_nothing
-from sans.common.enums import SANSInstrument
+from sans.common.enums import (SANSInstrument, SANSFacility)
+
 
 # ----------------------------------------------------------------------------------------------------------------------
 #  State
@@ -106,6 +107,7 @@ class StateTest(unittest.TestCase):
                            "save": MockStateSave(), "scale": MockStateScale(), "adjustment": MockStateAdjustment(),
                            "convert_to_q": MockStateConvertToQ()}
         default_entries["data"].instrument = SANSInstrument.LARMOR
+        default_entries["data"].facility = SANSFacility.ISIS
 
         for key, value in list(default_entries.items()):
             if key in entries:
diff --git a/scripts/test/SANS/user_file/state_director_test.py b/scripts/test/SANS/user_file/state_director_test.py
index 8a783e569332226cc0468b39ea769c6c09e82b7c..1203e8f2d04bfe508cd7ff3f0b873676eb9d4c71 100644
--- a/scripts/test/SANS/user_file/state_director_test.py
+++ b/scripts/test/SANS/user_file/state_director_test.py
@@ -6,11 +6,11 @@ import mantid
 
 from sans.user_file.state_director import StateDirectorISIS
 from sans.common.enums import (SANSFacility, ISISReductionMode, RangeStepType, RebinType, DataType, FitType,
-                               DetectorType)
+                               DetectorType, SampleShape)
 from sans.common.configurations import Configurations
 from sans.state.data import get_data_builder
 
-from user_file_test_helper import create_user_file, sample_user_file
+from sans.test_helper.user_file_test_helper import create_user_file, sample_user_file
 
 
 # -----------------------------------------------------------------
@@ -139,11 +139,11 @@ class UserFileStateDirectorISISTest(unittest.TestCase):
         self.assertTrue(calculate_transmission.background_TOF_monitor_stop["2"] == 98000)
         self.assertTrue(calculate_transmission.background_TOF_roi_start == 123)
         self.assertTrue(calculate_transmission.background_TOF_roi_stop == 466)
-        self.assertTrue(calculate_transmission.fit[DataType.to_string(DataType.Sample)].fit_type is FitType.Log)
+        self.assertTrue(calculate_transmission.fit[DataType.to_string(DataType.Sample)].fit_type is FitType.Logarithmic)
         self.assertTrue(calculate_transmission.fit[DataType.to_string(DataType.Sample)].wavelength_low == 1.5)
         self.assertTrue(calculate_transmission.fit[DataType.to_string(DataType.Sample)].wavelength_high == 12.5)
         self.assertTrue(calculate_transmission.fit[DataType.to_string(DataType.Sample)].polynomial_order == 0)
-        self.assertTrue(calculate_transmission.fit[DataType.to_string(DataType.Can)].fit_type is FitType.Log)
+        self.assertTrue(calculate_transmission.fit[DataType.to_string(DataType.Can)].fit_type is FitType.Logarithmic)
         self.assertTrue(calculate_transmission.fit[DataType.to_string(DataType.Can)].wavelength_low == 1.5)
         self.assertTrue(calculate_transmission.fit[DataType.to_string(DataType.Can)].wavelength_high == 12.5)
         self.assertTrue(calculate_transmission.fit[DataType.to_string(DataType.Can)].polynomial_order == 0)
@@ -202,14 +202,24 @@ class UserFileStateDirectorISISTest(unittest.TestCase):
         user_file_path = create_user_file(sample_user_file)
         director.set_user_file(user_file_path)
 
-        # Act
+        # Set additional items
         director.set_mask_builder_radius_min(0.001298)
         director.set_mask_builder_radius_max(0.003298)
+        director.set_scale_builder_width(1.)
+        director.set_scale_builder_height(1.5)
+        director.set_scale_builder_thickness(12.)
+        director.set_scale_builder_shape(SampleShape.Cuboid)
+
+        # Act
         state = director.construct()
 
         # Assert
         self.assertTrue(state.mask.radius_min == 0.001298)
         self.assertTrue(state.mask.radius_max == 0.003298)
+        self.assertTrue(state.scale.width == 1.)
+        self.assertTrue(state.scale.height == 1.5)
+        self.assertTrue(state.scale.thickness == 12.)
+        self.assertTrue(state.scale.shape is SampleShape.Cuboid)
 
         # clean up
         if os.path.exists(user_file_path):
@@ -219,4 +229,4 @@ if __name__ == "__main__":
     unittest.main()
 
 if __name__ == "__main__":
-    unittest.main()
\ No newline at end of file
+    unittest.main()
diff --git a/scripts/test/SANS/user_file/user_file_parser_test.py b/scripts/test/SANS/user_file/user_file_parser_test.py
index 624784336e6c86144429396117447c3523adad08..de90ac3f684655d4b31c97d2fba98851ed91ca3e 100644
--- a/scripts/test/SANS/user_file/user_file_parser_test.py
+++ b/scripts/test/SANS/user_file/user_file_parser_test.py
@@ -26,10 +26,7 @@ def assert_valid_result(result, expected, assert_true):
     for key in keys_result:
         assert_true(key in keys_expected)
         if result[key] != expected[key]:
-            print("=================================")
-            print(result[key])
-            print(expected[key])
-        assert_true(result[key] == expected[key])
+            assert_true(result[key] == expected[key])
 
 
 def assert_valid_parse(parser, to_parse, expected, assert_true):
@@ -663,12 +660,12 @@ class FitParserTest(unittest.TestCase):
                           "FIT/TRANS/Straight 123 3556": {FitId.general: fit_general(start=123, stop=3556,
                                                           fit_type=FitType.Linear, data_type=None, polynomial_order=0)},
                           "FIT/ tranS/LoG 123  3556.6 ": {FitId.general: fit_general(start=123, stop=3556.6,
-                                                          fit_type=FitType.Log, data_type=None, polynomial_order=0)},
+                                                          fit_type=FitType.Logarithmic, data_type=None, polynomial_order=0)},  # noqa
                           "FIT/TRANS/  YlOG 123   3556": {FitId.general: fit_general(start=123, stop=3556,
-                                                          fit_type=FitType.Log, data_type=None, polynomial_order=0)},
+                                                          fit_type=FitType.Logarithmic, data_type=None, polynomial_order=0)},  # noqa
                           "FIT/Trans/Lin": {FitId.general: fit_general(start=None, stop=None, fit_type=FitType.Linear,
                                                                        data_type=None, polynomial_order=0)},
-                          "FIT/Trans/ Log": {FitId.general: fit_general(start=None, stop=None, fit_type=FitType.Log,
+                          "FIT/Trans/ Log": {FitId.general: fit_general(start=None, stop=None, fit_type=FitType.Logarithmic,  # noqa
                                                                         data_type=None, polynomial_order=0)},
                           "FIT/Trans/ polYnomial": {FitId.general: fit_general(start=None, stop=None,
                                                     fit_type=FitType.Polynomial, data_type=None, polynomial_order=2)},
@@ -676,7 +673,7 @@ class FitParserTest(unittest.TestCase):
                                                                                  fit_type=FitType.Polynomial,
                                                                                  data_type=None, polynomial_order=3)},
                           "FIT/Trans/Sample/Log 23.4 56.7": {FitId.general: fit_general(start=23.4, stop=56.7,
-                                                             fit_type=FitType.Log, data_type=DataType.Sample,
+                                                             fit_type=FitType.Logarithmic, data_type=DataType.Sample,
                                                                                         polynomial_order=0)},
                           "FIT/Trans/can/ lIn 23.4 56.7": {FitId.general: fit_general(start=23.4, stop=56.7,
                                                            fit_type=FitType.Linear, data_type=DataType.Can,
diff --git a/scripts/test/SANS/user_file/user_file_reader_test.py b/scripts/test/SANS/user_file/user_file_reader_test.py
index 039bca871996f7a629707213fda37342b69c2205..13df4b189243e05b31c0afb449d242168e9c3e24 100644
--- a/scripts/test/SANS/user_file/user_file_reader_test.py
+++ b/scripts/test/SANS/user_file/user_file_reader_test.py
@@ -11,7 +11,7 @@ from sans.user_file.settings_tags import (DetectorId, BackId, range_entry, back_
                                           position_entry, TransId, TubeCalibrationFileId, QResolutionId, FitId,
                                           fit_general, MonId, monitor_length, monitor_file, GravityId,
                                           monitor_spectrum, PrintId, q_rebin_values)
-from user_file_test_helper import create_user_file, sample_user_file
+from sans.test_helper.user_file_test_helper import create_user_file, sample_user_file
 
 
 # -----------------------------------------------------------------
@@ -35,7 +35,7 @@ class UserFileReaderTest(unittest.TestCase):
                                                     back_single_monitor_entry(2, 85000, 98000)],
                            DetectorId.reduction_mode: [ISISReductionMode.LAB],
                            GravityId.on_off: [True],
-                           FitId.general: [fit_general(start=1.5, stop=12.5, fit_type=FitType.Log,
+                           FitId.general: [fit_general(start=1.5, stop=12.5, fit_type=FitType.Logarithmic,
                                                        data_type=None, polynomial_order=0)],
                            MaskId.vertical_single_strip_mask: [single_entry_with_detector(191, DetectorType.LAB),
                                                                single_entry_with_detector(191, DetectorType.HAB),
@@ -103,6 +103,7 @@ class UserFileReaderTest(unittest.TestCase):
     def _sort_list(elements):
         if len(elements) == 1:
             return
+
         if isinstance(elements[0], single_entry_with_detector):
             UserFileReaderTest._sort(elements, lambda x: x.entry)
         elif isinstance(elements[0], simple_range):